Junio C Hamano [Tue, 28 Apr 2026 01:13:28 +0000 (10:13 +0900)]
Merge branch 'hn/git-checkout-m-with-stash' into jch
"git checkout -m another-branch" was invented to deal with local
changes to paths that are different between the current and the new
branch, but it gave only one chance to resolve conflicts. The command
was taught to create a stash to save the local changes.
* hn/git-checkout-m-with-stash:
checkout -m: autostash when switching branches
checkout: rollback lock on early returns in merge_working_tree
sequencer: teach autostash apply to take optional conflict marker labels
sequencer: allow create_autostash to run silently
stash: add --label-ours, --label-theirs, --label-base for apply
Junio C Hamano [Tue, 28 Apr 2026 01:13:27 +0000 (10:13 +0900)]
Merge branch 'ps/history-fixup' into jch
* ps/history-fixup:
builtin/history: introduce "fixup" subcommand
builtin/history: generalize function to commit trees
replay: allow callers to control what happens with empty commits
Junio C Hamano [Tue, 28 Apr 2026 01:13:27 +0000 (10:13 +0900)]
Merge branch 'js/ci-github-actions-update' into jch
Update various GitHub Actions versions.
* js/ci-github-actions-update:
l10n: bump mshick/add-pr-comment from v2 to v3
ci: bump actions/checkout from v5 to v6
ci: bump actions/github-script from v8 to v9
ci: bump actions/{upload,download}-artifact to v7 and v8
ci: bump microsoft/setup-msbuild from v2 to v3
Junio C Hamano [Tue, 28 Apr 2026 01:13:26 +0000 (10:13 +0900)]
Merge branch 'ss/t7004-unhide-git-failures' into jch
Test clean-up.
* ss/t7004-unhide-git-failures:
t7004: avoid subshells to capture git exit codes
t7004: dynamically grab expected state in tests
t7004: drop hardcoded tag count for state verification
Junio C Hamano [Tue, 28 Apr 2026 01:13:26 +0000 (10:13 +0900)]
Merge branch 'ps/test-set-e-clean' into jch
The test suite harness and many individual test scripts have been
updated to work correctly when 'set -e' is in effect, which helps
detect misspelled test commands.
* ps/test-set-e-clean:
t: detect errors outside of test cases
t9902: fix use of `read` with `set -e`
t6002: fix use of `expr` with `set -e`
t1301: don't fail in case setfacl(1) doesn't exist or fails
t0008: silence error in subshell when using `grep -v`
t: prepare `test_when_finished ()`/`test_atexit()` for `set -e`
t: prepare execution of potentially failing commands for `set -e`
t: prepare conditional test execution for `set -e`
t: prepare `git config --unset` calls for `set -e`
t: prepare `stop_git_daemon ()` for `set -e`
t: prepare `test_must_fail ()` for `set -e`
t: prepare `test_match_signal ()` calls for `set -e`
Junio C Hamano [Tue, 28 Apr 2026 01:13:25 +0000 (10:13 +0900)]
Merge branch 'jc/neuter-sideband-fixup' into jch
Try to resurrect and reboot a stalled "avoid sending risky escape
sequences taken from sideband to the terminal" topic by Dscho. The
plan is to keep it in 'next' long enough to see if anybody screams
with the "everything dropped except for ANSI color escape sequences"
default.
* jc/neuter-sideband-fixup:
sideband: drop 'default' configuration
sideband: offer to configure sanitizing on a per-URL basis
sideband: add options to allow more control sequences to be passed through
sideband: do allow ANSI color sequences by default
sideband: introduce an "escape hatch" to allow control characters
sideband: mask control characters
Junio C Hamano [Tue, 28 Apr 2026 01:13:25 +0000 (10:13 +0900)]
Merge branch 'mc/http-emptyauth-negotiate-fix' into jch
The 'http.emptyAuth=auto' configuration now correctly attempts
Negotiate authentication before falling back to manual credentials.
This allows seamless Kerberos ticket-based authentication without
requiring users to explicitly set 'http.emptyAuth=true'.
* mc/http-emptyauth-negotiate-fix:
t5563: add tests for http.emptyAuth with Negotiate
http: attempt Negotiate auth in http.emptyAuth=auto mode
http: extract http_reauth_prepare() from retry paths
Junio C Hamano [Tue, 28 Apr 2026 01:13:24 +0000 (10:13 +0900)]
Merge branch 'ar/parallel-hooks' into jch
* ar/parallel-hooks:
t1800: test SIGPIPE with parallel hooks
hook: allow hook.jobs=-1 to use all available CPU cores
hook: add hook.<event>.enabled switch
hook: move is_known_hook() to hook.c for wider use
hook: warn when hook.<friendly-name>.jobs is set
hook: add per-event jobs config
hook: add -j/--jobs option to git hook run
hook: mark non-parallelizable hooks
hook: allow pre-push parallel execution
hook: allow parallel hook execution
hook: parse the hook.jobs config
config: add a repo_config_get_uint() helper
repository: fix repo_init() memleak due to missing _clear()
Junio C Hamano [Tue, 28 Apr 2026 01:13:24 +0000 (10:13 +0900)]
Merge branch 'cc/promisor-auto-config-url' into jch
Promisor remote handling has been refactored and fixed in
preparation for auto-configuration of advertised remotes.
* cc/promisor-auto-config-url:
t5710: use proper file:// URIs for absolute paths
promisor-remote: remove the 'accepted' strvec
promisor-remote: keep accepted promisor_info structs alive
promisor-remote: refactor accept_from_server()
promisor-remote: refactor has_control_char()
promisor-remote: refactor should_accept_remote() control flow
promisor-remote: reject empty name or URL in advertised remote
promisor-remote: clarify that a remote is ignored
promisor-remote: pass config entry to all_fields_match() directly
promisor-remote: try accepted remotes before others in get_direct()
Junio C Hamano [Tue, 28 Apr 2026 01:13:23 +0000 (10:13 +0900)]
Merge branch 'sp/refs-reduce-the-repository' into jch
Code clean-up to use the right instance of a repository instance in
calls inside refs subsystem.
* sp/refs-reduce-the-repository:
refs/reftable-backend: drop uses of the_repository
refs: remove the_hash_algo global state
refs: add struct repository parameter in get_files_ref_lock_timeout_ms()
Scott Bauersfeld [Mon, 27 Apr 2026 19:26:38 +0000 (19:26 +0000)]
index-pack, unpack-objects: increase input buffer from 4 KiB to 128 KiB
index-pack and unpack-objects both read pack data from stdin through
a 4 KiB static buffer. In index-pack, each fill() flushes consumed
bytes to the pack file via write_or_die(), capping every write(2)
at 4 KiB. unpack-objects uses the same buffer pattern for reads.
On FUSE-backed filesystems every write(2) is a synchronous round
trip through the FUSE protocol (userspace -> kernel -> userspace ->
back), so the 4 KiB buffer turns a clone into many unnecessary tiny
writes with noticeable latency overhead.
Increase the buffer from 4 KiB to 128 KiB. Introduce a shared
DEFAULT_IO_BUFFER_SIZE constant in git-compat-util.h (next to
MAX_IO_SIZE) and use it in index-pack, unpack-objects, and the
hashfile layer in csum-file (which already used 128 KiB but
hardcoded the value).
Syscall counts via strace on HTTPS clones of git/git (~296 MB pack,
5 runs per variant, isolated builds from the same v2.54.0 source):
The newly introduced git-history(1) command provides functionality to
easily edit commit history while also rebasing dependent branches. The
functionality exposed by this command is still somewhat limited though.
One common use case when editing commit history that is not yet covered
is fixing up a specific commit. Introduce a new subcommand that allows
the user to do exactly that by performing a three-way merge into the
target's commit tree, using HEAD's tree as the merge base. The flow is
thus essentially:
Like with the other commands, this will automatically rebase dependent
branches, as well. Unlike the other commands though:
- The command does not work in a bare repository as it interacts with
the index.
- The command may run into merge conflicts. If so, the command will
simply abort.
Especially the second item limits the usefulness of this command a bit.
But there are plans to introduce first-class conflicts into Git, which
will help use cases like this one.
Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/history: generalize function to commit trees
The function `commit_tree_with_edited_message_ext()` can be used to
commit a tree with a specific list of parents with an edited commit
message. This function is useful outside of editing the commit message
though, as it also performs the plumbing to extract the original commit
message and strip some headers from it.
Refactor the function to receive a flags field that allows the caller to
control whether or not the commit message should be edited, or whether
it should be retained as-is. This will be used in a subsequent commit.
Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
replay: allow callers to control what happens with empty commits
When replaying commits it may happen that some of the commits become
empty relative to their parent. Such commits are for now automatically
dropped by the replay subsystem without much control from the user.
Introduce a new enum that allows the caller to drop, keep or abort in
this case.
Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
The l10n workflow uses `mshick/add-pr-comment` to post git-po-helper
reports as comments on translation pull requests. It was still pinned
to v2, which runs on Node.js 20. GitHub is phasing out the Node.js 20
runtime on Actions runners, so staying on v2 will eventually cause the
"Create comment in pull request for report" step to fail.
The sole breaking change in v3 is the switch from Node.js 20 to
Node.js 24 (https://github.com/mshick/add-pr-comment/releases/tag/v3.0.0).
The action's inputs and outputs are unchanged, so the upgrade is a
drop-in replacement. Subsequent v3.x releases added new opt-in
features (message truncation, retry with exponential backoff, file
attachments, commit comment support, "delete on status") but none of
them affect existing callers that do not opt in.
Pointed-out-by: Christoph Grüninger <foss@grueninger.de> Assisted-by: Claude Opus 4.6 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Every workflow currently pins `actions/checkout` to v5, which was
introduced primarily to move to the Node.js 24 runtime. v6 is the
next release and worth picking up so we stay on a maintained version
of the action.
The one behaviorally interesting change in v6:
`persist-credentials` now stores the helper credentials under
`$RUNNER_TEMP` instead of writing them directly into the local
`.git/config`. Two implications follow:
1. In the normal case this is an unambiguous improvement -- the
token no longer lands in `.git/config`, reducing the risk of
inadvertently leaking it through workspace archiving
(`upload-artifact` snapshots, cache entries, core dumps, ...).
2. Docker container actions require an Actions Runner of at least
v2.329.0 to find the credentials in their new location. The
github.com-hosted runners our CI uses are already past that
version, so this does not affect us. Downstream users running
self-hosted runners may need to update them before adopting
this version of the action.
Risk analysis: our checkout steps either check out the default
repository (no special credential requirements) or, in the `vs-build`
job, explicitly set `repository: microsoft/vcpkg` and
`path: compat/vcbuild/vcpkg`. Neither case relies on the precise
location of the persisted credentials -- subsequent steps interact
with the API via the runner-provided `GITHUB_TOKEN` directly -- so
the v6 credential-storage change is transparent to our workflows.
The diff is purely the `@vN` identifier; there are no input or
output changes.
Originally-authored-by: dependabot[bot] <support@github.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
The only use we have of `actions/github-script` is the "skip if the
commit or tree was already tested" step in `main.yml`, which checks
whether an identical tree-SHA was already built successfully. It
currently pins v8; v9 is the latest release.
What v9 changes:
- The `ACTIONS_ORCHESTRATION_ID` environment variable is now
appended to the HTTP user-agent string. This is transparent to
our script.
- A new injected `getOctokit` factory lets scripts create
additional authenticated clients in the same step without
importing `@actions/github`. We do not use it.
- Two breaking changes affect scripts that either call
`require('@actions/github')` (fails at runtime, because
`@actions/github` v9 is now ESM-only) or that shadow the
implicit `getOctokit` parameter via `const`/`let` (syntax
error). Our script does neither -- it only uses the pre-supplied
`github` REST client and `core` helpers -- so the upgrade is
safe.
Risk analysis: the step is advisory. It sets `enabled=' but skip'`
as an optimization to avoid re-running CI on a tree that was already
tested successfully. Even if the v9 upgrade broke the script, the
surrounding `try { ... } catch (e) { core.warning(e); }` block would
degrade it to a warning and CI would still run normally. In practice
the script continues to work identically on v9.
Originally-authored-by: dependabot[bot] <support@github.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
ci: bump actions/{upload,download}-artifact to v7 and v8
`actions/upload-artifact` and `actions/download-artifact` are tightly
coupled: the upload action writes artifact archives in a format that
the download action then reads. Because of this coupling, the two
actions should always be bumped together so that the artifact format
contract between them is satisfied.
All of our `actions/upload-artifact` uses are still on v5, with one
stray v4 occurrence. Keeping them on these versions would leave the
artifact-upload steps running on Node.js 20, which GitHub is phasing
out, and would eventually cause all upload steps to fail.
Going from v5 directly to v7 folds in two release bumps:
- v6 switches the action's default runtime from Node.js 20 to
Node.js 24 (v5 had preliminary Node 24 support but still defaulted
to Node 20). This is the main motivation for bumping now: it gets
us off the deprecated runtime.
- v7 adds two opt-in features: direct (unzipped) single-file uploads
via a new `archive: false` parameter, and an internal conversion of
the action to ESM to match the updated `@actions/*` packages.
Risk analysis: we never pass `archive`, so the zip-as-usual behavior
is unchanged. We also do not `require('@actions/*')` from any calling
workflow, so the ESM migration cannot affect us. The upload steps we
care about -- tracked files/build artifacts and failing-test
directories -- keep the same inputs (`name`, `path`) and outputs, so
the diff is purely the `@vN` identifier. The main precondition is a
recent Actions Runner (>= 2.327.1), which the github.com-hosted
runners used by our CI already satisfy.
While at it, align the one remaining `@v4` occurrence with the rest
so that every `upload-artifact` step uses the same version.
We use `actions/download-artifact` to pass build artifacts between
the "windows-build" / "vs-build" / "windows-meson-build" jobs and
their corresponding test jobs. All callers are currently on v6;
bumping to v8 keeps this action in lockstep with the `upload-artifact`
bump above.
What v7 and v8 change:
- v7 switches the default runtime from Node.js 20 to Node.js 24 (v6
had preliminary Node 24 support but still defaulted to Node 20).
This is the main motivation: it gets us off the deprecated runtime.
- v8 makes three further changes:
* The package is converted to ESM (invisible to workflow authors).
* The action now checks the `Content-Type` header before
attempting to unzip a download, so that directly-uploaded
(unzipped) artifacts from `upload-artifact` v7 are downloaded
correctly.
* The `digest-mismatch` behaviour is changed from warn-and-
continue to a hard failure by default.
Risk analysis: defaulting hash-mismatch to a hard failure is
strictly safer than the previous warn-and-continue behaviour -- a
mismatch points to real corruption or tampering and should stop the
run. We download archives that the same workflow just uploaded, on
the same runner fleet, so false positives are not expected. Our
usage is limited to the `name` and `path` inputs, which are
unchanged between v6 and v8, so the diff is purely the `@vN`
identifier.
Originally-authored-by: dependabot[bot] <support@github.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
The v2 of `microsoft/setup-msbuild` runs on Node.js 20, which GitHub
is phasing out of the Actions runners. v3 is a minimal release whose
only substantive change is moving the action's runtime to Node.js 24,
so that our Visual Studio build jobs keep working once Node.js 20 is
removed from the runners.
The risk of this bump is very low: v3 contains no functional changes
to the action itself -- it merely adds `msbuild.exe` to `PATH`, with
no change to command-line flags, inputs, outputs, or default tool
resolution. The only precondition is a recent-enough Actions Runner,
which the github.com-hosted runners already satisfy.
Originally-authored-by: dependabot[bot] <support@github.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
env: move "warn_on_object_refname_ambiguity" into `struct repo_config_values`
The `core.warnAmbiguousRefs` configuration was previously stored in a
global `int` variable, making it shared across repository instances
and risking cross‑repository state leakage.
Store it instead in `repo_config_values`, where eagerly‑parsed
repository configuration lives. This option is parsed eagerly because
ambiguity warnings influence how users interpret object references in
many commands; a lazy parse could cause these warnings to behave
inconsistently or to appear for the wrong repository, confusing users
and hindering libification. This preserves the existing behavior while
tying the value to the repository from which it was read, avoiding
cross‑repository state leakage and continuing the effort to reduce
reliance on global configuration state.
Update all references to use `repo_config_values()`.
Mentored-by: Christian Couder <christian.couder@gmail.com> Mentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com> Signed-off-by: Olamide Caleb Bello <belkid98@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
env: move "sparse_expect_files_outside_of_patterns" into `repo_config_values`
The `core.sparseCheckoutExpectFilesOutsideOfPatterns` configuration was
previously stored in a global `int` variable, making it shared across
repository instances and risking cross‑repository state leakage.
Store it instead in `repo_config_values`, where eagerly‑parsed
repository configuration lives. This option is parsed eagerly because
it controls how sparse‑checkout paths are interpreted – a fundamental
behavior that many commands rely on; a lazy parse could cause
inconsistent sparse‑checkout handling and complicate libification.
This preserves the existing behavior while tying the value to the
repository from which it was read, avoiding cross‑repository state
leakage and continuing the effort to reduce reliance on global
configuration state.
Update all references to use `repo_config_values()`.
Mentored-by: Christian Couder <christian.couder@gmail.com> Mentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com> Signed-off-by: Olamide Caleb Bello <belkid98@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
env: move "core_sparse_checkout_cone" into `struct repo_config_values`
The `core.sparseCheckoutCone` configuration was previously stored in an
uninitialized global `int` variable, risking cross‑repository state
leakage.
Move it into `repo_config_values`, where eagerly‑parsed repository
configuration lives. `core.sparseCheckoutCone` is parsed eagerly
because it determines the fundamental sparse‑checkout mode and is
consulted very early during repository setup; a lazy parse could
leave the sparse‑checkout state undefined and complicate
libification. This preserves the existing behavior while tying the
value to the repository from which it was read, avoiding cross‑
repository state leakage and continuing the effort to reduce reliance
on global configuration state.
Update all references to use `repo_config_values()`.
Mentored-by: Christian Couder <christian.couder@gmail.com> Mentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com> Signed-off-by: Olamide Caleb Bello <belkid98@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
environment: move "precomposed_unicode" into `struct repo_config_values`
The `core.precomposeunicode` configuration is currently stored in the
global variable `precomposed_unicode`, which makes it shared across
repository instances within a single process.
Store it instead in `repo_config_values`, where eagerly‑parsed
repository configuration lives. `core.precomposeunicode` is parsed
eagerly because it controls Unicode path normalization on macOS,
a fundamental filesystem‑level behavior that many operations depend
on; a lazy parse could lead to inconsistent results and hamper
libification. This preserves the existing behavior while tying the
value to the repository from which it was read, avoiding cross‑
repository state leakage and continuing the effort to reduce reliance
on global configuration state.
Change the type of the field from `int` to `bool` since it is parsed
as a boolean value.
Update all references to use `repo_config_values()`.
Mentored-by: Christian Couder <christian.couder@gmail.com> Mentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com> Signed-off-by: Olamide Caleb Bello <belkid98@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
environment: move "pack_compression_level" into `struct repo_config_values`
The `pack_compression_level` configuration is currently stored in the
global variable `pack_compression_level`, which makes it shared across
repository instances within a single process.
Store it instead in `repo_config_values`, where eagerly‑parsed
repository configuration lives. `pack_compression_level` is parsed
eagerly because it influences packfile compression, a core operation
where a lazy parse could cause inconsistent behavior and hamper
libification. This preserves the existing eager‑parsing behavior while
tying the value to the repository from which it was read, avoiding
cross‑repository state leakage and continuing the effort to reduce
reliance on global configuration state.
The type remains `int` as it represents a numeric compression level,
not a boolean toggle.
Update all references to use `repo_config_values()`.
Mentored-by: Christian Couder <christian.couder@gmail.com> Mentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com> Signed-off-by: Olamide Caleb Bello <belkid98@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
environment: move `zlib_compression_level` into `struct repo_config_values`
The `zlib_compression_level` configuration is currently stored in the
global variable `zlib_compression_level`, which makes it shared across
repository instances within a single process.
Store it instead in `repo_config_values`, where eagerly‑parsed
repository configuration lives. `zlib_compression_level` is parsed
eagerly because it determines compression behaviour for objects and
packs – core operations where a lazy parse could lead to unpredictable
results and hinder libification. This preserves the existing
eager‑parsing behavior while tying the value to the repository it
was read from, avoiding cross‑repository state leakage and continuing
the effort to reduce reliance on global configuration state.
Update all references to use `repo_config_values()`.
Mentored-by: Christian Couder <christian.couder@gmail.com> Mentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com> Signed-off-by: Olamide Caleb Bello <belkid98@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
environment: move "check_stat" into `struct repo_config_values`
The `core.checkstat` configuration is currently stored in the global
variable `check_stat`, which makes it shared across repository
instances within a single process.
Store it instead in `repo_config_values`, where eagerly‑parsed
repository configuration lives. `core.checkstat` is parsed eagerly
because it controls how `match_stat_data()` and related functions
decide file freshness; a lazy parse could lead to unexpected
behavior or complicate libification. This preserves the existing
eager‑parsing behavior while tying the value to the repository it
was read from, avoiding cross‑repository state leakage, and
continuing the effort to reduce reliance on global configuration
state.
Update all references to use `repo_config_values()`.
Mentored-by: Christian Couder <christian.couder@gmail.com> Mentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com> Signed-off-by: Olamide Caleb Bello <belkid98@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
environment: move "trust_ctime" into `struct repo_config_values`
The `core.trustctime` configuration is currently stored in the global
variable `trust_ctime`, which makes it shared across repository
instances in a single process.
Store it instead in `repo_config_values`, where eagerly‑parsed
repository configuration lives. `core.trustctime` is parsed eagerly
because it is used in low‑level stat‑matching functions
(`match_stat_data()`), where a lazy parse could cause unexpected
fatal errors and complicate libification efforts. This preserves
that behavior while tying the value to the repository from which it
was read, avoiding cross‑repository state leakage and continuing the
effort to reduce reliance on global configuration state.
Update all references to use repo_config_values().
Mentored-by: Christian Couder <christian.couder@gmail.com> Mentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com> Signed-off-by: Olamide Caleb Bello <belkid98@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Harald Nordgren [Fri, 24 Apr 2026 21:10:12 +0000 (21:10 +0000)]
checkout -m: autostash when switching branches
When switching branches with "git checkout -m", the attempted merge
of local modifications may cause conflicts with the changes made on
the other branch, which the user may not want to (or may not be able
to) resolve right now. Because there is no easy way to recover from
this situation, we discouraged users from using "checkout -m" unless
they are certain their changes are trivial and within their ability
to resolve conflicts.
Teach the -m flow to create a temporary stash before switching and
reapply it after. On success, the stash is silently applied and
the list of locally modified paths is shown, same as a successful
"git checkout" without "-m".
If reapplying causes conflicts, the stash is kept and the user is
told they can resolve and run "git stash drop", or run "git reset
--hard" and later "git stash pop" to recover their changes.
Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Harald Nordgren [Fri, 24 Apr 2026 21:10:11 +0000 (21:10 +0000)]
checkout: rollback lock on early returns in merge_working_tree
merge_working_tree() acquires the index lock via
repo_hold_locked_index() but several early return paths exit
without calling rollback_lock_file(), leaving the lock held.
While this is currently harmless because the process exits soon
after, it becomes a problem if the function is ever called more
than once in the same process.
Add rollback_lock_file() calls to all early return paths.
Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Harald Nordgren [Fri, 24 Apr 2026 21:10:10 +0000 (21:10 +0000)]
sequencer: teach autostash apply to take optional conflict marker labels
Add label_ours, label_theirs, label_base, and stash_msg parameters to
apply_autostash_ref() and the autostash apply machinery so callers can
pass custom conflict marker labels through to
"git stash apply --label-ours/--label-theirs/--label-base", as well as
a custom stash message for "git stash store -m".
Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Harald Nordgren [Fri, 24 Apr 2026 21:10:09 +0000 (21:10 +0000)]
sequencer: allow create_autostash to run silently
Add a silent parameter to create_autostash_internal and introduce
create_autostash_ref_silent so that callers can create an autostash
without printing the "Created autostash" message.
Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Harald Nordgren [Fri, 24 Apr 2026 21:10:08 +0000 (21:10 +0000)]
stash: add --label-ours, --label-theirs, --label-base for apply
Allow callers of "git stash apply" to pass custom labels for conflict
markers instead of the default "Updated upstream" and "Stashed changes".
Document the new options and add a test.
Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
We need to adjust the test in t7810 as well. The file it uses has the
following five lines; I add a line highlighting the matches and a ruler
at the bottom here, to make it easier to see that the second "mmap"
indeed starts at column 14:
foo mmap bar
foo_mmap bar
foo_mmap bar mmap
foo mmap bar_mmap
foo_mmap bar mmap baz
==== ==== 123456789123456789 1
Reported-by: Brandon Chinn <brandonchinn178@gmail.com> Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Historically, config entries like alias.foo.bar expanded the alias
"foo.bar". The subsection-based alias syntax introduced in ac1f12a9de (alias: support non-alphanumeric names via subsection
syntax, 2026-02-18) broke that behavior by treating such entries as
if they were subsection syntax.
Restore support for the old dotted form by falling back to the full
name when the final key is not "command". Add tests covering execution
and help output for simple dotted aliases.
Reported-by: Michael Grossfeld <michael.grossfeld@amd.com> Helped-by: Jeff King <peff@peff.net> Signed-off-by: Jonatan Holmgren <jonatan@jontes.page> Signed-off-by: Junio C Hamano <gitster@pobox.com>
The goal of that commit was to avoid zombie child processes hanging
around when the parent git process is killed. But it doesn't quite work
when the child command is run by the shell:
1. If there is a shell, then we kill and wait for the shell, not the
process spawned by the shell. And so the child process, even if it
eventually exits, will hang around as a zombie forever. And this is
true of most (all?) shells: bash, dash, etc.
So we are not really accomplishing our goal in the first place.
2. Not all shells will exit immediately upon receiving a signal. In
particular, mksh will wait for its children to exit (but not
actually propagate the signal to them!) leaving us with a potential
deadlock: git is wait()ing on mksh, which is wait()ing on a child
process, but that child process is waiting on git to produce more
input (or EOF) over a pipe.
You can see several examples of this deadlock in the test suite,
for example by running:
make SHELL_PATH=/bin/mksh
cd t
./t5702-protocol-v2.sh
Because this is a regression for mksh users, and because we did not
achieve our goal even with other shells, let's revert the commit for
now. If there is a more clever way of doing the same thing, we can
consider applying it separately on top (or do nothing and just accept
the zombies and rely on PID 1 to reap them).
Reported-by: Jan Palus <jpalus@fastmail.com> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Back in commit a562d90a350d (merge-ort: fix failing merges in special
corner case, 2025-11-03), we hit a rename assertion due to a trivial
directory resolution affecting the parent of a cached rename. Since
the path didn't need to be considered, we side-stepped it with
if (!newinfo)
continue;
in process_renames(). We have since run into a case in production
where a trivial resolution of a file affects the direct target of a
cached rename rather than a parent directory of it. Add a testcase
demonstrating this additional case.
Now, if we were to follow the lead of commit a562d90a350d, we could
resolve this alternate case with an extra condition on the above if:
if (!newinfo || newinfo->merged.clean)
continue;
However, if we had done that earlier, we would have made 979ee83e8a90
(merge-ort: fix corner case recursive submodule/directory conflict
handling, 2025-12-29) harder to find and fix, and this particular
position for this condition isn't actually at the root of the issue
but downstream from it.
Instead, let's rip out this if-check from a562d90a350d and put in an
alternative that more directly addresses trivially resolved paths that
happen to be cached renames or parent directories thereof, which is a
better fix for the original testcase and which also solves the newly
added testcase as well.
Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
We have recently merged a patch series that had a simple misspelling of
`test_expect_success`. Instead of making our tests fail though, this
typo went completely undetected and all of our tests passed, which is of
course unfortunate. This is a more general issue with our test suite:
all commands that run outside of a specific test case can fail, and if
we don't explicitly check for such failure then this failure will be
silently ignored.
Improve the status quo by enabling the errexit option so that any such
unchecked failures will cause us to abort immediately.
Note that for now, we only enable this option for Bash 5 and newer. This
is because other shells have wildly different behaviour, and older
versions of Bash (especially on macOS) are buggy. The list of enabled
shells may be extended going forward.
Helped-by: Jeff King <peff@peff.net> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
In t9902 we're using the `read` builtin to read some values into a
variable. This is done by using `-d ""`, which cause us to read until
the end of the heredoc. As the read is terminated by EOF, the command
will end up returning a non-zero error code. This hasn't been an issue
until now as we didn't run with `set -e`, but that'll change in a
subsequent commit.
Prepare for this change by not using read at all, as we can simply store
the multi-line value directly.
Suggested-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
In `test_bisection_diff ()` we use `expr` to perform some math. This
command has some gotchas though in that it will only return success when
the result is neither null nor zero. In some of our cases though it
actually _is_ zero, and that will cause the expressions to fail once we
enable `set -e`.
Prepare for this change by instead using `$(( ))`, which doesn't have
the same issue. While at it, modernize the function a tiny bit.
Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
t1301: don't fail in case setfacl(1) doesn't exist or fails
In t1301 we're trying to remove any potentially-existing default ACLs
that might exist on the transh directory by executing setfacl(1).
According to 8ed0a740dd (t1301-shared-repo.sh: don't let a default ACL
interfere with the test, 2008-10-16), this is done because we play
around with permissions and umasks in this test suite.
The setfacl(1) binary may not exist on some systems though, even though
tests ultimately still pass. This doesn't matter currently, but will
cause the test to fail once we start running with `set -e`. Silence such
failures by ignoring failures here.
Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
t0008: silence error in subshell when using `grep -v`
In t0008 we use `grep -v` in a subshell, but expect that this command
will sometimes not match anything. This would cause grep(1) to return an
error code, but given that we don't run with `set -e` we swallow this
error.
We're about to enable `set -e`. Prepare for this by ignoring any errors.
Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
t: prepare `test_when_finished ()`/`test_atexit()` for `set -e`
Both `test_when_finished ()` and `test_atexit ()` build up a chain of
cleanup commands by prepending each new command to the existing cleanup
string. To preserve the exit code of the test body across cleanup
execution, we append the following logic:
} && (exit "$eval_ret"); eval_ret=$?; ...
The intent of this is to run the cleanup block and then unconditionally
restore `eval_ret`. The original behaviour of this is is:
+------------------+---------+------------------------------------+
|test body │ cleanup │ old behaviour │
+------------------+---------+------------------------------------+
│pass (eval_ret=0) | pass │ && taken -> (exit 0) -> eval_ret=0 |
+------------------+---------+------------------------------------+
│pass (eval_ret=0) | fail │ && not taken -> eval_ret=$? |
+------------------+---------+------------------------------------+
│fail (eval_ret=1) | pass │ && taken -> (exit 1) -> eval_ret=1 |
+------------------+---------+------------------------------------+
│fail (eval_ret=1) | fail | && not taken -> eval_ret=$? |
+------------------+---------+------------------------------------+
This logic will start to fail once we enable `set -e`. When `$eval_ret`
is non-zero, the subshell we create will fail, and with `set -e` we'll
thus bail out without evaluating the logic after the semicolon.
Fix this issue by instead using `|| eval_ret=\$?; ...`. Besides being
a bit simpler, it also retains the original behaviour:
+------------------+---------+------------------------------------+
|test body │ cleanup │ old behaviour │
+------------------+---------+------------------------------------+
│pass (eval_ret=0) | pass │ || not taken -> eval_ret unchanged |
+------------------+---------+------------------------------------+
│pass (eval_ret=0) | fail │ || taken -> eval_ret=$? |
+------------------+---------+------------------------------------+
│fail (eval_ret=1) | pass │ || not taken -> eval_ret unchanged |
+------------------+---------+------------------------------------+
│fail (eval_ret=1) | fail | || taken -> eval_ret=$? |
+------------------+---------+------------------------------------+
Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
t: prepare execution of potentially failing commands for `set -e`
Several of our tests verify whether a certain binary can be executed,
potentially skipping tests in case we cannot, for example because the
binary doesn't exist. In those cases we often run the binary outside of
any conditionally.
This will start to fail once we enable `set -e`, as that will cause us
to bail out the test immediately. Improve these tests by executing them
inside of a conditional instead.
Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
t: prepare conditional test execution for `set -e`
We have some test in our test suite where we use the pattern of
`test ... && test_expect_succeess` to conditionally execute a test. The
problem is that when we decide to not execute the test, we'll indeed
skip the test, but the overall statement will also be unsuccessful. This
will become a problem once we enable `set -e`.
Prepare for this future by turning this into a proper conditional, which
is also a bit easier to read overall.
Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
t: prepare `git config --unset` calls for `set -e`
We have a couple of calls to `git config --unset` that ultimately end up
as no-ops as the configuration variables aren't set (anymore) in the
first place. These calls are mostly intended to recover unconditionally
from tests that may have executed only partially, but they'll ultimately
fail during a normal test run.
This hasn't been a problem until now as we aren't running tests with
`set -e`. This is about to change though, so let's silence the case
where we cannot unset the config keys.
Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
We have a couple of calls to `stop_git_daemon ()` outside of specific
test cases that will kill a backgrounded git-daemon(1) process and
expect the process with a specific error code. While these function
calls do end up killing git-daemon(1), the error handling we have in
those contexts is basically ineffective. So while we expect the process
to exit with a specific error code, we will just continue with any error
in case it doesn't.
This will change once we enable `set -e` in a subsequent commit. There's
two issues though that will make this _always_ fail:
- Our call to `wait` is expected to fail, but because it's not part of
a condition it will cause us to bail out immediately with `set -e`.
- We try to kill git-daemon(1) a second time via the pidfile. We can
generally expect that this is the same PID though as we had in the
"GIT_DAEMON_PID" environment variable, and thus it's more likely
than not that we have already killed it, and the call to kill will
fail.
Prepare for this change by handling the failure of `wait` with `||` and
by silencing failures of the second call to `kill`.
Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
The helper function `test_must_fail ()` executes a specific Git command
that may or may not fail in a specific way. This is done by executing
the command in question and then comparing its exit code against a set
of conditions.
This works, but once we run our test suite with `set -e` we may bail out
of `test_must_fail ()` early in case the command actually fails, even
though we expect it to fail. Prepare for this change by handling the
failed case with `||`.
Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
t: prepare `test_match_signal ()` calls for `set -e`
We have a couple of calls to `test_match_signal ()` where we execute a
Git command and expect it to die with a specific signal. These calls
will essentially execute the process in a subshell via `foo; echo $?`,
but as we expect `foo` to fail this will cause the overall subshell to
fail once we `set -e`.
Fix this issue by using `foo && echo 0 || echo $?` instead.
Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Several tests in t7004 use the 'test$(git ...) = ...' or the '! (git ...)'
subshell pattern. This swallows git's exit code. If git crashes
(e.g. segmentation fault) the crash would go undetected, and the test
would fail due to a mismatch or an inverted exit code.
Modernize these tests by directly writing output to files(actual) and
verifying them with 'test_cmp' or 'test_grep'. Replace subshell
negations with 'test_must_fail'. This way, if git crashes, the test
fails immediately and clearly instead of hiding the error behind a
string mismatch.
Signed-off-by: Siddharth Shrimali <r.siddharth.shrimali@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
The tests for 'Multiple -l or --list options' and 'trying to delete
tags without params', hardcodes that exactly one or two specific tags
('myhead', 'mytag') exist in the repository.
If other tests are added, modified, or removed earlier in the script,
this expected global state will change, resulting in these tests to fail
for completely unrelated reasons.
Instead of hardcoding the expected tags, dynamically grab the state
of the repository before running the commands under test ('git tag -l'
and 'git tag -d'), and verify that the output matches or remains
unchanged afterward. This keeps the tests independent from the script's
overall state.
Signed-off-by: Siddharth Shrimali <r.siddharth.shrimali@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
t7004: drop hardcoded tag count for state verification
The test 'trying to create a tag with a non-valid name should fail',
checked that exactly one tag existed in the repository before and after
attempting to create invalid tags.
As pointed out by Junio, this makes the test brittle by relying on a
specific global tag count. If future tests are added or removed before
this test, the expected state changes and this test would break for
completely unrelated reasons.
Modernize the test by taking a snapshot of the existing tags before the
failure attempts and comparing it to a snapshot taken after.
This provides a "belt-and-suspenders" approach: we verify that
'git tag' both exits with the expected error code and leaves the
repository state untouched, without being brittle to the specific
number of tags present.
This replaces the hardcoded 'test_line_count = 1' checks with 'test_cmp'
to ensure the tag list remains identical.
Suggested-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Siddharth Shrimali <r.siddharth.shrimali@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
6cc6d1b4c699 (Documentation: update add --force option + ignore=all
config, 2026-02-06) added text describing both the ignore=none and
ignore=all behaviors. The former had minor formatting and grammatical
errors, while the latter was a bit garbled. I have tried to tweak the
wording on the latter to make it read as I think was intended, and fixed
the minor grammatical issues with both as well.
Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
doc: fix self-referential config in sendemail.smtpSSLClientKey
a8215a205141 (send-email: add client certificate options, 2026-03-02)
added documentation for sendemail.smtpSSLClientKey that says it works
"in conjunction with `sendemail.smtpSSLClientKey`" -- referring to
itself. It appears that `sendemail.smtpSSLClientCert` was the intended
reference; fix it.
Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jeff King [Thu, 16 Apr 2026 20:06:59 +0000 (16:06 -0400)]
MIDX: revert the default version to v1
We introduced midx version 2 in b2ec8e90c2 (midx: do not require packs
to be sorted in lexicographic order, 2026-02-24) and now write it by
default. The rationale was that older versions should ignore the v2 midx
and fall back to using the packs (just like we do for other midx
errors). Unfortunately this is not the case, as we have a hard die()
when we see an unknown midx version.
As a result, writing a midx with Git 2.54-rc2 puts the repository into a
state that is unusable with Git 2.53. And this midx write may happen
behind the scenes as part of normal operations, like fetch.
Let's switch back to writing v1 by default to avoid regressing the case
where multiple versions of Git are used on the same repository.
There is one gotcha, though: the v2 format is required for some new
features, like midx compaction, and running "git multi-pack-index
compact" will complain when asked to write a v1 index. The user must set
midx.version to "2" to make the feature work.
So instead of always using v1, we'll base the default on whether the
requested feature requires v2. That does mean that running midx
compaction will create a repository that can't be read by older versions
of Git. But we never do that by default; only people experimenting with
the new feature will be affected.
We have to adjust the test expectation in t5319, since it will now
generate v1 files. And our "auto-select v2" is covered by the tests in
t5335, which continue to check that compaction works without having to
set midx.version manually (and also explicitly check that asking for v1
with compaction reports the problem).
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
t5563: add tests for http.emptyAuth with Negotiate
Add tests exercising the interaction between http.emptyAuth and
servers that advertise Negotiate (SPNEGO) authentication.
Verify that auto mode gives Negotiate a chance via empty auth
(resulting in two 401 responses before falling through to
credential_fill with Basic credentials), and that false mode
strips Negotiate immediately (only one 401 response).
Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
http: attempt Negotiate auth in http.emptyAuth=auto mode
When a server advertises Negotiate (SPNEGO) authentication, the
"auto" mode of http.emptyAuth should detect this as an "exotic"
method and proactively send empty credentials, allowing libcurl to
use the system Kerberos ticket without prompting the user.
However, two features interact to prevent this from working:
The Negotiate-stripping logic, introduced in 4dbe66464b
(remote-curl: fall back to Basic auth if Negotiate fails,
2015-01-08), removes CURLAUTH_GSSNEGOTIATE from the allowed
methods on the first 401 response. The empty-auth auto-detection,
introduced in 40a18fc77c (http: add an "auto" mode for
http.emptyauth, 2017-02-25), then checks the remaining methods
for anything "exotic" -- but Negotiate has already been removed,
so auto mode never activates for servers whose only non-Basic/Digest
method is Negotiate (e.g., Apache with mod_auth_kerb offering
Basic + Negotiate).
Fix this by delaying the Negotiate stripping in auto mode: on the
first 401, keep Negotiate in the allowed methods so that auto mode
can detect it and retry with empty credentials. If that attempt
fails (no valid Kerberos ticket), strip Negotiate on the second 401
and fall through to credential_fill() as usual.
To support this, also teach http_reauth_prepare() to skip
credential_fill() when empty auth is about to be attempted, since
filling real credentials would bypass the empty-auth mechanism.
The true and false modes are unchanged: true sends empty credentials
on the very first request (before any 401), and false never sends
them.
Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
http: extract http_reauth_prepare() from retry paths
All three HTTP retry paths (http_request_recoverable, post_rpc,
probe_rpc) call credential_fill() directly when handling
HTTP_REAUTH. Extract this into a helper function so that a
subsequent commit can add pre-fill logic (such as attempting
empty-auth before prompting) in one place.
No functional change.
Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
- correct translation of pathspec msgs
Corrects cases where the “pathspec” is translated as if it was a
path
- correct translation of refspec msgs
Corrects cases where the “refspec” were not consistently translated
- correct translation of credential msgs
Corrects cases where the “credential” were not correctly translated
Signed-off-by: Stefan Björnelund <stefan.bjornelund.gnome@gmail.com> Modified-by: Peter Krefting <peter@softwolves.pp.se>
Originally-authored-by: dependabot[bot] <support@github.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Scott L. Burson [Wed, 15 Apr 2026 02:27:43 +0000 (02:27 +0000)]
userdiff: extend Scheme support to cover other Lisp dialects
Common Lisp has top-level forms, such as 'defun' and 'defmacro', that
are not matched by the current Scheme pattern. Also, it is more
common in CL, when defining user macros intended as top-level forms,
to prefix their names with "def" instead of "define"; such forms are
also not matched. And some top-level forms don't even begin with
"def".
On the other hand, it is an established formatting convention in the
Lisp community that only top-level forms start at the left margin. So
matching any unindented line starting with an open parenthesis is an
acceptable heuristic; false positives will be rare.
However, there are also cases where notionally top-level forms are
grouped together within some containing form. At least in the Common
Lisp community, it is conventional to indent these by two spaces, or
sometimes one. But matching just an open parenthesis indented by two
spaces would be too broad; so the pattern added by this commit
requires an indented form to start with "(def". It is believed that
this strikes a good balance between potential false positives and
false negatives.
Signed-off-by: Scott L. Burson <Scott@sympoiesis.com> Acked-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Johannes Sixt [Wed, 15 Apr 2026 02:27:42 +0000 (02:27 +0000)]
userdiff: tighten word-diff test case of the scheme driver
The scheme driver separates identifiers only at parentheses of all
sorts and whitespace, except that vertical bars act as brackets that
enclose an identifier.
The test case attempts to demonstrate the vertical bars with a change
from 'some-text' to '|a greeting|'. However, this misses the goal
because the same word coloring would be applied if '|a greeting|'
were parsed as two words.
Have an identifier between vertical bars with a space in both the pre-
and the post-image and change only one side of the space to show that
the single word exists between the vertical bars.
Also add cases that change parentheses of all kinds in a sequence of
parentheses to show that they are their own word each.
Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Scott L. Burson <Scott@sympoiesis.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>