Junio C Hamano [Tue, 18 Aug 2026 16:31:36 +0000 (09:31 -0700)]
Merge branch 'hn/bisect-reset-when-found'
The 'git bisect' command has been taught a
'--reset-when-found[=<where>]' option that tells the command to
automatically run 'git bisect reset' to jump back to the original
state or to the found culprit.
* hn/bisect-reset-when-found:
bisect: add --reset-when-found to leave when done
bisect: let bisect_reset() optionally check out quietly
Junio C Hamano [Tue, 18 Aug 2026 16:31:36 +0000 (09:31 -0700)]
Merge branch 'ps/writev'
A compatibility wrapper for writev(3p) has been reintroduced,
including fixes for CMake build and 'MAX_IO_SIZE' limits on NonStop.
Calls to write(3p) in send_sideband() and cat_blob() have been
refactored to use writev(3p) wrappers to reduce syscall overhead.
* ps/writev:
fast-import: use writev(3p) to send cat-blob responses
sideband: use writev(3p) to send pktlines
wrapper: properly handle MAX_IO_SIZE in writev(3p)
wrapper: introduce writev(3p) wrappers
compat/posix: introduce writev(3p) wrapper
Junio C Hamano [Tue, 18 Aug 2026 16:31:35 +0000 (09:31 -0700)]
Merge branch 'kh/doc-refs-migrate-limitations'
The known limitations of the ref format migration in 'git refs' have
been moved to be displayed as a warning admonition directly under the
description of the 'migrate' subcommand, improving visibility. A
reference to 'git-maintenance' has also been corrected to use the
'linkgit' macro.
* kh/doc-refs-migrate-limitations:
doc: refs: linkgit to git-maintenance(1)
doc: refs: put ref migration warning under the command
Junio C Hamano [Sat, 15 Aug 2026 16:20:27 +0000 (09:20 -0700)]
Merge branch 'jc/add-resolved'
'git add' has been taught a new '--resolved' option to stage
conflict-resolved paths, while leaving unrelated local changes
unstaged. It scans the unmerged paths for leftover conflict
markers and aborts if any are found.
Junio C Hamano [Sat, 15 Aug 2026 16:20:27 +0000 (09:20 -0700)]
Merge branch 'kl/t7528-ssh-agent-for-csh-users'
The 'ssh-agent' tests in 't7528' have been fixed to work when the
user's login shell is csh-like, by explicitly passing '-s' to
'ssh-agent' to force Bourne shell syntax.
* kl/t7528-ssh-agent-for-csh-users:
t7528: fix failure under csh
Junio C Hamano [Sat, 15 Aug 2026 16:20:26 +0000 (09:20 -0700)]
Merge branch 'tn/packfile-uri-concurrency'
Concurrent downloads of packfiles via packfile URIs and dumb HTTP are
safer by avoiding concurrent appends to the staging file. Opening in
read-write mode with separate file offsets prevents corruption and
preserves resumability. 'fetch-pack' now tolerates pre-existing
'.keep' files.
* tn/packfile-uri-concurrency:
fetch-pack: accept "pack" output for packfile URIs
http: permit unlinking partial packs on Windows
http: avoid concurrent appends to partial packs
http: accept HTTP 416 for complete partial packs
http: avoid closing index-pack input twice
http-fetch: correct --index-pack-arg documentation
The 'TRACE2_ANCESTRY' prerequisite in the 't0213' test script has been
refined to avoid failures under user-mode emulation by verifying that
the ancestry collector reports the expected process names rather than
the emulator binary name.
* jm/t0213-skip-emulated-ancestry-tests:
t0213: skip ancestry tests under user-mode emulation
Junio C Hamano [Tue, 11 Aug 2026 17:07:00 +0000 (10:07 -0700)]
Merge branch 'ns/merge-base-is-ancestor-tests'
Tests for 'git merge-base --is-ancestor' have been added to cover
exit codes (0 for success, 1 for non-ancestor, 128 for errors) and
to ensure it cannot be combined with '--all'.
* ns/merge-base-is-ancestor-tests:
merge-base: add tests for --is-ancestor
Junio C Hamano [Tue, 11 Aug 2026 17:07:00 +0000 (10:07 -0700)]
Merge branch 'lo/mv-missing-dest-dir-check'
'git mv' has been updated to check for a missing destination
leading directory during the checking phase, allowing 'git mv -n'
to report the failure. The error message when the rename(2)
syscall fails has also been improved to name both the source and
the destination.
* lo/mv-missing-dest-dir-check:
mv: reject a destination whose leading path is missing or a symlink
mv: name both source and destination when rename fails
Junio C Hamano [Tue, 11 Aug 2026 17:06:59 +0000 (10:06 -0700)]
Merge branch 'kh/doc-replay-config'
Documentation for 'git replay' has been updated to refer to its
configuration variables.
* kh/doc-replay-config:
doc: replay: move “default” to the right-hand side
doc: replay: use a nested description list
doc: replay: improve config description
doc: link to config for git-replay(1)
Junio C Hamano [Tue, 11 Aug 2026 17:06:59 +0000 (10:06 -0700)]
Merge branch 'sk/test-commit-body-helper'
A new test helper commit_body() has been introduced to print the
message body of a commit, and various tests have been updated to use
it instead of spelling out the command pipeline manually and losing
the exit status of the 'git cat-file' command on the upstream of the
pipe.
* sk/test-commit-body-helper:
t: use commit_body to extract commit message bodies
test-lib-functions: add commit_body helper
Junio C Hamano [Tue, 11 Aug 2026 17:06:59 +0000 (10:06 -0700)]
Merge branch 'ja/doc-synopsis-style-yet-more'
Synopsis and options in the documentation for 'git format-patch',
'git imap-send', 'git send-email', and 'git request-pull' have been
updated to the modern style.
* ja/doc-synopsis-style-yet-more:
doc: convert git-request-pull synopsis and options to new style
doc: convert git-send-email synopsis and options to new style
doc: convert git-format-patch synopsis and options to new style
doc: convert git-imap-send synopsis and options to new style
Junio C Hamano [Fri, 7 Aug 2026 21:48:01 +0000 (14:48 -0700)]
Merge branch 'ds/sparse-index-ita-crash'
A crash in the 'sparse-index' collapse code when encountering an
invalidated cache-tree node (due to an intent-to-add path) has been
fixed by avoiding collapsing such subtrees.
* ds/sparse-index-ita-crash:
sparse-index: avoid crash on intent-to-add entry outside the cone
Junio C Hamano [Fri, 7 Aug 2026 21:48:01 +0000 (14:48 -0700)]
Merge branch 'dl/pack-bitmap-position-zero'
A boundary case check in reachability bitmap traversal has been
corrected to properly handle the object at position zero, which was
previously skipped, leading to redundant bitmap loading.
* dl/pack-bitmap-position-zero:
pack-bitmap: handle objects at bitmap position zero
A memory leak in 'git merge' when run without arguments (which
triggers the default-to-upstream path) has been fixed. A test has
been added to cover this case.
* tc/merge-default-to-upstream-leakfix:
merge: fix leak with merge.defaultToUpstream
Junio C Hamano [Fri, 7 Aug 2026 21:48:00 +0000 (14:48 -0700)]
Merge branch 'mm/revision-pure-get-commit-action'
The get_commit_action() function has been refactored to be a pure
predicate by moving the side-effecting line-level log range folding to
simplify_commit(). This ensures that evaluating a commit's action
before the walk reaches it does not prematurely mutate its tracked
line ranges, making it safer for potential lookahead evaluations.
* mm/revision-pure-get-commit-action:
revision: make get_commit_action() a pure predicate
fast-import: use writev(3p) to send cat-blob responses
When answering a `cat-blob` command, `cat_blob()` issues three separate
calls to write(3p) on the cat-blob fd: one for the header line, one for
the full blob payload, and one for the trailing newline. Frontends like
git-filter-repo issue these commands in bulk, once per rewritten blob,
so the syscall overhead adds up.
Use `writev_in_full()` to send all three parts with a single syscall.
Every pktline that we send out via `send_sideband()` currently requires
two syscalls: one to write the pktline's length, and one to send its
data. This typically isn't all that much of a problem, but under extreme
load the syscalls may cause contention in the kernel.
Refactor the code to instead use the newly introduced writev(3p) infra
so that we can send out the data with a single syscall. This reduces the
number of syscalls from around 133,000 calls to write(3p) to around
67,000 calls to writev(3p).
This change leads to a performance improvement for git-upload-pack(1),
but we have to cheat a bit to really make it measurable. Usually, the
time is strongly dominated by generating the packfile itself. But if we
precompute the pack and serve it via the pack-objects hook then we can
essentially eliminate that overhead. The following setup is executed in
the Git repository:
Benchmarking the last command leads to the following results:
Benchmark 1: HEAD~
Time (mean ± σ): 192.9 ms ± 0.6 ms [User: 106.5 ms, System: 95.3 ms]
Range (min … max): 191.7 ms … 194.1 ms 50 runs
Benchmark 2: HEAD
Time (mean ± σ): 141.1 ms ± 0.7 ms [User: 63.2 ms, System: 86.6 ms]
Range (min … max): 139.8 ms … 142.7 ms 50 runs
Summary
HEAD ran
1.37 ± 0.01 times faster than HEAD~
This might not be impressive in absolute numbers when you also take into
account the time it takes to generate the packfile itself. But GitLab
(and supposedly other forges) have caching mechanisms in place that work
exactly like the above setup, where repeated incoming requests can be
served from the same cached packfile. And in those cases, the impact is
sizeable.
More importantly though, as hinted at above, GitLab has observed in the
past that with enough cache hits we eventually start to saturate a
semaphore in the Linux kernel itself in the pipe write path. This
bottleneck is being moved a bit by having to do less syscalls.
Suggested-by: Jeff King <peff@peff.net> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
wrapper: properly handle MAX_IO_SIZE in writev(3p)
Some systems like NonStop set a comparatively small `MAX_IO_SIZE`, which
limits the maximum number of bytes we're allowed to write in a single
call. We already handle this limit properly in `xwrite()`, but we have
recently introduced wrappers for writev(3p) where we don't. This will
cause the syscall to return EINVAL in case somebody passes an iovec
entry to writev(3p) that is larger than `MAX_IO_SIZE`.
Introduce a new function `xwritev()` that is similar to `xwrite()` in
that it handles such platform-specific nuances:
- We only pass the leading iovec entries to writev(3p) that fit into
`MAX_IO_SIZE`, pretending that the underlying syscall performed a
short write. This mirrors how `xwrite()` chomps overly large
requests before handing them to write(3p). As a consequence, callers
will never see writev(3p)'s EINVAL error for requests whose summed
length would overflow an ssize_t, but observe a short write instead.
- If already the first iovec entry exceeds the limit we instead punt
to `xwrite()`, which knows to handle this case for us.
- We restart the underlying syscall on EINTR and EAGAIN, just like
`xwrite()` does for write(3p).
Adapt `writev_in_full()` to use this new wrapper. With the retry logic
now living in `xwritev()`, the calling loop becomes the exact mirror
image of `write_in_full()`, which also retains the responsibility of
translating a zero-length write into ENOSPC.
Reported-by: Randall Becker <randall.becker@nexbridge.ca> Helped-by: Jeff King <peff@peff.net> Helped-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
In the preceding commit we have added a compatibility wrapper for the
writev(3p) syscall. Introduce some generic wrappers for this function
that we nowadays take for granted in the Git codebase.
Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
In a subsequent commit we're going to add the first caller to
writev(3p). Introduce a compatibility wrapper for this syscall that we
can use on systems that don't have this syscall.
The syscall exists on modern Unixes like Linux and macOS, and seemingly
even for NonStop according to [1]. It doesn't seem to exist on Windows
though.
Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
doc: refs: put ref migration warning under the command
I have to scroll down at least three screens in man(1) from the
`migrate` description in order to see the “known limitations” for
it. This is important information since the text says that concurrent
writes can lead to an inconsistent migrated state. Let’s move that text
up to the command description and put it inside a Warning admonition.
This section made sense when it was added in 25a0023f (builtin/refs:
new command to migrate ref storage formats, 2024-06-06); `migrate` was
the only subcommand, and this section was visible from the command
description. A one-page man page. But that is not the case anymore
now that the command has nine subcommands to describe.
Acked-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano [Wed, 5 Aug 2026 18:10:52 +0000 (11:10 -0700)]
Merge branch 'js/mingw-symlink-net-share-leak'
Git for Windows has been updated to avoid auto-detecting the symlink
type if the target path starts with a slash, preventing NTLM
credential leaks when checking out repositories with crafted
symbolic links pointing to network shares.
* js/mingw-symlink-net-share-leak:
mingw: skip symlink type auto-detection for network share targets
Junio C Hamano [Wed, 5 Aug 2026 18:10:52 +0000 (11:10 -0700)]
Merge branch 'jk/t0014-dynamic-deprecated-cmds'
The alias tests in 't/t0014-alias.sh' have been updated to dynamically
query the list of deprecated commands using 'git
--list-cmds=deprecated' to avoid test failures when running with
'WITH_BREAKING_CHANGES' in a build directory that contains stale
executables of formerly deprecated commands.
* jk/t0014-dynamic-deprecated-cmds:
t0014: generate deprecated command names dynamically
t0014: factor out choice of deprecated commands
Junio C Hamano [Wed, 5 Aug 2026 18:10:51 +0000 (11:10 -0700)]
Merge branch 'jk/ci-static-analysis-image-bump'
The image version used by the static-analysis CI job has been bumped
to ubuntu-latest (Ubuntu 24.04), which brings in a newer Coccinelle
version that resolves a severe performance regression. A false
positive warning from the 'CHECK_ASSERTION_SIDE_EFFECTS' build with
GCC 15 in the Bloom filter code has also been silenced to facilitate
the image upgrade.
* jk/ci-static-analysis-image-bump:
ci: bump ubuntu image version for static-analysis job
bloom: silence CHECK_ASSERTION_SIDE_EFFECTS false positive
Junio C Hamano [Wed, 5 Aug 2026 18:10:51 +0000 (11:10 -0700)]
Merge branch 'ps/odb-pluggable-housekeeping'
Object database housekeeping in 'git gc' and 'git maintenance' has
been refactored to be pluggable. The files-backend-specific logic,
including incremental and geometric repacking as well as object
pruning, has been moved out of the command implementation and into the
files object database source, enabling future alternative object
database backends to implement their own housekeeping services.
* ps/odb-pluggable-housekeeping:
odb: make optimizations pluggable
builtin/gc: fix signedness issues in ODB-related functionality
builtin/gc: refactor ODB optimizations to operate on "files" source
builtin/gc: introduce `odb_optimize_required()`
builtin/gc: move geometric repacking into `odb_optimize()`
builtin/gc: introduce object database optimization options
builtin/gc: inline config values specific to the "files" backend
builtin/gc: make repack arguments self-contained
builtin/gc: extract object database optimizations into separate function
builtin/gc: move worktree and rerere tasks before object optimizations
odb: run "pre-auto-gc" hook for all maintenance tasks
t7900: simplify how we check for maintenance tasks
Junio C Hamano [Wed, 5 Aug 2026 18:10:51 +0000 (11:10 -0700)]
Merge branch 'pw/rebase-fixup-fixes'
Two bugs in how 'git rebase' handles skipped 'fixup' and 'squash'
commands have been fixed. One bug caused an incorrect commit count to
be shown in the template message when multiple commands were skipped,
and another prevented the editor from opening when the final command
in a chain containing 'fixup -c' was skipped.
* pw/rebase-fixup-fixes:
rebase: remember fixup -c after skipping fixup/squash
rebase -i: fix counting of fixups after rebase --skip
D. Ben Knoble [Wed, 5 Aug 2026 12:19:32 +0000 (08:19 -0400)]
mailmap: change primary address for D. Ben Knoble
Ben uses the +github GMail trick to identify emails sent to him by folks
that found his GitHub profile. At the time, that also meant he had to
commit under the same email for GitHub to recognize his commits. He has
since found out that GitHub can be configured with more than one email
for identification, and he would prefer his canonical email to omit
mention of GitHub (where it's not relevant) going forward.
Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
mailmap: change primary address for Christian Couder
The `chriscool@tuxfamily.org` address is an old one that I don't use
anymore, while `christian.couder@gmail.com` is the address I have been
sending patches from for a long time.
Let's swap the two addresses in the existing entry, so that the Gmail
address becomes the primary one and the old tuxfamily.org address is
mapped to it. This way both addresses still resolve to the same person,
and the address I actually use is the canonical one.
Signed-off-by: Christian Couder <christian.couder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
The remote-matching logic for submodules has been corrected to resolve
'url.*.insteadOf' aliases before comparing the inventoried URL from
'.gitmodules' with the URLs of configured remotes.
* en/submodule-insteadof-remote-match:
submodule: resolve insteadOf aliases when matching remote
Junio C Hamano [Mon, 3 Aug 2026 16:31:29 +0000 (09:31 -0700)]
Merge branch 'jc/exclude-first-parent-seen'
Traversals with '--exclude-first-parent-only' have been corrected
to properly stop after the first parent even when it has already
been marked as 'SEEN'.
* jc/exclude-first-parent-seen:
revision: honor --exclude-first-parent-only with SEEN first parent
Junio C Hamano [Mon, 3 Aug 2026 16:31:29 +0000 (09:31 -0700)]
Merge branch 'hn/url-push-tracking'
When the push remote is specified as a URL, the fetch refspec of a
uniquely matching configured remote is now used to find and update
the remote-tracking branch (e.g., '@{push}').
* hn/url-push-tracking:
remote: find tracking branches for URL push destinations
remote: pass repository to push tracking helper
Kenneth Lorber [Mon, 3 Aug 2026 00:41:03 +0000 (20:41 -0400)]
t7528: fix failure under csh
Explicitly set sh mode for ssh-agent (ssh-agent -s) to prevent
failure when user's login shell is csh-like. The failure is
caused by propagation of the $SHELL value from the user's original
shell despite the test and test harness explictly using sh, which
makes ssh-agent emit initialization code for the wrong shell:
> cd t
> echo $SHELL
/bin/tcsh
> ./t7528-signed-commit-ssh.sh --verbose --debug
[...]
expecting success of 7528.2 'sign commits using literal public keys with ssh-agent':
[...]
./t7528-signed-commit-ssh.sh: 1: eval: setenv: not found
./t7528-signed-commit-ssh.sh: 1: eval: setenv: not found
[...]
Signed-off-by: Kenneth Lorber <keni@his.com> Acked-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Harald Nordgren [Sun, 2 Aug 2026 21:24:20 +0000 (21:24 +0000)]
bisect: add --reset-when-found to leave when done
When a bisection finishes, "git bisect" reports the first bad commit
but leaves the session active until "git bisect reset" is run by hand.
Add a "--reset-when-found[=<where>]" option, accepted by both "git
bisect start" and "git bisect run", that resets as soon as the first
bad commit is found. The "original" value returns to the commit checked
out before "git bisect start", while "found" leaves the first bad commit
checked out; omitting the value defaults to "original".
Persist the selected target in a BISECT_RESET_WHEN_FOUND state file
and perform the reset quietly.
Let the internal first-bad result propagate to cmd_bisect(), which
performs the reset using the existing bad bisect ref after the
subcommand has returned. For "git bisect run", this means BISECT_RUN
has been printed and closed before cleanup, which also works on systems
that cannot unlink an open file.
Reject this option together with "--no-checkout", since that mode must
not check out either target.
Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Harald Nordgren [Sun, 2 Aug 2026 21:24:19 +0000 (21:24 +0000)]
bisect: let bisect_reset() optionally check out quietly
Add a "quiet" parameter to bisect_reset() that passes "--quiet" to the
checkout restoring the original HEAD, suppressing its progress and
branch-status output.
No caller sets the flag yet, so behavior is unchanged.
Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano [Fri, 31 Jul 2026 12:56:05 +0000 (05:56 -0700)]
add: introduce '--resolved' option
During a conflicted merge, rebase, or cherry-pick, 'git add -u' is a
handy way to add modified paths to the index. However, '-u'
indiscriminately adds all modified tracked paths, including unmerged
paths that may still contain unresolved conflict markers. It also
adds tracked files modified in the worktree that are not involved in
the ongoing merge.
The latter is not a huge problem for "git rebase", which refuses to
start with any local changes, but is a problem for "git merge",
which is often run with local changes in maintainer workflows.
Introduce 'git add --resolved' to add only unmerged paths, limited
by an optional pathspec, where no conflict markers remain in the
working tree.
Before modifying the index, scan unmerged regular files for leftover
conflict markers using a new helper, has_conflict_markers(), defined
in merge-ll.c in terms of the is_conflict_marker_line() helper we
introduced earlier. If any unmerged path still contains conflict
markers, show an error listing the conflicted paths and abort
without updating the index. Otherwise, add these unmerged paths
that do not have conflict markers to the index.
Note that unmerged paths without conflict markers (such as binary
files and deletions) are added as resolved using add_file_to_index()
and remove_file_from_index_with_flags(). Tracked files that were
not in a conflicted state are ignored by '--resolved'.
add_file_to_index() takes flags such as ADD_CACHE_PRETEND and
ADD_CACHE_VERBOSE and internally handles both reporting (e.g.,
"add 'path'") and suppressing index updates during dry runs.
In contrast, remove_file_from_index() takes only istate and path
without flags. Callers that perform file removals (such as
update_callback() in read-cache.c) are forced to manually inspect
ADD_CACHE_PRETEND and ADD_CACHE_VERBOSE flags for removed
files.
Introduce remove_file_from_index_with_flags() to encapsulate
pretend mode and verbose reporting for index removals. Update
update_callback() to use the new helper.
The diff.c:is_conflict_marker() and rerere.c:is_cmarker() functions
implement duplicate logic for identifying conflict marker lines
(lines that begin with a run of '<', '=', '>', and '|' characters).
diff.c's original version from 049540435f (diff --check: detect
leftover conflict markers, 2008-06-26) accepts any whitespace (such
as a newline) immediately following '<<<<<<<' and '>>>>>>>', whereas
rerere.c's version from 191f241717 (rerere: prepare for customizable
conflict marker length, 2010-01-16) strictly requires a space
character (' ') after them.
Implement is_conflict_marker_line() in merge-ll.c to serve as a
replacement for both, and update diff.c and rerere.c to use the new
helper. The unified helper intentionally adopts rerere's stricter
rule, as the conflicts generated by Git always show the "ours" and
"theirs" labels after these markers separated by a space.
Junio C Hamano [Fri, 31 Jul 2026 12:56:02 +0000 (05:56 -0700)]
read-cache: reindent
I do not know how this happened without anybody noticing, but a few
months ago we added a16c4a245a (read-cache: submodule add need
--force given ignore=all configuration, 2026-02-06), and almost all
lines the patch added were incorrectly indented.
Reindent these lines so that they play better with surrounding lines
in the same file.
Junio C Hamano [Thu, 30 Jul 2026 17:32:04 +0000 (10:32 -0700)]
Merge branch 'ps/odb-move-loose-object-writing'
The logic to write loose objects has been refactored and moved from
'object-file.c' to the loose backend source file 'odb/source-loose.c',
making the loose backend more self-contained. This is achieved by
first refactoring force_object_loose() to use generic ODB write
interfaces instead of loose-backend internals.
* ps/odb-move-loose-object-writing:
object-file: move logic to write loose objects
object-file: move `force_object_loose()`
object-file: force objects loose via generic interface
object-file: fix memory leak in `force_object_loose()`
odb: support setting mtime when writing objects
odb: lift object existence check out of the "loose" backend
odb: compute object hash in `odb_write_object_ext()`
t/u-odb-inmemory: implement wrapper for writing objects
odb: compute compat object ID in `odb_write_object_ext()`
The object ID shortening and linking in the 'commitdiff' view of
'gitweb' has been corrected to work even when the index line carries
a trailing file mode.
* tl/gitweb-shorten-hashes-with-modes:
gitweb: shorten index hashes with trailing file modes
Junio C Hamano [Thu, 30 Jul 2026 17:32:04 +0000 (10:32 -0700)]
Merge branch 'ps/cat-file-remote-object-info'
The 'remote-object-info' command has been added to 'git cat-file
--batch-command', allowing clients to request object metadata
(currently size) from a remote server via protocol v2 without
downloading the entire object. Format placeholders are dynamically
filtered on the client based on server-advertised capabilities,
returning empty strings for inapplicable or unsupported fields.
* ps/cat-file-remote-object-info:
cat-file: make remote-object-info allow-list adapt to the server
cat-file: add remote-object-info to batch-command
transport: add client support for object-info
serve: advertise object-info feature
protocol-caps: check object existence regardless of the attributes requested
fetch-pack: move fetch initialization
connect: make write_fetch_command_and_capabilities() more generic
fetch-pack: move write_fetch_command_and_capabilities() to connect.c
fetch-pack: use unsigned int for hash_algo variable
fetch-pack: drop the static advertise_sid variable
t1006: extract helper functions into new 'lib-cat-file.sh'
cat-file: declare loop counter inside for()
transport-helper: fix memory leak of helper on disconnect
Junio C Hamano [Thu, 30 Jul 2026 17:32:04 +0000 (10:32 -0700)]
Merge branch 'jt/config-lock-timeout'
Configuration file locking has been updated to retry for a short
period, avoiding failures when multiple processes attempt to update
the configuration simultaneously.
* jt/config-lock-timeout:
config: retry acquiring config.lock, configurable via core.configLockTimeout
The 'git stash push' command has been optimized to avoid unnecessary
sparse index expansion when pathspecs are wholly inside the
sparse-checkout cone. Also, a potential out-of-bounds read in the
sparse-index expansion check helper pathspec_needs_expanded_index()
has been fixed by consistently using the parsed, prefixed path.
* tn/stash-avoid-sparse-index-expansion:
stash: avoid sparse-index expansion for in-cone paths
pathspec: use match for sparse-index expansion checks
Junio C Hamano [Thu, 30 Jul 2026 17:32:03 +0000 (10:32 -0700)]
Merge branch 'sk/userdiff-swift'
Userdiff patterns for Swift have been added, with support for
Swift-specific constructs such as attributes, modifiers, failable
initializers, and generics.
* sk/userdiff-swift:
userdiff: add support for Swift
Junio C Hamano [Thu, 30 Jul 2026 17:32:03 +0000 (10:32 -0700)]
Merge branch 'ty/migrate-excludes-file'
The 'excludes_file' and various other global configuration variables
(including 'editor_program', 'pager_program', 'askpass_program', and
'push_default') have been migrated into the per-repository structure.
* ty/migrate-excludes-file:
repository: adjust the comment of config_values_private_
environment: move object_creation_mode into repo_config_values
environment: move autorebase into repo_config_values
environment: move push_default into repo_config_values
environment: migrate apply_default_whitespace and apply_default_ignorewhitespace
environment: move askpass_program into repo_config_values
environment: move pager_program into repo_config_values
environment: move editor_program into repo_config_values
environment: move excludes_file into repo_config_values
repository: introduce repo_config_values_clear()
Junio C Hamano [Thu, 30 Jul 2026 17:32:02 +0000 (10:32 -0700)]
Merge branch 'ty/migrate-trust-executable-bit'
The 'trust_executable_bit' (coming from the 'core.filemode'
configuration) has been migrated into 'struct repo_config_values' to
tie it to a specific repository instance.
* ty/migrate-trust-executable-bit:
environment: move has_symlinks into repo_config_values
environment: move trust_executable_bit into repo_config_values
read-cache: pass 'repo' to 'ce_mode_from_stat()'
read-cache: remove redundant extern declarations
Junio C Hamano [Thu, 30 Jul 2026 17:32:02 +0000 (10:32 -0700)]
Merge branch 'rs/tempfile-wo-the-repository'
The tempfile and lockfile APIs have been refactored to stop depending
on the 'the_repository' global variable, and their callers have been
updated to use the repository-aware variants.
* rs/tempfile-wo-the-repository:
use repo_hold_lock_file_for_update{,_mode,_timeout}() with custom repos
tempfile: stop using the_repository
lockfile: add repo_hold_lock_file_for_update{,_timeout}{,_mode}()
refs/packed: use repo_create_tempfile()
tempfile: add repo_create_tempfile{,_mode}()
mv: reject a destination whose leading path is missing or a symlink
When moving a file, if any leading directory in the destination path
is missing or is not a real directory, the problem is detected only
later when rename() is called. Furthermore, if a leading directory
component is a symbolic link, the issue is not detected at all.
Three cases reach rename(2) unchecked today:
- A leading directory is missing: rename(2) fails with ENOENT,
reported against the source (misleading), and "git mv -n" does not
detect it since the dry run never reaches the syscall.
- A leading component is a non-directory ("git mv x a/b" with 'a' a
file): rename(2) fails with ENOTDIR, again only at the syscall.
- A leading component is a symbolic link: "git mv" follows it. Since
Git tracks symlinks, the destination is really occupied by a
tracked object, and following it is wrong regardless of the link
target. The move is done on disk at the resolved location while the
index records the literal path, leaving the index describing a
worktree that does not exist. A later "git add" can reconcile it,
but "git mv" alone has already corrupted the state.
Detect all three in the checking phase. Reject a destination that goes
through a symlink with has_symlink_leading_path(), which uses lstat()
and never follows the link, so the refusal is independent of the
target. Then lstat() the leading directory: report "destination
directory does not exist" for ENOENT/ENOTDIR and "destination is not a
directory" for a non-directory. Other errors fall through to rename().
Guard the directory check with the same condition under which rename(2)
runs, so directory moves and sparse/out-of-cone destinations are not
flagged incorrectly.
This changes behavior: a move through a tracked symlink that previously
"succeeded" while corrupting the index is now refused. The other two
cases only change when the failure is diagnosed.
Signed-off-by: Lucas Zamboni Orioli <lucaszam0@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
mv: name both source and destination when rename fails
When "git mv" fails at the rename(2) syscall, the error is reported
with die_errno() using only the source path:
fatal: renaming 'src' failed: No such file or directory
rename(2) returns ENOENT both when the source does not exist and when
a directory component of the destination does not exist, and errno
does not distinguish the two. Reporting only the source therefore
misleads the user in the latter case: for
git mv a/file b/no-such-dir/file
the message blames 'a/file', which exists, and gives no hint that
'b/no-such-dir/' is the missing part.
Inspecting the paths again after the failure to determine which one is
at fault would be racy, since either could appear or disappear between
the rename(2) and the follow-up check. Instead, simply name both the
source and the destination in the message and let the reader see which
one is wrong:
fatal: renaming 'a/file' to 'b/no-such-dir/file' failed:
No such file or directory
Signed-off-by: Lucas Zamboni Orioli <lucaszam0@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
doc: replay: move “default” to the right-hand side
This is now a description list (see previous commit) and parentheticals
like this do not go on the left-hand side. Moving it to the other side
makes it stand out just as much and is also more consistent with the
rest of the documentation.
Let’s also do the same for the `replay.refAction` description list.
That makes the two desc. lists identical in the first sentence. Let’s
add a comment about that for future editors.
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This bullet list for `--ref-action` introduces a term with a colon.
This is exactly what a description list is, structurally. Let’s be
stylistically consistent and use the desc. list markup construct.
In short, just transform this unordered list in the same way that we
did for `replay.refAction` in the previous commit.
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name> Signed-off-by: Junio C Hamano <gitster@pobox.com>
First of all, this unordered list for `replay.refAction` introduces
a term with a colon. This is exactly what a description list is,
structurally. Let’s be stylistically consistent and use the desc.
list markup construct. Let’s also drop the harmless but unneeded
indentation.
We can reuse the `::` delimiter since we use an open block.
But for consistency use the typical nested description list
delimiter, namely `;;`.
Second, let’s replace the inline-verbatim `git replay` with a link
to git-replay(1), since we are naming the command. But make that
conditional so that we avoid a self-link inside git-replay(1).[1]
† 1: See e.g. e7b3a768 (doc: git-init: rework config item
init.templateDir, 2024-03-10) for another example of
avoiding self-linking
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This config doc was added in 336ac90c (replay: add replay.refAction
config option, 2025-11-06) but never included anywhere. Include it in
git-replay(1) and git-config(1).
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name> Signed-off-by: Junio C Hamano <gitster@pobox.com>
`git merge-base --is-ancestor A B` is used a lot in scripts but has no
tests. Add some to t6010 covering its exit codes: 0 when A is an
ancestor of B, 1 when it is not, and 128 (not 1) when given a bad
argument. Also check that --is-ancestor and --all can't be combined,
and that the resulting error names both options.
Signed-off-by: Nikolaus Schuetz <nikolauspschuetz@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
We have a few tests related to aliasing of deprecated commands. They use
whatchanged and pack-redundant because those are the only two deprecated
commands we have. Eventually those commands will be removed, at which
point these tests will be checking nothing useful (they'll just be
regular aliases, which we already cover in other tests).
We could remove them at that point, but the code to handle deprecated
commands will still remain. We probably do want to keep the tests around
for the eventual day that we deprecate more commands. So let's ask Git
for its list of deprecated commands, and if we don't have any, skip
those tests.
This also prevents an annoying corner case when your build directory
contains old build products. Right now those commands are marked as
deprecated builtins and treated specially; we allow aliases and never
look for them as dashed external commands. But after they are removed,
they aren't special anymore. If your directory happens to contain
hardlinks from the build of an older version, that confuses Git: it sees
the old hardlinks in place, thinks those are actual external commands,
and refuses to allow aliasing.
You can see that today like this:
make
make WITH_BREAKING_CHANGES=1 test
The first "make" creates git-whatchanged as a hardlink to Git, and the
second does not clean it up (it doesn't know about the whatchanged
command at all anymore). t0014 fails because Git won't create an alias
to the "external" whatchanged command.
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jeff King [Tue, 28 Jul 2026 14:37:26 +0000 (10:37 -0400)]
t0014: factor out choice of deprecated commands
We have a few tests related to aliasing deprecated commands which use
"whatchanged" and "pack-redundant", as these are the only two deprecated
commands we have. Let's pull those names into variables so that we can
refactor the tests without relying on the specific names.
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
mingw: skip symlink type auto-detection for network share targets
On Windows, symbolic links come in two flavors: file symlinks and
directory symlinks. Since Git was born on Linux where this distinction
does not exist, Git for Windows has to auto-detect the type by looking
at the target. When the target does not yet exist at symlink creation
time, Git for Windows creates a "phantom" file symlink and later, once
checkout is complete, calls `CreateFileW()` on the target to check
whether it is actually a directory.
If the symlink target is a UNC path (e.g. `\\attacker\share`), this
auto-detection triggers an SMB connection to the remote host. Windows
performs NTLM authentication by default for such connections, which
means a crafted repository can exfiltrate the cloning user's NTLMv2 hash
to an attacker-controlled server without any user interaction beyond
`git clone -c core.symlinks=true <url>`.
There are ways to specify UNC paths that start with only a single
backslash (e.g. `\??\UNC\host\share`); All of them do start like that,
though, so let's use that as a tell-tale that we should skip the
auto-detection in `process_phantom_symlink()`. The symlink is then left
as a file symlink (the `mklink` default), and a warning is emitted
suggesting the user set the `symlink` gitattribute to `dir` if a
directory symlink is needed. When the attribute is already set,
auto-detection is never invoked in the first place, so that code path is
unaffected.
This is the same class of vulnerability as CVE-2025-66413
(https://github.com/git-for-windows/git/security/advisories/GHSA-hv9c-4jm9-jh3x)
and follows the same general mitigation pattern that MinTTY adopted for
ANSI escape sequences referencing network share paths
(https://github.com/mintty/mintty/security/advisories/GHSA-jf4m-m6rv-p6c5).
Note that there are legitimate paths starting with a single backslash
that are _not_ network paths: drive-less absolute paths are interpreted
as relative to the current working directory's drive. In practice, these
are highly uncommon (and brittle, just one working directory change away
from breaking). In any case, the only consequence is now that the
symlink type of those has to be specified via Git attributes, is all.
Reported-by: Justin Lee <jessdhoctor@gmail.com>
Addresses: CVE-2026-32631 Assisted-by: Claude Opus 4.6 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
David Lin [Tue, 28 Jul 2026 13:52:48 +0000 (09:52 -0400)]
pack-bitmap: handle objects at bitmap position zero
`bitmap_position()` only returns a negative value when an object is not
present in the bitmap index.
In `find_objects()`, we have added a check (11d45a6e6a) to avoid
processing a root whose reachability is already represented by the base
bitmap, but accidentally uses `pos > 0`. Consequently, it never performs
the membership test for an object at position zero.
If that object has an individual reachability bitmap, we unnecessarily
OR that bitmap into the base again. Otherwise, we add the object to the
not-mapped list, only for the subsequent pass to recognize that it is
already present. The latter pass correctly treats all non-negative
positions as valid, so this does not change the resulting object set,
but an off-by-one edge case.
Treat position zero as valid by changing the condition to `pos >= 0`.
The existing pseudo-merge traversal test exercises this case. Its
position-zero commit is presented through multiple roots. Before this
change, each occurrence is counted as a bitmap hit; afterwards, only
the first occurrence is counted. Assert the resulting hit count to
cover the boundary condition.
Also cover the non-pseudo-merge case by passing `HEAD` twice. The first
occurrence initializes the base from its stored bitmap, and the second
must recognize that position zero is already present.
Helped-by: Taylor Blau <ttaylorr@openai.com> Signed-off-by: David Lin <davidlin@stripe.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
By default the setting 'merge.defaultToUpstream' for git-merge(1) is set
to 'true', which means when `git merge` is invoked with no arguments it
merges the upstream branch configured for the current branch.
With this configuration set to 'true', setup_with_upstream() is called.
That function allocates an array of arguments and hands it back to
cmd_merge() via its `argv` parameter. This array is never freed, so
cmd_merge() leaks it on every invocation.
Track the allocated array in a separate variable and free it at the end.
The leak has been present since 93e535a5b7 (merge: merge with the
default upstream branch without argument, 2011-03-24). Although the leak
sanitizer was enabled for tests in fc1ddf42af (t: remove
TEST_PASSES_SANITIZE_LEAK annotations, 2024-11-21), it went unnoticed
because no test calls `git merge` without arguments, exercising the
default-to-upstream path. Add such a test in t7600, which fails under
the leak sanitizer without this fix.
Signed-off-by: Toon Claes <toon@iotcl.com> Acked-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jeff King [Tue, 28 Jul 2026 15:00:31 +0000 (11:00 -0400)]
cat-file: handle content request for --batch-command without type
The batch mode of cat-file needs to know the object's type in order to
print the contents (because it decides whether to stream or not based on
object type). The default batch output contains %(objecttype), so we get
the type info automatically. But when it doesn't, we have to ask for it
explicitly.
In the --batch code path, we check while setting up the object_info
struct whether we will print the contents, and if so set "typep" to get
the value. This comes from 6554dfa97a (cat-file: handle --batch format
with missing type/size, 2013-12-12).
But later we added a --batch-command mode, which does not do the same
trick. The decision about whether to retrieve the contents is made
per-command (a "contents" vs "info" command), so we can't decide when
building the object_info originally. As a result, asking for:
will fail the assertion in print_object_or_die() that the type was
actually filled in.
We can fix it by tweaking the object_info on the fly as we receive each
command. But we should be careful to restore it afterwards; otherwise a
sequence of commands like:
contents $one
info $two
info $three
will pay the type-lookup price for $two and $three when it does not need
to. This wouldn't be incorrect, but just slightly inefficient (and hence
there are no tests for that part, because the externally-visible
behavior is the same).
Reported-by: Alan Stokes <alan@source.dev> Helped-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jeff King [Sun, 26 Jul 2026 08:47:05 +0000 (04:47 -0400)]
diff-lib: skip paths outside prefix in oneway_diff()
Commit 8174627b3d (diff-lib: ignore paths that are outside $cwd if
--relative asked, 2021-08-22) taught run_diff_files() to skip entries
outside the requested prefix before processing them.
Do the same in oneway_diff(), which handles the diff-index code path.
The lower-level diff queue functions already reject such paths, but
checking here avoids unnecessary work and keeps them out of every
do_oneway_diff() code path.
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jeff King [Sun, 26 Jul 2026 08:46:22 +0000 (04:46 -0400)]
diff-lib: drop stale comment about advancing o->pos
The comment above oneway_diff() claims that the callback must advance
o->pos to skip index entries it has already processed. That stopped
being true in da165f470e (unpack-trees.c: prepare for looking ahead in
the index, 2010-01-07), which moved that bookkeeping into
unpack_trees().
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jeff King [Tue, 28 Jul 2026 15:14:58 +0000 (11:14 -0400)]
diff-lib: add idx/tree sanity check to oneway_diff
When looking just at the code in oneway_diff(), it seems possible for
both "idx" and "tree" to be NULL, in which case we'd potentially
segfault while checking the relative prefix.
But if you consider what these items actually mean, it shouldn't be
possible for both to be NULL. Let's add an assertion and a comment
documenting this. It might help human readers, but should also silence
static analyzers like Coverity which complain about the potential
segfault.
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
t: use commit_body to extract commit message bodies
Replace the "git cat-file commit | sed" idiom with commit_body across the
test suite: 61 sites in 12 files, plus one local helper that wrapped the
same idiom. The idiom appears in four equivalent spellings -- piped or
written to a file first, "sed -e" or plain "sed", "\$" or "$" in the
address -- all producing byte-identical output; they all collapse to the
same commit_body call.
t7509-commit-authorship.sh defined its own local message_body() helper
around the idiom instead of spelling it out at each call site; remove the
helper and convert its six call sites to commit_body directly.
Two sites needed more than a mechanical substitution:
* t7600.sh ("merge --no-ff --edit") greps the raw commit object for a
phrase before stripping its header for the final comparison. The
phrase is part of the commit body, not the header, so the grep can
run against the already-stripped body instead, letting both steps
share one commit_body call.
* t3900-i18n-commit.sh pipes the stripped body into "iconv" to test
re-encoding. Piping commit_body's output into "iconv" would reintroduce
an exit-code hole one line after removing it elsewhere, so this site
writes the body to a file first and reads that, keeping the &&-chain
intact.
Some greps for sed -e "1,/^\*$/d" left unconverted, as they are not extracting a commit's message body:
* t9001-send-email.sh strips mail headers from a message file, not a
commit object.
* t1450-fsck.sh strips the header off a hand-built commit object while
constructing a malformed one for fsck to reject.
* t4014-format-patch.sh runs the same sed address on a ".patch" file,
with an additional expression.
All converted files pass in full, and a deliberately failing
"git cat-file" now fails a converted test that previously passed.
Signed-off-by: Shlok Kulshreshtha <diy2903@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Extracting the message body of a commit -- running "git cat-file commit"
and stripping everything up to and including the first blank line with
"sed" -- is spelled out in about 60 places across the test suite.
Add a helper for it, so that the operation is written once instead of
being copied around.
The commit object goes to a temporary file rather than into a pipe,
because a pipeline reports only its last command's exit status, so a
failure of "git cat-file" would go unnoticed.
Signed-off-by: Shlok Kulshreshtha <diy2903@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
fetch-pack: accept "pack" output for packfile URIs
When index-pack finds an existing keep file it reports pack rather than
keep. Accept either result from http-fetch, and only register a keep
lockfile when this fetch created it.
Read the pack/keep prefix and hash without consuming any following fsck
output, validate the reported pack hash against the advertised hash, and
exercise a packfile URI fetch with a pre-existing keep file.
Signed-off-by: Ted Nyman <tnyman@openai.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
On Windows, an open file must permit FILE_SHARE_DELETE before another
process can unlink it. MinGW's non-append O_RDWR open enables that
sharing mode only for an existing file; adding O_CREAT falls back to
_wopen(), which cannot set it.
First try opening the partial pack without O_CREAT. If it does not
exist, create it exclusively, close that descriptor, and retry through
the existing-file path. A racing creator retries after EEXIST.
This ensures that every retained descriptor permits another downloader
to unlink the staging path. Add an unlink-while-indexing test that does
not require FIFOs and can therefore run on MinGW.
Signed-off-by: Ted Nyman <tnyman@openai.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Pack requests stage downloads in a predictable partial-pack file so an
interrupted transfer can be resumed. Both packfile URI and ordinary dumb
HTTP requests use this staging path. Opening it in append mode forces
each write to the current end of the file, so concurrent responses can
append duplicate data and corrupt the pack.
Open the partial pack read-write without O_APPEND and seek once to its
current end. Each downloader then retains the offset matching the Range
it requested. Because the staging key must uniquely identify immutable
pack contents, overlapping responses write the same bytes at the same
offsets instead of extending the file with duplicate data.
Duplicate the staging descriptor for index-pack instead of reopening the
path after closing the stream. Another downloader may unlink the staging
path before indexing begins, but index-pack can still read the retained
descriptor.
Exercise resumed transfers and overlapping 200 and 206 responses, and
clarify the staging-key documentation.
Signed-off-by: Ted Nyman <tnyman@openai.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
A resumed pack request may already have all bytes of the remote pack.
A server can respond to the resulting Range request with HTTP 416
instead of returning an empty response.
Accept that response in each pack-download caller and let index-pack
validate the completed staging file. This can happen without concurrent
downloads when a previous attempt completed the transfer but failed
before indexing it.
Add a regression test that seeds a complete partial pack and checks that
http-fetch indexes it after the server returns HTTP 416.
Signed-off-by: Ted Nyman <tnyman@openai.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
finish_http_pack_request() passes its staging-file descriptor to
index-pack through child_process.in. start_command() takes ownership
of a supplied descriptor and closes it, even when starting the child
fails.
Do not close the descriptor again after run_command() returns.
Signed-off-by: Ted Nyman <tnyman@openai.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
The --packfile mode accepts one --index-pack-arg=<arg> option per
argument passed to index-pack, but its documentation and option
dependency errors still refer to the plural --index-pack-args form.
Correct the spelling and describe the repeatable per-argument form.
Signed-off-by: Ted Nyman <tnyman@openai.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano [Mon, 27 Jul 2026 16:09:01 +0000 (09:09 -0700)]
Merge branch 'bc/rust-hash-cleanups'
A few memory problems in the Rust interface to C hash functions have
been corrected. The 'Clone' implementation of 'CryptoHasher' now
properly initializes the context before cloning, and its 'Drop'
implementation now discards the context to prevent leaks.
* bc/rust-hash-cleanups:
rust: discard hash context when finished
hash: initialize context before cloning
Junio C Hamano [Mon, 27 Jul 2026 16:09:00 +0000 (09:09 -0700)]
Merge branch 'pw/rebase-drop-notes-with-commit'
The rebase post-rewrite notes-copying logic has been corrected. When
a commit is dropped during rebase (e.g., because its changes are
already upstream), it is no longer recorded as rewritten, preventing
its notes from being copied to an unrelated commit.
* pw/rebase-drop-notes-with-commit:
sequencer: do not record dropped commits as rewritten
sequencer: use an enum to represent result of picking a commit
sequencer: simplify pick_one_commit()
sequencer: remove unnecessary condition in pick_one_commit()
sequencer: simplify handling of fixup with conflicts
sequencer: remove unnecessary "or" in pick_one_commit()
sequencer: never reschedule on failed commit
sequencer: be more careful with external merge
t3400: restore coverage for note copying with apply backend
Junio C Hamano [Mon, 27 Jul 2026 16:09:00 +0000 (09:09 -0700)]
Merge branch 'ps/copy-wo-the-repository'
The copy_file() and copy_file_with_time() functions have been
refactored to take a repository parameter, allowing the removal of the
implicit dependency on the global 'the_repository' variable in
'copy.c'.
* ps/copy-wo-the-repository:
copy: drop dependency on `the_repository`
The enumeration of untracked and ignored files in 'git status' has
been optimized by avoiding quadratic complexity when inserting into
string lists, reducing the construction cost from O(n^2) to O(n log
n).
* sc/wt-status-avoid-quadratic-insertion:
wt-status: avoid repeated insertion for untracked paths
Junio C Hamano [Mon, 27 Jul 2026 16:09:00 +0000 (09:09 -0700)]
Merge branch 'ps/refspec-wo-the-repository'
The dependency on the global 'the_repository' variable in the
'refspec.c' API has been removed by passing the hash algorithm
explicitly to refspec-parsing functions and storing it in 'struct
refspec'.
* ps/refspec-wo-the-repository:
refspec: stop depending on `the_repository`
refspec: let callers pass in hash algorithm when parsing items
refspec: group related structures and functions
Junio C Hamano [Mon, 27 Jul 2026 16:08:59 +0000 (09:08 -0700)]
Merge branch 'rs/remote-curl-simplify-push-specs'
The passing of push destination specifications in the 'remote-curl'
helper has been simplified by removing the explicit 'count' parameter
and relying on the NULL-termination of the array.
* rs/remote-curl-simplify-push-specs:
remote-curl: simplify passing of push specs
Junio C Hamano [Mon, 27 Jul 2026 16:08:59 +0000 (09:08 -0700)]
Merge branch 'td/ref-filter-memoize-contains'
'git branch --contains' and 'git for-each-ref --contains' have been
optimized to use the memoized commit traversal previously used only by
'git tag --contains', significantly speeding up connectivity checks
across many candidate refs with shared history.
* td/ref-filter-memoize-contains:
commit-reach: die on contains walk errors
ref-filter: memoize --contains with generations
commit-reach: reject cycles in contains walk
Junio C Hamano [Mon, 27 Jul 2026 16:08:59 +0000 (09:08 -0700)]
Merge branch 'ps/refs-wo-the-repository'
The ref subsystem and the worktree API have been refactored to pass a
repository pointer down the call chain, allowing them to drop
references to the global 'the_repository' variable. As part of this,
the handling of the 'core.packedRefsTimeout' configuration has been
moved into the per-repository ref store structure.
* ps/refs-wo-the-repository:
refs: remove remaining uses of `the_repository`
worktree: pass repository to public functions
worktree: pass repository to file-local functions
worktree: refactor code to use available repositories
refs/files: drop `USE_THE_REPOSITORY_VARIABLE`
refs/packed: de-globalize handling of "core.packedRefsTimeout"
Junio C Hamano [Mon, 27 Jul 2026 16:08:58 +0000 (09:08 -0700)]
Merge branch 'jc/submodule-helper-avoid-zu'
An accidental use of the '%zu' format specifier in 'git
submodule--helper' has been corrected to use 'PRIuMAX' and cast the
value to 'uintmax_t' to avoid portability issues.
* jc/submodule-helper-avoid-zu:
submodule--helper: avoid use of %zu for now
Junio C Hamano [Mon, 27 Jul 2026 16:08:58 +0000 (09:08 -0700)]
Merge branch 'ps/shift-root-in-graph'
'git log --graph' has been modified to visually distinguish parentless
'root' commits (and commits that become roots due to history
simplification) by indenting them, preventing them from appearing
falsely related to unrelated commits rendered immediately above them.
* ps/shift-root-in-graph:
graph: add --[no-]graph-indent and log.graphIndent
graph: move config reading into graph_read_config()
graph: wrap cascading commits after 4 columns
graph: indent visual root in graph
graph: add a 2 commit buffer for lookahead
revision: add next_commit_to_show()
lib-log-graph: move check_graph function
rebase: remember fixup -c after skipping fixup/squash
When the final command in a chain of "fixup" and "squash" commands
is skipped, we should prompt the user to edit the commit message
if the chain contains a "fixup -c" command that was not skipped.
Unfortunately, commit_staged_changes() only looks for completed "squash"
commands and so does not prompt the user to edit the message. Fix
this by recording whether a fixup command has the "-c" flag set and
then checking whether we have seen either a "fixup -c" or a "squash"
command. Add regression tests for skipping a command in the middle
of the chain (which currently works but has no test coverage), and
for skipping the final command (which is fixed by this patch).
Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>