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}()
Junio C Hamano [Wed, 29 Jul 2026 18:46:33 +0000 (11:46 -0700)]
Merge branch 'js/mingw-symlink-net-share-leak' into next
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, 29 Jul 2026 18:46:33 +0000 (11:46 -0700)]
Merge branch 'jk/t0014-dynamic-deprecated-cmds' into next
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, 29 Jul 2026 18:46:32 +0000 (11:46 -0700)]
Merge branch 'jk/ci-static-analysis-image-bump' into next
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
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>
Junio C Hamano [Tue, 28 Jul 2026 19:15:03 +0000 (12:15 -0700)]
Merge branch 'ps/odb-pluggable-housekeeping' into next
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 [Tue, 28 Jul 2026 19:15:03 +0000 (12:15 -0700)]
Merge branch 'pw/rebase-fixup-fixes' into next
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
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>
Junio C Hamano [Mon, 27 Jul 2026 16:10:56 +0000 (09:10 -0700)]
Merge branch 'en/submodule-insteadof-remote-match' into next
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, 27 Jul 2026 16:10:55 +0000 (09:10 -0700)]
Merge branch 'hn/branch-delete-merged' into next
The 'git branch' command has been taught the '--delete-merged' option
to remove local branches that are already merged into their tracked
remote-tracking branches.
* hn/branch-delete-merged:
branch: add --dry-run for --delete-merged
branch: add branch.<name>.deleteMerged opt-out
branch: add --delete-merged <branch>
branch: prepare delete_branches for a bulk caller
branch: let delete_branches skip unmerged branches on bulk refusal
branch: convert delete_branches() to a flags argument
branch: add --forked filter for --list mode
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>
rebase -i: fix counting of fixups after rebase --skip
When the sequencer processes a chain of "fixup" and "squash" commands
it keeps a list of the commands that have been executed. If there are
conflicts, then the list is saved when the rebase stops for the user to
resolve them. When the rebase resumes, the list is loaded and is used
to initialize the count of how many "fixup" and "squash" commands have
been processed; if a command has been skipped with "git rebase --skip",
then the last command needs to be popped off the end of the list.
To count the number of commands, commit_staged_changes() uses the
number of newlines in the file plus one. This is due to the slightly
unusual way the list is constructed - instead of appending a newline
when a command is added, a newline is inserted before the command
if the current count is greater than zero. Therefore, when we pop a
skipped command off the list, we should also remove the newline that
precedes it. Otherwise, when a new command is added, a blank line
will be left before it, which will contribute to the fixup count the
next time the file is read. Unfortunately, the preceding newline is
not removed, leading to an incorrect count. Fix this by removing the
newline that appears before the skipped command.
In addition to fixing the code that removes a skipped command from the
list, the code that reads the list is fixed to skip blank lines. We
have had reports of users starting a rebase with one version of
git and continuing it with another. Often this happens because the
version of git bundled with an IDE or TUI differs from the one used
at the command line. By fixing both the reading and writing ends of
the problem we ensure the count is correct when an older version of
git reads the fixup file written by a newer version and vice versa.
Triggering the incorrect count requires the user to skip two "fixup" or
"squash" commands before the final command in the chain. An existing
test is extended to prevent future regressions. The consequence of
miscounting is not serious: we just print the wrong count in the
header of the commit message template.
Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jeff King [Sun, 26 Jul 2026 08:39:05 +0000 (04:39 -0400)]
ci: bump ubuntu image version for static-analysis job
We recently ran into a case[1] where old versions of coccinelle ran very
slowly, but newer ones are fine. The version we use in GitHub's CI was
the old slow version, leading to timeouts of the static-analysis job.
We get the old version because we ask for the ubuntu-22.04 image. That
has coccinelle 1.1.1, but the "fast" improvement is in coccinelle 1.3.0,
specifically their 58619b8fe (break up envs for e1 & e2, 2024-08-18).
Bumping to ubuntu-25.10 would be enough to get that new version. But I
don't see any need to ask for a specific version at all. We originally
used a specific version because coccinelle wasn't available in ubuntu
20.04, so we pinned to 18.04 in d051ed77ee (.github/workflows/main.yml:
run static-analysis on bionic, 2021-02-08). Later that got bumped in ef46584831 (ci: update 'static-analysis' to Ubuntu 22.04, 2022-08-23)
when 18.04 support was dropped.
It seems like the absence of coccinelle was a blip in 20.04, and we can
just stick with "latest" going forward.
I tested the result on GitHub's CI. I bumped the matching line in the
GitLab definition, but didn't have a simple means of testing (but it's
such a trivial change nothing could go wrong, right?).
Using gcc 15, compiling with CHECK_ASSERTION_SIDE_EFFECTS=1 causes a
complaint about this line in bloom.c having a side effect:
assert(version == 1 || version == 2);
I think this is pretty clearly a false positive, as those comparisons
should not have side effects. The side-effect checker uses a magic
definition of assert() that relies on the compiler's optimizer to drop a
reference to an otherwise unused variable. And for whatever reason, gcc
chooses not to do so here under -O2 (side note: if you have -O0 in your
CFLAGS, that naturally creates many more false positives!).
This code has been around for a while, but nobody seems to have noticed
because we use an older version of the compiler in our static-analysis
ci job, and it does not complain. Presumably very few people run this
check locally on their more modern compilers.
Let's silence the false positive to avoid confusion for anyone running
locally, and to make it possible to upgrade the image we use for our
static-analysis job.
We could just switch to our custom ASSERT() here, but I think we can
improve the code by integrating the assertion into the if/else cascade.
That avoids repeating the logic about which versions are acceptable.
Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano [Sat, 25 Jul 2026 21:37:16 +0000 (14:37 -0700)]
Merge branch 'ps/odb-move-loose-object-writing' into next
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()`
Junio C Hamano [Sat, 25 Jul 2026 21:37:16 +0000 (14:37 -0700)]
Merge branch 'tl/gitweb-shorten-hashes-with-modes' into next
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 [Sat, 25 Jul 2026 21:37:15 +0000 (14:37 -0700)]
Merge branch 'jc/exclude-first-parent-seen' into next
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 [Sat, 25 Jul 2026 21:37:15 +0000 (14:37 -0700)]
Merge branch 'hn/url-push-tracking' into next
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
Harald Nordgren [Sat, 25 Jul 2026 11:32:15 +0000 (11:32 +0000)]
branch: add branch.<name>.deleteMerged opt-out
Setting branch.<name>.deleteMerged=false exempts that branch from
"git branch --delete-merged", which is useful for a topic you want
to keep developing after an early round of it has been merged
upstream. Unless --quiet is given, each skip is reported so the
user knows why their topic was kept.
Explicit deletion with "git branch -d" still uses the normal merge
check and ignores this setting.
Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
deletes local branches matching the optional patterns when their
configured upstream matches one of the --delete-merged arguments and
their tip is reachable from that upstream. The work has already landed
on the upstream they track, so the local copy is no longer needed.
The option can be repeated to widen the upstream match. Keeping the
candidate patterns as positional arguments lets users bound the set of
local branches that may be deleted independently of the upstream
selection.
A branch is not deleted when:
* it is checked out in any worktree
* its configured upstream ref no longer exists, since a missing
upstream is not by itself a sign of integration
* pushing it by name to the remote configured by
branch.<name>.remote would update its upstream, as determined by
mapping the branch ref through that remote's fetch refspec. For
example, a local "main" that tracks "origin/main" is kept even when
remote.pushDefault names a fork. Right after a pull it merely looks
fully merged.
A branch whose work is not yet merged into its upstream is silently
skipped, so one unmerged topic does not abort the whole sweep.
A branch that a surviving branch depends on through a chain of local
upstreams is also kept, so no branch is deleted out from under stacked
work. Collect this transitive set without changing the candidate set
during ref iteration: walk upstream chains from surviving branches,
visit each branch at most once, and remove the collected bases only
after the iteration completes. This makes the result independent of
ref iteration order without repeated full scans.
Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Harald Nordgren [Sat, 25 Jul 2026 11:32:13 +0000 (11:32 +0000)]
branch: prepare delete_branches for a bulk caller
Teach delete_branches() a new mode for the upcoming --delete-merged
caller that checks whether a branch is merged into its upstream without
falling back to HEAD when there is no upstream. Existing callers keep
their current behavior.
Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Harald Nordgren [Sat, 25 Jul 2026 11:32:12 +0000 (11:32 +0000)]
branch: let delete_branches skip unmerged branches on bulk refusal
Add a skip-unmerged mode to delete_branches() and check_branch_commit()
so a bulk caller can silently skip branches that are not fully merged
and carry on, rather than erroring with the "use 'git branch -D'"
advice that the plain "git branch -d" path emits. Existing callers are
unaffected.
Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Harald Nordgren [Sat, 25 Jul 2026 11:32:11 +0000 (11:32 +0000)]
branch: convert delete_branches() to a flags argument
delete_branches() takes separate force and quiet parameters, while
check_branch_commit() takes force. The next commits would grow this
collection further. Replace them with a single unsigned flags argument
and an enum.
Test the FORCE and QUIET bits directly from flags at each use site so
that mutating or forwarding flags cannot leave cached values stale.
No change in behavior.
Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Harald Nordgren [Sat, 25 Jul 2026 11:32:10 +0000 (11:32 +0000)]
branch: add --forked filter for --list mode
Add a --forked option to "git branch" list mode that lists only
branches whose configured upstream matches <branch>. The argument
can be a ref (e.g. "origin/main", "master"), a remote name like
"origin" for the branch its origin/HEAD points at, or a shell glob
(e.g. "origin/*"), and may be repeated to widen the filter.
It is an ordinary list filter, so it combines with the others:
Junio C Hamano [Sat, 25 Jul 2026 16:03:24 +0000 (09:03 -0700)]
remote: plug memory leaks
The in-core data structure used to keep track of
'url.<real>.{insteadOf,pushInsteadOf} = <alias>' settings is not
properly cleaned up when the process is done with it.
'struct rewrites' is embedded in 'remote_state' and serves as the
top level of the rewrite data. This holds an array of a variable
number of pointers to 'struct rewrite' allocated individually on the
heap. Each 'struct rewrite' holds a '.base' string and an array of
'struct counted_string' called '.instead_of', which is allocated
contiguously on the heap. Each 'struct counted_string' has a
pointer to a string allocated on the heap.
Amid these pointers, rewrites_release() fails to free everything
other than 'struct rewrite''s '.base' member and the 'struct rewrite'
instances themselves.
Fix rewrites_release() to also free the contiguous array storing
'.instead_of', the string pointers within each '.instead_of' element,
and each 'struct rewrite' instance individually allocated on the heap.
René Scharfe [Sat, 25 Jul 2026 10:41:07 +0000 (12:41 +0200)]
branch: report active bisect run when rejecting delete
git branch refuses to delete branches that are currently checked out
with a message like this: "error: cannot delete branch 'foo' used by
worktree at '/path/of/worktree'". This can be confusing if it's an
internal checkout for git bisect. Report a more specific error in
that case to help users that might have forgotten their bisect run.
Suggested-by: stsp <stsp2@yandex.ru> Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano [Fri, 24 Jul 2026 21:46:47 +0000 (14:46 -0700)]
Merge branch 'ps/cat-file-remote-object-info' into next
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 [Fri, 24 Jul 2026 21:46:47 +0000 (14:46 -0700)]
Merge branch 'jt/config-lock-timeout' into next
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
Adrian Friedli [Fri, 24 Jul 2026 12:41:38 +0000 (14:41 +0200)]
builtin/clone: fix segfault when using --revision with protocol v0
Servers supporting protocol v2 do not advertise excess refs and honor
`transport_ls_refs_options.ref_prefixes` when
$ git clone --revision=refs/heads/main $URL
contacts them, but when talking to a server that does not support
protocol v2 the client segfaults. This can also be observed when v0 is
enforced for example by
In the protocol v2 case the server honors
`transport_ls_refs_options.ref_prefixes` and in `cmd_clone()` the linked
list `refs` returned by `transport_get_remote_refs()` only contains a
single item, which is the ref requested with the --revision argument.
Both `remote_head` returned by `find_ref_by_name()` and
`remote_head_points_at` returned by `guess_remote_head()` are NULL. The
guard in `update_remote_refs()` skips a the affected code because
`remote_head_points_at` is NULL.
In the protocol v0 case in `cmd_clone()` the linked list `refs` returned
by `transport_get_remote_refs()` contains many items, amongst others
"HEAD". `remote_head` returned by `find_ref_by_name()` is not NULL and
`remote_head_points_at` returned by `guess_remote_head()` is not NULL
but its field `peer_ref` is NULL. Because `remote_head_points_at` is not
NULL the guard in `update_remote_refs()` does not skip the affected code
and `remote_head_points_at->peer_ref->name` is accessed, which causes a
segfault later on.
Signed-off-by: Adrian Friedli <adrian.friedli@mt.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Pablo Sabater [Fri, 24 Jul 2026 10:54:24 +0000 (12:54 +0200)]
cat-file: make remote-object-info allow-list adapt to the server
The static allow-list in expand_atom() is hardcoded to allow only
"objectname" and "objectsize" for remote queries. This works because,
up to this point, servers will either support object-info with name
and size or they do not support them at all.
As object-info gains new capabilities, we cannot expect different
servers with different Git versions to have the same object-info
capabilities. Therefore, the client needs to adapt its allow-list to
what the server advertises.
The client now:
1. Requests the protocol option that the placeholder refers to (i.e.
"size" for "%(objectsize)").
2. Drops any requested option that the server does not advertise in
fetch_object_info().
3. Maps the remaining advertised options back to their placeholders and
populates remote_allowed_atoms.
4. Uses remote_allowed_atoms in expand_atom(), preserving the previous
behavior for supported placeholders.
For example, if the client requests "%(objectsize) %(objecttype)" and
the server only supports 'size', then the client only requests 'size'.
The server returns the size (i.e "42") "%(objectsize)" is expanded
normally while "%(objecttype)" expands to an empty string:
"42 "
Note that the empty string expansion is only for known but unsupported
placeholders. "%(objectcolor)" which doesn't exist would die().
This honors what for-each-ref does for known but inapplicable atoms
(placeholders).
Move object_info_options out of get_remote_info() so the caller which
has data can select what options will be requested instead of requesting
always size.
Move batch_object_write() out so output is always produced.
If there are no supported attributes, the output is a blank line.
Include "type" in the object_info_options even though the client does
not yet know how to parse the server's "type" capability.
As a result, "type" is always filtered out, allowing the tests to verify
that known but unsupported placeholders expand to an empty string.
Since the filter removes options by swapping with the last element,
the list is no longer kept sorted. Drop the pre-sort in
fetch_object_info_via_pack() and use the unsorted string_list lookup
for the response header. This has no effect in performance as the list
can only be two entries long ('size' and 'type').
Mentored-by: Karthik Nayak <karthik.188@gmail.com> Mentored-by: Chandra Pratap <chandrapratap3519@gmail.com> Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Eric Ju [Fri, 24 Jul 2026 10:54:23 +0000 (12:54 +0200)]
cat-file: add remote-object-info to batch-command
Since the info command in cat-file --batch-command prints object
info for a given object, it is natural to add another command in
cat-file --batch-command to print object info for a given object
from a remote.
Add remote-object-info command to cat-file --batch-command.
While info takes object ids one at a time, this creates overhead when
making requests to a server. So remote-object-info instead can take
multiple object ids at once.
The cat-file --batch-command command is generally implemented in the
following manner:
- Receive and parse input from user
- Call respective function attached to command
- Get object info, print object info
In --buffer mode, this changes to:
- Receive and parse input from user
- Store respective function attached to command in a queue
- After flush, loop through commands in queue
- Call respective function attached to command
- Get object info, print object info
Notice how the getting and printing of object info is accomplished one
at a time. As described above, this creates a problem for making
requests to a server. Therefore, remote-object-info is implemented in
the following manner:
- Receive and parse input from user
If command is remote-object-info:
- Get object info from remote
- Loop through and print each object info
Else:
- Call respective function attached to command
- Parse input, get object info, print object info
And finally for --buffer mode remote-object-info:
- Receive and parse input from user
- Store respective function attached to command in a queue
- After flush, loop through commands in queue:
If command is remote-object-info:
- Get object info from remote
- Loop through and print each object info
Else:
- Call respective function attached to command
- Get object info, print object info
To summarize, remote-object-info gets object info from the remote and
then loops through the object info passed in, printing the info.
In order for remote-object-info to avoid remote communication
overhead in the non-buffer mode, the objects are passed in as such:
Placeholders in the format are validated against an allow-list of the
atoms the remote path supports: "objectname" and "objectsize".
Unsupported atoms expand to an empty string, honoring how for-each-ref
handles known but inapplicable atoms.
Without this, atoms like %(objecttype) would mark data->info.typep and
because the server only sends size, type_name() would later crash.
As extra safety, even outside of the remote path, initialize
expand_data's type to OBJ_BAD and handle type_name() returning NULL.
Helped-by: Jonathan Tan <jonathantanmy@google.com> Helped-by: Christian Couder <chriscool@tuxfamily.org> Mentored-by: Karthik Nayak <karthik.188@gmail.com> Mentored-by: Chandra Pratap <chandrapratap3519@gmail.com> Signed-off-by: Calvin Wan <calvinwan@google.com> Signed-off-by: Eric Ju <eric.peijian@gmail.com>
[pablo: added the atom allow-list validation] Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Calvin Wan [Fri, 24 Jul 2026 10:54:22 +0000 (12:54 +0200)]
transport: add client support for object-info
Sometimes, it is beneficial to retrieve information about an object
without downloading it entirely. The server-side logic for this
functionality was implemented in commit "a2ba162cda (object-info:
support for retrieving object info, 2021-04-20)." And the wire
format is documented at
https://git-scm.com/docs/protocol-v2#_object_info.
Introduce client-side support for the object-info capability.
Add its own function for object-info separate from existing fetch
infrastructure.
Currently, the client supports requesting a list of OIDs with the size
attribute from a v2 server. If the server does not advertise this
feature (i.e., transfer.advertiseobjectinfo is set to false), the client
returns an error and exits.
Note that:
1. The entire request is written into req_buf before being sent to the
remote. This approach follows the pattern used in the
send_fetch_request() logic within 'fetch-pack.c'. Streaming the
request is not addressed in this patch.
2. A new field 'unrecognized' has been added to object_info. This new
field is set at fetch_object_info() when the object is unrecognized
by the server.
Helped-by: Jonathan Tan <jonathantanmy@google.com> Helped-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Calvin Wan <calvinwan@google.com> Signed-off-by: Eric Ju <eric.peijian@gmail.com> Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Calvin Wan [Fri, 24 Jul 2026 10:54:21 +0000 (12:54 +0200)]
serve: advertise object-info feature
In order for a client to know what object-info components a server can
provide, advertise supported object-info features. This allows a client
to decide whether to query the server for object-info or fetch as a
fallback.
Helped-by: Jonathan Tan <jonathantanmy@google.com> Helped-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Calvin Wan <calvinwan@google.com> Signed-off-by: Eric Ju <eric.peijian@gmail.com> Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Pablo Sabater [Fri, 24 Jul 2026 10:54:20 +0000 (12:54 +0200)]
protocol-caps: check object existence regardless of the attributes requested
Currently, send_info() only checks for existence when the attribute
'size' is also requested. Requesting a bare OID, without attributes only
echoes back the OID.
Extract the existence check to be done regardless of the number of
attributes requested.
While at it, introduce a wrapper called get_object_info() similar to
odb_read_object_info() that returns OBJ_BAD on fail and adds
OBJECT_INFO_SKIP_FETCH_OBJECT and OBJECT_INFO_QUICK flags.
OBJECT_INFO_SKIP_FETCH_OBJECT is so a server with a partial clone
doesn't trigger fetching objects when it gets an object-info request
with an OID that is not available locally. A server should only report
what it has locally.
Tighten the condition used to determine whether an object is
recognized. get_object_info() returns OBJ_BAD for unknown objects,
but OBJ_NONE (0) can also mean "not found". Change the check from '< 0'
to '<= OBJ_NONE' to cover both as unrecognized.
With this patch, a bare OID has two possible responses:
1. Recognized OID: the server answers with "<OID>"
2. Unrecognized OID: the server answers with "<OID> SP"
Update the object-info section in 'gitprotocol-v2.adoc':
- Require full obj-oid explicitly.
- Fix parentheses.
- Define obj-size explicitly.
- Make obj-size optional in obj-info and document the behavior
for unrecognized object IDs.
- Describe the attr header as zero or more pkt-lines, one per attribute,
matching what the server implements. A request with no attributes gets
no header.
Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Calvin Wan [Fri, 24 Jul 2026 10:54:19 +0000 (12:54 +0200)]
fetch-pack: move fetch initialization
There are some variables initialized at the start of the
do_fetch_pack_v2() state machine. Currently, they are initialized in
FETCH_CHECK_LOCAL, which is the initial state set at the beginning
of the function.
However, a subsequent patch will allow for another initial state,
while still requiring these initialized variables.
Move the initialization to be before the state machine,
so that they are set regardless of the initial state.
Note that there is no change in behavior, because we're moving code
from the beginning of the first state to just before the execution of
the state machine.
Helped-by: Jonathan Tan <jonathantanmy@google.com> Helped-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Calvin Wan <calvinwan@google.com> Signed-off-by: Eric Ju <eric.peijian@gmail.com> Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Pablo Sabater [Fri, 24 Jul 2026 10:54:18 +0000 (12:54 +0200)]
connect: make write_fetch_command_and_capabilities() more generic
Refactor write_fetch_command_and_capabilities(), enabling it to serve
both fetch and additional commands.
In this context, "command" refers to the "operations" supported by
Git's wire protocol Documentation/gitprotocol-v2.adoc, such as a Git
subcommand (e.g., git-fetch(1)) or a server-side operation like
"object-info" as implemented in commit a2ba162cda
(object-info: support for retrieving object info, 2021-04-20).
Refactor the function signature to accept a command instead of the
hardcoded "fetch".
Helped-by: Jonathan Tan <jonathantanmy@google.com> Helped-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Calvin Wan <calvinwan@google.com> Signed-off-by: Eric Ju <eric.peijian@gmail.com> Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Pablo Sabater [Fri, 24 Jul 2026 10:54:17 +0000 (12:54 +0200)]
fetch-pack: move write_fetch_command_and_capabilities() to connect.c
In a subsequent commit write_fetch_command_and_capabilities() will be
refactored to a more general-purpose function, making it more accessible
to additional commands in the future.
Move write_fetch_command_and_capabilities() to 'connect.c', where
there are similar purpose functions.
Because string_list is only used as a pointer, use a forward
declaration [1].
Helped-by: Jonathan Tan <jonathantanmy@google.com> Helped-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Calvin Wan <calvinwan@google.com> Signed-off-by: Eric Ju <eric.peijian@gmail.com> Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Pablo Sabater [Fri, 24 Jul 2026 10:54:15 +0000 (12:54 +0200)]
fetch-pack: drop the static advertise_sid variable
write_fetch_command_and_capabilities() is moved to 'connect.c' in a
subsequent commit. To prepare for that, drop the static variable usage
of advertise_sid.
Currently advertise_sid is set in fetch_pack_config() by reading
"transfer.advertisesid". It is used in three places:
1. In do_fetch_pack(), to clear it when the server lacks support:
if (!server_supports("session-id"))
advertise_sid = 0;
2. In find_common(), to advertise the session id over protocol v0/v1:
if (advertise_sid)
strbuf_addf(&c, " session-id=%s", trace2_session_id());
3. In write_fetch_command_and_capabilities(), to advertise it over
protocol v2:
if (advertise_sid && server_supports_v2("session-id"))
packet_buf_write(req_buf, "session-id=%s", trace2_session_id());
About 1, the check only guards the v0/v1 path, and the v2 path
already checks server support inline in its condition. Follow the
same pattern and fold the check into the condition in find_common().
About 2 and 3, replace the static variable with a local read via
repo_config_get_bool() in each function.
Because repo_config_get_bool() leaves advertise_sid as is if it is not
set, initialize it to 0, matching its default.
Helped-by: Jonathan Tan <jonathantanmy@google.com> Helped-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Calvin Wan <calvinwan@google.com> Signed-off-by: Eric Ju <eric.peijian@gmail.com> Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Eric Ju [Fri, 24 Jul 2026 10:54:14 +0000 (12:54 +0200)]
t1006: extract helper functions into new 'lib-cat-file.sh'
Extract utility functions from the cat-file's test script
't1006-cat-file.sh' into a new 'lib-cat-file.sh' dedicated library file.
A subsequent commit will need these functions. This improves the code
reuse and readability, enabling future cat-file tests to share these
helpers without duplicating code.
While at it update the style of this line to follow coding
guidelines:
. "$TEST_DIRECTORY/lib-loose.sh"
to
. "$TEST_DIRECTORY"/lib-loose.sh
Signed-off-by: Eric Ju <eric.peijian@gmail.com> Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Eric Ju [Fri, 24 Jul 2026 10:54:13 +0000 (12:54 +0200)]
cat-file: declare loop counter inside for()
Declare loop counters in the for statement when they are only used
within the loop body, limiting their scope and improving readability.
While updating the loop counters, use size_t instead of int for counters
that iterate over object counts.
Update the 'nr' parameter of dispatch_calls() to size_t as all callers
already pass a value of that type.
Helped-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Eric Ju <eric.peijian@gmail.com> Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Pablo Sabater [Fri, 24 Jul 2026 10:54:12 +0000 (12:54 +0200)]
transport-helper: fix memory leak of helper on disconnect
disconnect_helper() only frees data inside of the if(data->helper) block
[1]. When the transport is disconnected without the helper being fully
started, data->name allocated in transport_helper_init()
is never freed.
Move FREE_AND_NULL(data->name) outside the conditional block so it's
always freed on disconnect.
Junio C Hamano [Thu, 23 Jul 2026 17:33:52 +0000 (10:33 -0700)]
Merge branch 'tn/stash-avoid-sparse-index-expansion' into next
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, 23 Jul 2026 17:33:51 +0000 (10:33 -0700)]
Merge branch 'sk/userdiff-swift' into next
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, 23 Jul 2026 17:33:51 +0000 (10:33 -0700)]
Merge branch 'ty/migrate-excludes-file' into next
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, 23 Jul 2026 17:33:51 +0000 (10:33 -0700)]
Merge branch 'ty/migrate-trust-executable-bit' into next
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, 23 Jul 2026 17:33:50 +0000 (10:33 -0700)]
Merge branch 'hn/history-squash' into next
The experimental 'git history' command has been taught a new 'squash'
subcommand to fold a range of commits into a single commit, with any
descendants replayed on top.
* hn/history-squash:
history: re-edit a squash with every message
sequencer: share the squash message marker helpers and flags
history: add squash subcommand to fold a range
history: give commit_tree_ext a message template
history: extract helper for a commit's parent tree
Add a built-in userdiff driver for the Swift programming language so that
diff hunk headers and word diffs work out of the box for ".swift" files.
The funcname pattern is built for Swift's own declaration grammar: an
optional run of attributes ("@objc", "@available(iOS 13, *)", ...),
followed by an optional run of lowercase modifiers ("public", "static",
"final", ...), followed by a declaration keyword (func, class, struct,
enum, protocol, extension, actor, init, deinit, subscript). The keyword
is followed by a boundary that allows whitespace, "(" (init/subscript),
"?" or "!" (failable init), or "<" (generics), while still acting as a
word boundary so e.g. "initialize(" does not match.
The word regex recognizes Swift identifiers, hexadecimal, octal, binary,
integer and floating-point literals, and the language's operators.
Signed-off-by: Shlok Kulshreshtha <diy2903@gmail.com> Acked-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Éric NICOLAS [Thu, 23 Jul 2026 00:21:32 +0000 (02:21 +0200)]
submodule: resolve insteadOf aliases when matching remote
When ca62f524c1 (submodule: look up remotes by URL first, 2025-06-23)
introduced a mechanism to identify which remote is to be used by a
submodule, it compared the URL stored in the .gitmodules inventory to
that of each available remote.
The URLs of remotes are rewritten according to url.<base>.insteadOf,
whereas those stored in the .gitmodules aren't. When such aliasing
applies, no match can be made between the two corresponding sides, and
the procedure degrades to its fallback logic electing either the only
configured remote if there is only one, or "origin" otherwise.
That behaviour is unfortunate when no remote is called "origin",
because its last resort will have a submodule update command look for a
non-existent remote-tracking reference and fail to proceed, instead of
using the remote whose rewritten URL matches.
Resolve the alias in the URL inventoried in .gitmodules before comparing
it against those of the corresponding submodule's configured remotes.
Signed-off-by: Éric NICOLAS <ccjmne@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano [Wed, 22 Jul 2026 17:03:13 +0000 (10:03 -0700)]
revision: honor --exclude-first-parent-only with SEEN first parent
The '--exclude-first-parent-only' option instructs the revision
walker to follow only the first parent of a merge commit to
propagate down the UNINTERESTING bit.
However, if the first parent has already been marked SEEN (for
example, because it was explicitly specified on the command line),
process_parents() skips it with a 'continue' statement. But the
loop then continues on to process the second parent, because the
check for the '--exclude-first-parent-only' option is near the end
of the loop, which the 'continue' statement skips. Consequently, we
end up marking the second parent as UNINTERESTING.
Break out of the loop instead of continuing when the first parent is
already SEEN or fails to parse. This ensures that we do not process
subsequent parents and mark them as UNINTERESTING.
Signed-off-by: Junio C Hamano <gitster@pobox.com> Reviewed-by: Jerry Zhang <jerry@skydio.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Harald Nordgren [Wed, 22 Jul 2026 18:08:58 +0000 (18:08 +0000)]
remote: find tracking branches for URL push destinations
Git accepts a repository URL as branch.<name>.pushRemote and can push
to it. This branch setting takes precedence over remote.pushDefault.
A branch can be configured with a URL-valued pushRemote before any push
occurs. If the remotes are later rearranged with "git remote rename" and
"git remote add", the newly added remote may use that URL. The URL value
is unaffected by the rename and continues to take precedence over
remote.pushDefault. The URL and the remote then point to the same
repository, but Git does not connect them for tracking. Pushing works,
but @{push} cannot identify the remote's tracking branch. As a result,
"git status" cannot show the push branch, and an up-to-date push can
leave its tracking information stale.
When exactly one configured remote would push to the same URL, use that
remote for push tracking. Continue to push to the URL so the configured
remote's push settings do not change existing behavior. Keep the current
behavior when no remote matches or multiple remotes match.
Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Harald Nordgren [Wed, 22 Jul 2026 18:08:57 +0000 (18:08 +0000)]
remote: pass repository to push tracking helper
The next commit needs tracking_for_push_dest() to inspect the
repository's configured remotes. Pass the repository through the
existing callers and mark the new parameter as unused.
No change in behavior.
Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Junio C Hamano [Wed, 22 Jul 2026 17:31:47 +0000 (10:31 -0700)]
Merge branch 'hn/bisect-reset-when-found' into next
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 [Wed, 22 Jul 2026 17:31:46 +0000 (10:31 -0700)]
Merge branch 'rs/tempfile-wo-the-repository' into next
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}()
Junio C Hamano [Wed, 22 Jul 2026 17:30:54 +0000 (10:30 -0700)]
Merge branch 'sk/t1100-modernize'
The test script 't/t1100-commit-tree-options.sh' has been modernized
by converting test cases to the modern style (using single quotes and
tab indentation) and moving the creation of the expected file inside
the setup test so it runs under the protection of the test harness.
* sk/t1100-modernize:
t1100: move creation of expected output into setup test
t1100: modernize test style
Junio C Hamano [Wed, 22 Jul 2026 17:30:54 +0000 (10:30 -0700)]
Merge branch 'ps/odb-for-each-object-filter'
The object database enumeration interface odb_for_each_object() has
been taught to accept object filters, allowing the underlying backends
to optimize the traversal by using reachability bitmaps when
available. 'git cat-file --batch-all-objects' has been updated to use
this generic interface, simplifying its code and avoiding direct
access to ODB backend internals.
* ps/odb-for-each-object-filter:
builtin/cat-file: filter objects via object database
odb: introduce object filters to `odb_for_each_object()`
pack-bitmap: introduce function to open bitmap for a single source
pack-bitmap: drop `_1` suffix from functions that open bitmaps
pack-bitmap: iterate object sources when opening bitmaps
pack-bitmap: allow aborting iteration of bitmapped objects
pack-objects: drop unused return value from add_object_entry()
pack-bitmap: mark object filter as `const`
odb/source-packed: improve lookup when enumerating objects
Junio C Hamano [Wed, 22 Jul 2026 17:30:54 +0000 (10:30 -0700)]
Merge branch 'rs/strbuf-avoid-redundant-reset'
A redundant strbuf_reset() call in the 'HAVE_GETDELIM' path of
strbuf_getwholeline() has been removed, as getdelim() overwrites the
buffer and the length is updated afterward.
* rs/strbuf-avoid-redundant-reset:
strbuf: avoid redundant reset in strbuf_getwholeline()