]> git.ipfire.org Git - thirdparty/git.git/log
thirdparty/git.git
3 months agoMerge branch 'ak/t9812-test-path-is-helpers'
Junio C Hamano [Fri, 20 Feb 2026 19:36:18 +0000 (11:36 -0800)] 
Merge branch 'ak/t9812-test-path-is-helpers'

Test update.

* ak/t9812-test-path-is-helpers:
  t9812: modernize test path helpers

3 months agoMerge branch 'pw/diff-anchored-optim'
Junio C Hamano [Fri, 20 Feb 2026 19:36:18 +0000 (11:36 -0800)] 
Merge branch 'pw/diff-anchored-optim'

"git diff --anchored=<text>" has been optimized.

* pw/diff-anchored-optim:
  diff --anchored: avoid checking unmatched lines

3 months agoMerge branch 'jc/doc-cg-c-comment'
Junio C Hamano [Fri, 20 Feb 2026 19:36:18 +0000 (11:36 -0800)] 
Merge branch 'jc/doc-cg-c-comment'

A CodingGuidelines update.

* jc/doc-cg-c-comment:
  CodingGuidelines: document // comments

3 months agoMerge branch 'pw/xdiff-cleanups'
Junio C Hamano [Fri, 20 Feb 2026 19:36:17 +0000 (11:36 -0800)] 
Merge branch 'pw/xdiff-cleanups'

Small clean-up of xdiff library to remove unnecessary data
duplication.

* pw/xdiff-cleanups:
  xdiff: remove unused data from xdlclass_t
  xdiff: remove "line_hash" field from xrecord_t

3 months agotree-diff: remove the usage of the_hash_algo global
Shreyansh Paliwal [Fri, 20 Feb 2026 17:51:26 +0000 (23:21 +0530)] 
tree-diff: remove the usage of the_hash_algo global

emit_path() uses the global the_hash_algo even though a local repository is
already available via struct diff_options *opt.

Replace these uses with opt->repo->hash_algo. With no remaining reliance on
global states in this file, drop the dependency on 'environment.h' and remove
'#define USE_THE_REPOSITORY_VARIABLE'.

This follows earlier cleanups to introduce opt->repo in tree-diff.c [1][2].

[1]- https://lore.kernel.org/git/20180921155739.14407-21-pclouds@gmail.com/
[2]- https://lore.kernel.org/git/20260109213021.2546-2-l.s.r@web.de/

Signed-off-by: Shreyansh Paliwal <shreyanshpaliwalcmsmn@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agocontrib/subtree: process out-of-prefix subtrees
Colin Stagner [Wed, 18 Feb 2026 02:31:32 +0000 (20:31 -0600)] 
contrib/subtree: process out-of-prefix subtrees

`should_ignore_subtree_split_commit` detects subtrees which are
outside of the current path --prefix and ignores them. This can
speed up splits of repositories that have many subtrees.

Since its inception [1], every iteration of this logic [2], [3]
incorrectly excludes commits. This alters the split history. The
split history and its commit hashes are API contract, so this is
not permissible.

While a commit from a different subtree may look like it doesn't
contribute anything to a split, sometimes it does. Merge commits
are a particular hot spot. For these, the pruning logic in
`copy_or_skip` performs:

1. a check for "treesame" parents
2. two different common ancestry checks

These checks operate on the **split history**, not the input
history. The split history omits commits that do not affect the
--prefix. This can significantly alter the ancestry of a merge.
In order to determine if `copy_or_skip` will skip a merge, it
is likely necessary to compute all the split history... which
is what `should_ignore_subtree_split_commit` tries to avoid.

To make this logic API-preserving, we could gate it behind a
new CLI argument. The present implementation is actually a
speed penalty in many cases, however, so this is not done here.

Remove the `should_ignore_subtree_split_commit` logic. This
fixes the regression reported in [4].

[1]: 98ba49ccc2 (subtree: fix split processing with multiple subtrees present, 2023-12-01)

[2]: 83f9dad7d6 (contrib/subtree: fix split with squashed subtrees, 2025-09-09)

[3]: 28a7e27cff (contrib/subtree: detect rewritten subtree commits, 2026-01-09)

[4]: <20251230170719.845029-1-george@mail.dietrich.pub>

Reported-by: George <george@mail.dietrich.pub>
Reported-by: Christian Heusel <christian@heusel.eu>
Signed-off-by: Colin Stagner <ask+git@howdoi.land>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agocontrib/subtree: test history depth
Colin Stagner [Wed, 18 Feb 2026 02:31:31 +0000 (20:31 -0600)] 
contrib/subtree: test history depth

Add history depth checks to some of the subtree unit tests.

These checks were previously introduced as part of 28a7e27cff
(contrib/subtree: detect rewritten subtree commits, 2026-01-09),
which has since been reverted.

Signed-off-by: Colin Stagner <ask+git@howdoi.land>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agocontrib/subtree: capture additional test-cases
Colin Stagner [Wed, 18 Feb 2026 02:31:30 +0000 (20:31 -0600)] 
contrib/subtree: capture additional test-cases

Patch series e7b07376e5 (Merge branch 'rs/subtree-fixes',
2018-10-26) corrects several defects in `git subtree split`.
The defects affect `split --rejoin` and merge commit processing.

There is no test coverage for this, and e7b07376e5 did not
introduce any.

Convert the minimum working example [1] from the original patch
submission [2] into test cases.

[1]: https://gist.github.com/FoxFireX/1b794384612b7fd5e7cd157cff96269e

[2]: <20180928183540.48968-1-roger.strain@swri.org>

Signed-off-by: Colin Stagner <ask+git@howdoi.land>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoapply: normalize path in --directory argument
Joaquim Rocha [Wed, 18 Feb 2026 00:15:32 +0000 (00:15 +0000)] 
apply: normalize path in --directory argument

When passing a relative path like --directory=./some/sub, the leading
"./" caused apply to prepend it literally to patch filenames, resulting
in an error (invalid path).
There may be more cases like this where users pass some/./path to the
directory which can easily be normalized to an acceptable path, so
these changes try to normalize the path before using it.

Signed-off-by: Joaquim Rocha <joaquim@amutable.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoMerge branch 'ps/for-each-ref-in-fixes' into ps/refs-for-each
Junio C Hamano [Fri, 20 Feb 2026 18:09:32 +0000 (10:09 -0800)] 
Merge branch 'ps/for-each-ref-in-fixes' into ps/refs-for-each

* ps/for-each-ref-in-fixes:
  bisect: simplify string_list memory handling
  bisect: fix misuse of `refs_for_each_ref_in()`
  pack-bitmap: fix bug with exact ref match in "pack.preferBitmapTips"
  pack-bitmap: deduplicate logic to iterate over preferred bitmap tips

3 months agoMerge branch 'lo/repo-info-keys' into lo/repo-leftover-bits
Junio C Hamano [Fri, 20 Feb 2026 17:17:56 +0000 (09:17 -0800)] 
Merge branch 'lo/repo-info-keys' into lo/repo-leftover-bits

* lo/repo-info-keys:
  repo: add new flag --keys to git-repo-info
  repo: rename the output format "keyvalue" to "lines"

3 months agoref-filter: clarify lstrip/rstrip component counting
Jeff King [Fri, 20 Feb 2026 06:00:03 +0000 (01:00 -0500)] 
ref-filter: clarify lstrip/rstrip component counting

When a strip option to the %(refname) placeholder is asked to leave N
path components, we first count up the path components to know how many
to remove. That happens with a loop like this:

/* Find total no of '/' separated path-components */
for (i = 0; p[i]; p[i] == '/' ? i++ : *p++)
;

which is a little hard to understand for two reasons.

First, the dereference in "*p++" is seemingly useless, since nobody
looks at the result. And static analyzers like Coverity will complain
about that. But removing the "*" will cause gcc to complain with
-Wint-conversion, since the two sides of the ternary do not match (one
is a pointer and the other an int).

Second, it is not clear what the meaning of "p" is at each iteration of
the loop, as its position with respect to our walk over the string
depends on how many slashes we've seen. The answer is that by itself, it
doesn't really mean anything: "p + i" represents the current state of
our walk, with "i" counting up slashes, and "p" by itself essentially
meaningless.

None of this behaves incorrectly, but ultimately the loop is just
counting the slashes in the refname. We can do that much more simply
with a for-loop iterating over the string and a separate slash counter.

We can also drop the comment, which is somewhat misleading. We are
counting slashes, not components (and a comment later in the function
makes it clear that we must add one to compensate). In the new code it
is obvious that we are counting slashes here.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agomailmap: drop global config variables
Burak Kaan Karaçay [Fri, 20 Feb 2026 06:04:42 +0000 (09:04 +0300)] 
mailmap: drop global config variables

The 'mailmap.file' and 'mailmap.blob' configurations are currently
parsed and stored in the global variables 'git_mailmap_file' and
'git_mailmap_blob'. Since these values are typically only needed once
when initializing a mailmap, there is no need to keep them as global
state throughout the lifetime of the Git process.

To reduce global state, remove these global variables and instead use
'repo_config_get_*' functions to read the configuration on demand.

Signed-off-by: Burak Kaan Karaçay <bkkaracay@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agomailmap: stop using the_repository
Burak Kaan Karaçay [Fri, 20 Feb 2026 06:04:41 +0000 (09:04 +0300)] 
mailmap: stop using the_repository

The 'read_mailmap' and 'read_mailmap_blob' functions rely on the global
'the_repository' variable. Update both functions to accept a
'struct repository' parameter.

Update all callers to pass 'the_repository' to retain the current
behavior.

Signed-off-by: Burak Kaan Karaçay <bkkaracay@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoosxkeychain: define build targets in the top-level Makefile.
Koji Nakamaru [Fri, 20 Feb 2026 01:39:00 +0000 (01:39 +0000)] 
osxkeychain: define build targets in the top-level Makefile.

The fix for git-credential-osxkeychain in 4580bcd235 (osxkeychain: avoid
incorrectly skipping store operation, 2025-11-14) introduced linkage
with libgit.a, and its Makefile was adjusted accordingly. However, the
build fails as of 864f55e190 because several macOS-specific refinements
were applied to the top-level Makefile and config.mak.uname, such as:

  - 363837afe7 (macOS: make Homebrew use configurable, 2025-12-24)
  - cee341e9dd (macOS: use iconv from Homebrew if needed and present,
    2025-12-24)
  - d281241518 (utf8.c: enable workaround for iconv under macOS 14/15,
    2026-01-12)

Since libgit.a and its corresponding header files depend on many flags
defined in the top-level Makefile, these flags must be consistently
defined when building git-credential-osxkeychain. Continuing to manually
adjust the git-credential-osxkeychain Makefile is cumbersome and
fragile.

Define the build targets for git-credential-osxkeychain in the top-level
Makefile and modify its local Makefile to simply rely on those targets.

Helped-by: Junio C Hamano <gitster@pobox.com>
Reported-by: D. Ben Knoble <ben.knoble@gmail.com>
Helped-by: Kristoffer Haugsbakk <kristofferhaugsbakk@fastmail.com>
Signed-off-by: Koji Nakamaru <koji.nakamaru@gree.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agot6006: don't use iconv(1) without ICONV prereq
Patrick Steinhardt [Fri, 20 Feb 2026 08:26:03 +0000 (09:26 +0100)] 
t6006: don't use iconv(1) without ICONV prereq

Two tests in t6006 depend on the iconv(1) prerequisite to reencode a
commit message. This executable may not even exist though in case the
prereq is not set, which will cause the tests to fail.

Fix this by using UTF-8 instead when the prereq is not set.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agot5550: add ICONV prereq to tests that use "$HTTPD_URL/error"
Patrick Steinhardt [Fri, 20 Feb 2026 08:26:02 +0000 (09:26 +0100)] 
t5550: add ICONV prereq to tests that use "$HTTPD_URL/error"

We've got a bunch of tests in t5550 that connect to "$HTTPD_URL/error"
to ensure that error messages are properly forwarded. This URL executes
the "t/lib-httpd/error.sh" script, which in turn depends on the iconv(1)
executable to reencode the message.

This executable may not exist on platforms, which will make the tests
fail. Guard them with the ICONV prereq to fix such failures.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agot4205: improve handling of ICONV prerequisite
Patrick Steinhardt [Fri, 20 Feb 2026 08:26:01 +0000 (09:26 +0100)] 
t4205: improve handling of ICONV prerequisite

In t4205 we have a bunch of tests that depend on the iconv prereq. This
is for most of the part because we format commit messages that have been
encoded in an encoding different than UTF-8.

Those tests fall into two classes though:

  - One class of tests outputs the data as-is without reencoding.

  - One class of tests outputs the data with "i18n.logOutputEncoding" to
    reencode it.

Curiously enough, both of these classes are marked with the ICONV
prereq, even though one might expect that the first class wouldn't need
the prereq. This is because we unconditionally use ISO-8859-1 encoding
for the initial commit message, and thus we depend on converting to
UTF-8 indeed.

This creates another problem though: when the iconv(1) executable does
not exist the test setup fails, even in the case where the ICONV prereq
has not been set.

Fix these issues by making the test encoding conditional on ICONV: if
it's available we use ISO-8859-1, otherwise we use UTF-8. This fixes the
test setup on platforms without iconv(1), and it allows us to drop the
ICONV prereq from a bunch of tests.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agot40xx: don't use iconv(1) without ICONV prereq
Patrick Steinhardt [Fri, 20 Feb 2026 08:26:00 +0000 (09:26 +0100)] 
t40xx: don't use iconv(1) without ICONV prereq

We've got a couple of tests related to diffs in t40xx that use the
iconv(1) executable to convert the encoding of a commit message. All of
these tests are prepared to handle a missing ICONV prereq, in which case
they will simply use UTF-8 encoding.

But even if the ICONV prerequisite has failed we try to use the iconv(1)
executable, even though it's not safe to assume that the executable
exists in that case. And besides that, it's also unnecessary to use
iconv(1) in the first place, as we would only use it to convert from
UTF-8 to UTF-8, which should be equivalent to a no-op.

Fix the issue and skip the call to iconv(1) in case the prerequisite is
not set. This makes tests work on systems that don't have iconv at all.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agot: don't set ICONV prereq when iconv(1) is missing
Patrick Steinhardt [Fri, 20 Feb 2026 08:25:59 +0000 (09:25 +0100)] 
t: don't set ICONV prereq when iconv(1) is missing

We've got a couple of tests that exercise Git with different encodings,
typically around commit messages. All of these tests depend on the ICONV
prerequisite, which is set when Git was built with support for iconv.

Many of those tests also end up using the iconv(1) executable to
reencode text. But while tests can rely on the fact that Git does have
support for iconv, they cannot assume that the iconv(1) executable
exists. The consequence is thus that tests will break in case Git is
built with iconv, but the executable doesn't exist. In fact, some of the
tests even use the iconv(1) executable unconditionally, regardless of
whether or not the ICONV prerequisite is set.

Git for Windows has recently (unintentionally) shipped a change where
the iconv(1) binary is not getting installed anymore [1]. And as we use
Git for Windows directly in MSVC+Meson jobs in GitLab CI this has caused
such tests to break. The missing iconv(1) binary is considered a bug
that will be fixed in Git for Windows. But regardless of that it makes
sense to not assume the binary to always exist so that our test suite
passes on platforms that don't have iconv at all.

Extend the ICONV prerequisite so that we know to skip tests in case the
iconv(1) binary doesn't exist. We'll adapt tests that are currently
broken in subsequent commits.

[1]: https://github.com/git-for-windows/git/issues/6083

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agohook: add -z option to "git hook list"
Adrian Ratiu [Wed, 18 Feb 2026 22:23:52 +0000 (00:23 +0200)] 
hook: add -z option to "git hook list"

Add a NUL-terminate mode to git hook list, just in case hooks are
configured with weird characters like newlines in their names.

Suggested-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agohook: allow out-of-repo 'git hook' invocations
Emily Shaffer [Wed, 18 Feb 2026 22:23:51 +0000 (00:23 +0200)] 
hook: allow out-of-repo 'git hook' invocations

Since hooks can now be supplied via the config, and a config can be
present without a gitdir via the global and system configs, we can start
to allow 'git hook run' to occur without a gitdir. This enables us to do
things like run sendemail-validate hooks when running 'git send-email'
from a nongit directory.

It still doesn't make sense to look for hooks in the hookdir in nongit
repos, though, as there is no hookdir.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agohook: allow event = "" to overwrite previous values
Adrian Ratiu [Wed, 18 Feb 2026 22:23:50 +0000 (00:23 +0200)] 
hook: allow event = "" to overwrite previous values

Add the ability for empty events to clear previously set multivalue
variables, so the newly added "hook.*.event" behave like the other
multivalued keys.

Suggested-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agohook: allow disabling config hooks
Adrian Ratiu [Wed, 18 Feb 2026 22:23:49 +0000 (00:23 +0200)] 
hook: allow disabling config hooks

Hooks specified via configs are always enabled, however users
might want to disable them without removing from the config,
like locally disabling a global hook.

Add a hook.<name>.enabled config which defaults to true and
can be optionally set for each configured hook.

Suggested-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agohook: include hooks from the config
Adrian Ratiu [Wed, 18 Feb 2026 22:23:48 +0000 (00:23 +0200)] 
hook: include hooks from the config

Teach the hook.[hc] library to parse configs to populate the list of
hooks to run for a given event.

Multiple commands can be specified for a given hook by providing
"hook.<friendly-name>.command = <path-to-hook>" and
"hook.<friendly-name>.event = <hook-event>" lines.

Hooks will be started in config order of the "hook.<name>.event"
lines and will be run sequentially (.jobs == 1) like before.
Running the hooks in parallel will be enabled in a future patch.

The "traditional" hook from the hookdir is run last, if present.

A strmap cache is added to struct repository to avoid re-reading
the configs on each rook run. This is useful for hooks like the
ref-transaction which gets executed multiple times per process.

Examples:

  $ git config --get-regexp "^hook\."
  hook.bar.command=~/bar.sh
  hook.bar.event=pre-commit

  # Will run ~/bar.sh, then .git/hooks/pre-commit
  $ git hook run pre-commit

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agohook: add "git hook list" command
Emily Shaffer [Wed, 18 Feb 2026 22:23:47 +0000 (00:23 +0200)] 
hook: add "git hook list" command

The previous commit introduced an ability to run multiple commands for
hook events and next commit will introduce the ability to define hooks
from configs, in addition to the "traditional" hooks from the hookdir.

Introduce a new command "git hook list" to make inspecting hooks easier
both for users and for the tests we will add.

Further commits will expand on this, e.g. by adding a -z output mode.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agohook: run a list of hooks to prepare for multihook support
Emily Shaffer [Wed, 18 Feb 2026 22:23:46 +0000 (00:23 +0200)] 
hook: run a list of hooks to prepare for multihook support

Hooks are limited to run one command (the default from the hookdir) for
each event. This limitation makes it impossible to run multiple commands
via config files, which the next commits will add.

Implement the ability to run a list of hooks in hook.[ch]. For now, the
list contains only one entry representing the "default" hook from the
hookdir, so there is no user-visible change in this commit.

All hook commands still run sequentially like before. A separate patch
series will enable running them in parallel.

Signed-off-by: Emily Shaffer <emilyshaffer@google.com>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agohook: add internal state alloc/free callbacks
Adrian Ratiu [Wed, 18 Feb 2026 22:23:45 +0000 (00:23 +0200)] 
hook: add internal state alloc/free callbacks

Some hooks use opaque structs to keep internal state between callbacks.

Because hooks ran sequentially (jobs == 1) with one command per hook,
these internal states could be allocated on the stack for each hook run.

Next commits add the ability to run multiple commands for each hook, so
the states cannot be shared or stored on the stack anymore, especially
since down the line we will also enable parallel execution (jobs > 1).

Add alloc/free helpers for each hook, doing a "deep" alloc/init & free
of their internal opaque struct.

The alloc callback takes a context pointer, to initialize the struct at
at the time of resource acquisition.

These callbacks must always be provided together: no alloc without free
and no free without alloc, otherwise a BUG() is triggered.

Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agopath: remove repository argument from worktree_git_path()
Phillip Wood [Thu, 19 Feb 2026 14:26:33 +0000 (14:26 +0000)] 
path: remove repository argument from worktree_git_path()

worktree_git_path() takes a struct repository and a struct worktree
which also contains a struct repository. The repository argument
was added by a973f60dc7c (path: stop relying on `the_repository` in
`worktree_git_path()`, 2024-08-13) and exists because the worktree
argument is optional. Having two ways of passing a repository is
a potential foot-gun as if the the worktree argument is present the
repository argument must match the worktree's repository member. Since
the last commit there are no callers that pass a NULL worktree so lets
remove the repository argument. This removes the potential confusion
and lets us delete a number of uses of "the_repository".

worktree_git_path() has the following callers:

 - builtin/worktree.c:validate_no_submodules() which is called from
   check_clean_worktree() and move_worktree(), both of which supply
   a non-NULL worktree.

 - builtin/fsck.c:cmd_fsck() which loops over all worktrees.

 - revision.c:add_index_objects_to_pending() which loops over all
   worktrees.

 - worktree.c:worktree_lock_reason() which dereferences wt before
   calling worktree_git_path().

 - wt-status.c:wt_status_check_bisect() and wt_status_check_rebase()
   which are always called with a non-NULL worktree after the last
   commit.

 - wt-status.c:git_branch() which is only called by
   wt_status_check_bisect() and wt_status_check_rebase().

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agowt-status: avoid passing NULL worktree
Phillip Wood [Thu, 19 Feb 2026 14:26:32 +0000 (14:26 +0000)] 
wt-status: avoid passing NULL worktree

In preparation for removing the repository argument from
worktree_git_path() add a function to construct a "struct worktree"
from a "struct repository" using its "gitdir" and "worktree"
members. This function is then used to avoid passing a NULL worktree to
wt_status_check_bisect() and wt_status_check_rebase(). In general the
"struct worktree" returned may not correspond to the "current" worktree
defined by is_current_worktree() as that function uses "the_repository"
rather than "wt->repo" when deciding which worktree is "current". In
practice the "struct repository" we pass corresponds to "the_repository"
as we only ever operate on a single repository at the moment.

wt_status_check_bisect() and wt_status_check_rebase() have the following
callers:

 - branch.c:prepare_checked_out_branches() which loops over all
   worktrees.

 - worktree.c:is_worktree_being_rebased() which is called from
   builtin/branch.c:reject_rebase_or_bisect_branch() that loops over all
   worktrees and worktree.c:is_shared_symref() which dereferences wt
   earlier in the function.

 - wt-status:wt_status_get_state() which is updated to avoid passing a
   NULL worktree by this patch.

This updates the only callers that pass a NULL worktree to
worktree_git_path(). A new test is added to check that "git status"
detects a rebase in a linked worktree.

Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agobisect: simplify string_list memory handling
Jeff King [Thu, 19 Feb 2026 07:57:52 +0000 (08:57 +0100)] 
bisect: simplify string_list memory handling

We declare the refs_for_removal string_list as NODUP, forcing us to
manually allocate strings we insert. And then when it comes time to
clean up, we set strdup_strings so that string_list_clear() will free
them for us.

This is a confusing pattern, and can be done much more simply by just
declaring the list with the DUP initializer in the first place.

It was written this way originally because one of the callsites
generated the item using xstrfmt(). But that spot switched to a plain
xstrdup() in the preceding commit. That means we can now just let the
string_list code handle allocation itself.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agobisect: fix misuse of `refs_for_each_ref_in()`
Patrick Steinhardt [Thu, 19 Feb 2026 07:57:51 +0000 (08:57 +0100)] 
bisect: fix misuse of `refs_for_each_ref_in()`

All callers of `refs_for_each_ref_in()` pass in a string that is
terminated with a trailing slash to indicate that they only want to see
refs in that specific ref hierarchy. This is in fact a requirement if
one wants to use this function, as the function trims the prefix from
each yielded ref. So if there was a reference that was called
"refs/bisect" as in our example, the result after trimming would be the
empty string, and that's something we disallow.

Fix this by adding the trailing slash.

Furthermore, taking a closer look, we strip the prefix only to re-add it
in `mark_for_removal()`. This is somewhat roundabout, as we can instead
call `refs_for_each_fullref_in()` to not do any stripping at all. Do so
to simplify the code a bit.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agopack-bitmap: fix bug with exact ref match in "pack.preferBitmapTips"
Patrick Steinhardt [Thu, 19 Feb 2026 07:57:50 +0000 (08:57 +0100)] 
pack-bitmap: fix bug with exact ref match in "pack.preferBitmapTips"

The "pack.preferBitmapTips" configuration allows the user to specify
which references should be preferred when generating bitmaps. This
option is typically expected to be set to a reference prefix, like for
example "refs/heads/".

It's not unreasonable though for a user to configure one specific
reference as preferred. But if they do, they'll hit a `BUG()`:

    $ git -c pack.preferBitmapTips=refs/heads/main repack -adb
    BUG: ../refs/iterator.c:366: attempt to trim too many characters
    error: pack-objects died of signal 6

The root cause for this bug is how we enumerate these references. We
call `refs_for_each_ref_in()`, which will:

  - Yield all references that have a user-specified prefix.

  - Trim each of these references so that the prefix is removed.

Typically, this function is called with a trailing slash, like
"refs/heads/", and in that case things work alright. But if the function
is called with the name of an existing reference then we'll try to trim
the full reference name, which would leave us with an empty name. And as
this would not really leave us with anything sensible, we call `BUG()`
instead of yielding this reference.

One could argue that this is a bug in `refs_for_each_ref_in()`. But the
question then becomes what the correct behaviour would be:

  - Do we want to skip exact matches? In our case we certainly don't
    want that, as the user has asked us to generate a bitmap for it.

  - Do we want to yield the reference with the empty refname? That would
    lead to a somewhat weird result.

Neither of these feel like viable options, so calling `BUG()` feels like
a sensible way out. The root cause ultimately is that we even try to
trim the whole refname in the first place. There are two possible ways
to fix this issue:

  - We can fix the bug by using `refs_for_each_fullref_in()` instead,
    which does not strip the prefix at all. Consequently, we would now
    start to accept all references that start with the configured
    prefix, including exact matches. So if we had "refs/heads/main", we
    would both match "refs/heads/main" and "refs/heads/main-branch".

  - Or we can fix the bug by appending a slash to the prefix if it
    doesn't already have one. This would mean that we only match
    ref hierarchies that start with this prefix.

While the first fix leaves the user with strictly _more_ configuration
options, we have already fixed a similar case in 10e8a9352b (refs.c:
stop matching non-directory prefixes in exclude patterns, 2025-03-06) by
using the second option. So for the sake of consistency, let's apply the
same fix here.

Clarify the documentation accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agopack-bitmap: deduplicate logic to iterate over preferred bitmap tips
Patrick Steinhardt [Thu, 19 Feb 2026 07:57:49 +0000 (08:57 +0100)] 
pack-bitmap: deduplicate logic to iterate over preferred bitmap tips

We have two locations that iterate over the preferred bitmap tips as
configured by the user via "pack.preferBitmapTips". Both of these
callsites are subtly wrong: when the preferred bitmap tips contain an
exact refname match, then we will hit a `BUG()`.

Prepare for the fix by unifying the two callsites into a new
`for_each_preferred_bitmap_tip()` function.

This removes the last callsite of `bitmap_preferred_tips()` outside of
"pack-bitmap.c". As such, convert the function to be local to that file
only. Note that the function is still used by a second caller, so we
cannot just inline it.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agogitlab-ci: handle failed tests on MSVC+Meson job
Patrick Steinhardt [Thu, 19 Feb 2026 06:25:33 +0000 (07:25 +0100)] 
gitlab-ci: handle failed tests on MSVC+Meson job

The MSVC+Meson job does not currently have any logic to print failing
tests, nor does it upload the failed test artifacts. Backfill this logic
to make help debugging efforts in case any of its jobs has failed.

GitHub already knows to do this, so we don't need an equivalent change
over there.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agogitlab-ci: use "run-test-slice-meson.sh"
Patrick Steinhardt [Thu, 19 Feb 2026 06:25:32 +0000 (07:25 +0100)] 
gitlab-ci: use "run-test-slice-meson.sh"

While our GitHub workflow already uses "ci/run-test-slice-meson.sh",
GitLab CI open-codes the parameters. Adapt the latter to also use the
same script so that we always use the same Meson options across both CI
systems.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoci: make test slicing consistent across Meson/Make
Patrick Steinhardt [Thu, 19 Feb 2026 06:25:31 +0000 (07:25 +0100)] 
ci: make test slicing consistent across Meson/Make

In the preceding commit we have adjusted test slicing to be one-based
when using the "ci/run-test-slice.sh" script. But we also have an
equivalent script for Meson that is still zero-based, which is of course
inconsistent.

Adapt the script to be one-based, as well, and adapt the GitHub workflow
accordingly. Note that GitLab doesn't yet use the script, so it does not
need to be adapted. This will change in the next commit though.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agogithub: fix Meson tests not executing at all
Patrick Steinhardt [Thu, 19 Feb 2026 06:25:30 +0000 (07:25 +0100)] 
github: fix Meson tests not executing at all

While the win+Meson test jobs run in GitHub workflows, the shell script
that is supposed to run the jobs is seemingly not running at all. All
that the CI job prints is the following:

  Run ci/run-test-slice-meson.sh build 1 10
    ci/run-test-slice-meson.sh build 1 10
    shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'"
    env:
      DEVELOPER: 1

The step is currently defined to use PowerShell, and of course it
doesn't know how to execute POSIX shell scripts. What's surprising
though is that this step doesn't even lead to a CI failure.

Fix the issue by using Bash instead of PowerShell, as we do in other
steps that execute shell scripts.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agomeson: fix MERGE_TOOL_DIR with "--no-bin-wrappers"
Patrick Steinhardt [Thu, 19 Feb 2026 06:25:29 +0000 (07:25 +0100)] 
meson: fix MERGE_TOOL_DIR with "--no-bin-wrappers"

On Windows, we execute tests with "--no-bin-wrappers". This has been
introduced via a87e427e35 (ci: speed up Windows phase, 2019-01-29) to
save some time: spawning processes is expensive on Windows, and shell
scripts tend to spawn a bunch of them. So overall, the bin-wrappers led
to a performance overhead of ~10-30%.

This causes test failures when using Meson on Windows:

  failure: t7610.28 mergetool --tool-help shows recognized tools
    ++ git mergetool --tool-help
    /d/a/git/git/build/git-mergetool--lib: line 45: cd: D:/a/git/git/build/mergetools: No such file or directory

The root cause here is that our bin-wrappers are usually responsible for
setting up the `MERGE_TOOL_DIR` environment variable so that we can
locate these scripts. But as we don't use the bin-wrappers, we'll
instead use the default location for merge tools, which is derived from
`GIT_EXEC_PATH`. And as `GIT_EXEC_PATH` points to our build directory,
which won't ever contain any of the merge tools, we will fail to locate
any of the merge tools.

This issue has went unnoticed for a long time given that we only skip
bin-wrappers on Windows, and because the CI jobs on Windows didn't
execute due to a bug.

Fix the issue by always setting the `MERGE_TOOL_DIR` environment
variable to the correct directory.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoci: don't skip smallest test slice in GitLab
Patrick Steinhardt [Thu, 19 Feb 2026 06:25:28 +0000 (07:25 +0100)] 
ci: don't skip smallest test slice in GitLab

The "ci/run-test-slice.sh" script can be used to slice up all of our
tests into N pieces and then run each of them on a separate CI job.
This is used by both GitLab and GitHub CI to speed up Windows tests,
which would otherwise be painfully slow.

The infra itself is fueled by `test-tool path-utils slice-tests`. This
tool receives as input an "offset" and a "stride" that can be combined
to slice up tests. This framing can be misleading though: you are
expected to pass a zero-based index as "offset", and the complete number
of slices to the "stride". The latter makes sense, but it is somewhat
surprising that the offset needs to be zero-based. And this is in fact
biting us: while GitHub passes zero-based indices, GitLab passes
`$CI_NODE_INDEX`, which is a one-based indice.

Ideally, we should have verification that the parameters make sense.
And naturally, one would for example expect that it's an error to call
the binary with an offset larger than the stride. But with the current
framing as "offset" it's not even wrong to do so, as it is of course
well-defined to start at a larger offset than the stride.

This means that we get this wrong on GitLab's CI, as we pass a one based
index there, and this causes us to skip one of the tests. Interestingly,
it's not the lexicographically first test that we skip. Instead, as we
sort tests by size before slicing them, we skip the _smallest_ test.

Reframe the problem to instead talk about "slice number" and "total
number of slices". For all of our use cases this is semantically
equivalent, but it allows us to perform some verifications:

  - The total number of slices must be greater than 1.

  - The selected slice must be between 1 <= nr <= slices_total.

As the indices are now one-based it means that GitLab's CI is fixed.
The GitHub workflow is updated accordingly.

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>
3 months agoci: handle failures of test-slice helper
Patrick Steinhardt [Thu, 19 Feb 2026 06:25:27 +0000 (07:25 +0100)] 
ci: handle failures of test-slice helper

The "run-test-slice.sh" script executes the test helper to slice up
tests passed to it. As the execution is part of a pipe though, we end up
ignoring any potential error code returned by the helper.

Make the code more robust by storing the tests in a variable first so
that we can split up the pipeline.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agocompletion: fix zsh alias listing for subsection aliases
Jonatan Holmgren [Wed, 18 Feb 2026 21:57:37 +0000 (22:57 +0100)] 
completion: fix zsh alias listing for subsection aliases

The zsh completion function __git_zsh_cmd_alias() uses 'git config
--get-regexp' to enumerate aliases and then strips the "alias." prefix
from each key. For subsection-style aliases (alias.name.command), this
leaves "name.command" as the completion candidate instead of just
"name".

The bash completion does not have this problem because it goes through
'git --list-cmds=alias', which calls list_aliases() in C and already
handles both alias syntaxes correctly. However, zsh needs both the
alias name and its value for descriptive completion, which
--list-cmds=alias does not provide.

Add a hidden --aliases-for-completion option to 'git help', following
the existing --config-for-completion pattern. It outputs NUL-separated
"name\nvalue" pairs using list_aliases(), which correctly resolves both
the traditional (alias.name) and subsection (alias.name.command)
formats. Update __git_zsh_cmd_alias() to use it.

Signed-off-by: Jonatan Holmgren <jonatan@jontes.page>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoalias: support non-alphanumeric names via subsection syntax
Jonatan Holmgren [Wed, 18 Feb 2026 21:57:36 +0000 (22:57 +0100)] 
alias: support non-alphanumeric names via subsection syntax

Git alias names are limited to ASCII alphanumeric characters and
dashes because aliases are implemented as config variable names.
This prevents aliases being created in languages using characters outside that range.

Add support for arbitrary alias names by using config subsections:

    [alias "förgrena"]
        command = branch

The subsection name is matched as-is (case-sensitive byte comparison),
while the existing definition without a subsection (e.g.,
"[alias] co = checkout") remains case-insensitive for backward
compatibility. This uses existing config infrastructure since
subsections already support arbitrary bytes, and avoids introducing
Unicode normalization.

Also teach the help subsystem about the new syntax so that "git help
-a" properly lists subsection aliases and the autocorrect feature can
suggest them. Use utf8_strwidth() instead of strlen() for column
alignment so that non-ASCII alias names display correctly.

Suggested-by: Jeff King <peff@peff.net>
Signed-off-by: Jonatan Holmgren <jonatan@jontes.page>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoalias: prepare for subsection aliases
Jonatan Holmgren [Wed, 18 Feb 2026 21:57:35 +0000 (22:57 +0100)] 
alias: prepare for subsection aliases

Switch git_unknown_cmd_config() from skip_prefix() to
parse_config_key() for alias parsing. This properly handles the
three-level config key structure and prepares for the new
alias.*.command subsection syntax in the next commit.

This is a compatibility break: the alias configuration parser used
to be overly permissive and accepted "alias.<subsection>.<key>" as
defining an alias "<subsection>.<key>". With this change,
alias.<subsection>.<key> entries are silently ignored (unless <key>
is "command", which will be given meaning in the next commit).

This behavior was arguably a bug, since config subsections were never
intended to work this way for aliases, and aliases with dots in their
names have never been documented or intentionally supported.

Signed-off-by: Jonatan Holmgren <jonatan@jontes.page>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agohelp: use list_aliases() for alias listing
Jonatan Holmgren [Wed, 18 Feb 2026 21:57:34 +0000 (22:57 +0100)] 
help: use list_aliases() for alias listing

help.c has its own get_alias() config callback that duplicates the
parsing logic in alias.c. Consolidate by teaching list_aliases() to
also store the alias values (via the string_list util field), then
use it in list_all_cmds_help_aliases() instead of the private
callback.

This preserves the existing error checking for value-less alias
definitions by checking in alias.c rather than help.c.

No functional change intended.

Signed-off-by: Jonatan Holmgren <jonatan@jontes.page>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoobject-file: use `container_of()` to convert from base types
Justin Tobler [Wed, 18 Feb 2026 21:01:20 +0000 (15:01 -0600)] 
object-file: use `container_of()` to convert from base types

To improve code hygiene, replace direct casts from `struct
odb_transaction` and `struct odb_read_stream` to their concrete
implementations with `container_of()`.

Signed-off-by: Justin Tobler <jltobler@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agodoc: fetch: document `--jobs=0` behavior
Daniel D. Beck [Wed, 18 Feb 2026 19:32:39 +0000 (19:32 +0000)] 
doc: fetch: document `--jobs=0` behavior

In c39952b92 (fetch: choose a sensible default with --jobs=0 again,
2023-02-20), the `--jobs=0` behavior was (re)introduced, but it went
undocumented. Since this is the same behavior as `git -c fetch.parallel=0
fetch`, which is documented, this change creates symmetry between the two
documentation sections.

Signed-off-by: Daniel D. Beck <daniel@ddbeck.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agocommit: use commit graph in `lookup_commit_reference_gently()`
Patrick Steinhardt [Mon, 16 Feb 2026 15:38:03 +0000 (16:38 +0100)] 
commit: use commit graph in `lookup_commit_reference_gently()`

In the preceding commit we refactored `lookup_commit_reference_gently()`
so that it doesn't parse non-commit objects anymore. This has led to a
speedup when git-receive-pack(1) accepts a shallow push into a repo
with lots of refs that point to blobs or trees.

But while this case is now faster, we still have the issue that
accepting pushes with lots of "normal" refs that point to commits are
still slow. This is mostly because we look up the commits via the object
database, and that is rather costly.

Adapt the code to use `repo_parse_commit_gently()` instead of
`parse_object()` to parse the resulting commit object. This function
knows to use the commit-graph to fill in the object, which is way more
cost efficient.

This leads to another significant speedup when accepting shallow pushes.
The following benchmark pushes a single objects from a shallow clone
into a repository with 600,000 references that all point to commits:

  Benchmark 1: git-receive-pack (rev = HEAD~)
    Time (mean ± σ):      9.179 s ±  0.031 s    [User: 8.858 s, System: 0.528 s]
    Range (min … max):    9.154 s …  9.213 s    3 runs

  Benchmark 2: git-receive-pack (rev = HEAD)
    Time (mean ± σ):      2.337 s ±  0.032 s    [User: 2.331 s, System: 0.234 s]
    Range (min … max):    2.308 s …  2.371 s    3 runs

  Summary
    git-receive-pack . </tmp/input (rev = HEAD) ran
      3.93 ± 0.05 times faster than git-receive-pack (rev = HEAD~)

Also, this again leads to a significant reduction in memory allocations.
Before this change:

  HEAP SUMMARY:
      in use at exit: 17,524,978 bytes in 22,393 blocks
    total heap usage: 33,313 allocs, 10,920 frees, 407,774,251 bytes allocated

And after this change:

  HEAP SUMMARY:
      in use at exit: 11,534,036 bytes in 12,406 blocks
    total heap usage: 13,284 allocs, 878 frees, 15,521,451 bytes allocated

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agocommit: make `repo_parse_commit_no_graph()` more robust
Patrick Steinhardt [Mon, 16 Feb 2026 15:38:02 +0000 (16:38 +0100)] 
commit: make `repo_parse_commit_no_graph()` more robust

In the next commit we will start to parse more commits via the
commit-graph. This change will lead to a segfault though because we try
to access the tree of a commit via `repo_get_commit_tree()`, but:

  - The commit has been parsed via the commit-graph, and thus its
    `maybe_tree` field is not yet populated.

  - We cannot use the commit-graph to populate the commit's tree because
    we're in the process of writing the commit-graph.

The consequence is that we'll get a `NULL` pointer for the tree in
`write_graph_chunk_data()`.

In theory we are already mindful of this situation, as we explicitly use
`repo_parse_commit_no_graph()` to parse the commit without the help of
the commit-graph. But that doesn't do the trick as the commit is already
marked as parsed, so the function will not re-populate it. And as the
commit-graph has been closed, neither will `get_commit_tree_oid()` be
able to load the tree for us.

It seems like this issue can only be hit under artificial circumstances:
the error was hit via `git_test_write_commit_graph_or_die()`, which is
run by git-commit(1) and git-merge(1) in case `GIT_TEST_COMMIT_GRAPH=1`:

  $ GIT_TEST_COMMIT_GRAPH=1 meson test t7507-commit-verbose \
      --test-args=-ix -i
  ...
  ++ git -c commit.verbose=true commit --amend
  hint: Waiting for your editor to close the file...
  ./test-lib.sh: line 1012: 55895 Segmentation fault         (core dumped) git -c commit.verbose=true commit --amend

To the best of my knowledge, this is the only case where we end up
writing a commit-graph in the same process that might have already
consulted the commit-graph to look up arbitrary objects. But regardless
of that, this feels like a bigger accident that is just waiting to
happen.

Make the code more robust by extending `repo_parse_commit_no_graph()` to
unparse a commit first in case we detect it's coming from a graph. This
ensures that we will re-read the object without it, and thus we will
populate `maybe_tree` properly.

This fix shouldn't have any performance consequences: the function is
only ever called in the "commit-graph.c" code, and we'll only re-parse
the commit at most once.

Add an exclusion to our Coccinelle rules so that it doesn't complain
about us accessing `maybe_tree` directly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agocommit: avoid parsing non-commits in `lookup_commit_reference_gently()`
Patrick Steinhardt [Mon, 16 Feb 2026 15:38:01 +0000 (16:38 +0100)] 
commit: avoid parsing non-commits in `lookup_commit_reference_gently()`

The function `lookup_commit_reference_gently()` can be used to look up a
committish by object ID. As such, the function knows to peel for example
tag objects so that we eventually end up with the commit.

The function is used quite a lot throughout our tree. One such user is
"shallow.c" via `assign_shallow_commits_to_refs()`. The intent of this
function is to figure out whether a shallow push is missing any objects
that are required to satisfy the ref updates, and if so, which of the
ref updates is missing objects.

This is done by painting the tree with `UNINTERESTING`. We start
painting by calling `refs_for_each_ref()` so that we can mark all
existing referenced objects as the boundary of objects that we already
have, and which are supposed to be fully connected. The reference tips
are then parsed via `lookup_commit_reference_gently()`, and the commit
is then marked as uninteresting.

But references may not necessarily point to a committish, and if a lot
of them aren't then this step takes a lot of time. This is mostly due to
the way that `lookup_commit_reference_gently()` is implemented: before
we learn about the type of the object we already call `parse_object()`
on the object ID. This has two consequences:

  - We parse all objects, including trees and blobs, even though we
    don't even need the contents of them.

  - More importantly though, `parse_object()` will cause us to check
    whether the object ID matches its contents.

Combined this means that we deflate and hash every non-committish
object, and that of course ends up being both CPU- and memory-intensive.

Improve the logic so that we first use `peel_object()`. This function
won't parse the object for us, and thus it allows us to learn about the
object's type before we parse and return it.

The following benchmark pushes a single object from a shallow clone into
a repository that has 100,000 refs. These refs were created by listing
all objects via `git rev-list(1) --objects --all` and creating refs for
a subset of them, so lots of those refs will cover non-commit objects.

  Benchmark 1: git-receive-pack (rev = HEAD~)
    Time (mean ± σ):     62.571 s ±  0.413 s    [User: 58.331 s, System: 4.053 s]
    Range (min … max):   62.191 s … 63.010 s    3 runs

  Benchmark 2: git-receive-pack (rev = HEAD)
    Time (mean ± σ):     38.339 s ±  0.192 s    [User: 36.220 s, System: 1.992 s]
    Range (min … max):   38.176 s … 38.551 s    3 runs

  Summary
    git-receive-pack . </tmp/input (rev = HEAD) ran
      1.63 ± 0.01 times faster than git-receive-pack . </tmp/input (rev = HEAD~)

This leads to a sizeable speedup as we now skip reading and parsing
non-commit objects. Before this change we spent around 40% of the time
in `assign_shallow_commits_to_refs()`, after the change we only spend
around 1.2% of the time in there. Almost the entire remainder of the
time is spent in git-rev-list(1) to perform the connectivity checks.

Despite the speedup though, this also leads to a massive reduction in
allocations. Before:

  HEAP SUMMARY:
      in use at exit: 352,480,441 bytes in 97,185 blocks
    total heap usage: 2,793,820 allocs, 2,696,635 frees, 67,271,456,983 bytes allocated

And after:

  HEAP SUMMARY:
      in use at exit: 17,524,978 bytes in 22,393 blocks
    total heap usage: 33,313 allocs, 10,920 frees, 407,774,251 bytes allocated

Note that when all references refer to commits performance stays roughly
the same, as expected. The following benchmark was executed with 600k
commits:

  Benchmark 1: git-receive-pack (rev = HEAD~)
    Time (mean ± σ):      9.101 s ±  0.006 s    [User: 8.800 s, System: 0.520 s]
    Range (min … max):    9.095 s …  9.106 s    3 runs

  Benchmark 2: git-receive-pack (rev = HEAD)
    Time (mean ± σ):      9.128 s ±  0.094 s    [User: 8.820 s, System: 0.522 s]
    Range (min … max):    9.019 s …  9.188 s    3 runs

  Summary
    git-receive-pack (rev = HEAD~) ran
      1.00 ± 0.01 times faster than git-receive-pack (rev = HEAD)

This will be improved in the next commit.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agot: use test_seq -f and pipes in a few more places
Aaron Plattner [Wed, 18 Feb 2026 18:10:19 +0000 (10:10 -0800)] 
t: use test_seq -f and pipes in a few more places

Several tests use a pattern that writes to a temporary file like this:

  printf "do something with %d\n" $(test_seq <count>) >tmpfile &&
  git do-something --stdin <tmpfile

Other tests use test_seq's -f parameter, but still write to a temporary file:

  test_seq -f "do something with %d" <count> >input &&
  git do-something --stdin <input

Simplify both of these patterns to

  test_seq -f "do something with %d" <count> |
  git do-something --stdin

Signed-off-by: Aaron Plattner <aplattner@nvidia.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agowt-status: use hash_algo from local repository instead of global the_hash_algo
Shreyansh Paliwal [Wed, 18 Feb 2026 17:53:42 +0000 (23:23 +0530)] 
wt-status: use hash_algo from local repository instead of global the_hash_algo

wt-status.c still uses the global the_hash_algo even though a repository
instance is already available via struct wt_status.

Replace uses of the_hash_algo with the hash algorithm stored in the
associated repository (s->repo->hash_algo or r->hash_algo).

This removes another dependency on global state and keeps wt-status
consistent with local repository usage.

Signed-off-by: Shreyansh Paliwal <shreyanshpaliwalcmsmn@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agowt-status: replace uses of the_repository with local repository instances
Shreyansh Paliwal [Wed, 18 Feb 2026 17:53:41 +0000 (23:23 +0530)] 
wt-status: replace uses of the_repository with local repository instances

wt-status.c uses the global the_repository in several places even when a
repository instance is already available via struct wt_status *s or struct
repository *r.

Replace these uses of the_repository with the repository available in the
local context (i.e. s->repo or r).

The replacements of all the_repository with s->repo are mostly to cases
where a repository instance is already available via struct wt_status *s
and struct repository *r, all functions operating on struct wt_status *s
are only used after s is initialized by wt_status_prepare(), which sets
s->repo from the repository provided by the caller. As a result, s->repo is
guaranteed to be available and consistent whenever these functions are
invoked.

This reduces reliance on global state and keeps wt-status consistent,
though many functions operating on struct wt_status *s are called via
commit.c and it still relies on the_repository, but within wt-status.c the
local repository pointer refers to the same underlying repository object.

Signed-off-by: Shreyansh Paliwal <shreyanshpaliwalcmsmn@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agowt-status: pass struct repository through function parameters
Shreyansh Paliwal [Wed, 18 Feb 2026 17:53:40 +0000 (23:23 +0530)] 
wt-status: pass struct repository through function parameters

Some functions in wt-status.c (count_stash_entries(),
read_line_from_git_path(), abbrev_oid_in_line(), and
read_rebase_todolist()) rely on the_repository as they do not have access
to a local repository instance.

Add a struct repository *r parameter to these functions and pass the local
repository instance through the callers, which already have access to it
either directly by struct repository *r or indirectly by struct wt_state
*s (s->repo).

Replace uses of the_repository in these functions with the passed parameter.

Signed-off-by: Shreyansh Paliwal <shreyanshpaliwalcmsmn@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoMerge branch 'pks-meson-fixes' of github.com:pks-gitlab/git-gui
Johannes Sixt [Wed, 18 Feb 2026 12:02:20 +0000 (13:02 +0100)] 
Merge branch 'pks-meson-fixes' of github.com:pks-gitlab/git-gui

* 'pks-meson-fixes' of github.com:pks-gitlab/git-gui:
  git-gui: wire up "git-gui--askyesno" with Meson
  git-gui: massage "git-gui--askyesno" with "generate-script.sh"
  git-gui: prefer shell at "/bin/sh" with Meson
  git-gui: fix use of GIT_CEILING_DIRECTORIES

Signed-off-by: Johannes Sixt <j6t@kdbg.org>
3 months agoformat-patch: fix From header in cover letter
Mirko Faina [Tue, 17 Feb 2026 23:25:18 +0000 (00:25 +0100)] 
format-patch: fix From header in cover letter

"git format-patch" takes "--from=<user ident>" command line option
and uses the given ident for patch e-mails, but this is not applied
to the cover letter, the option is ignored and the committer ident
of the current user is used. This has been the case ever since
"--from" was introduced in a9080475 (teach format-patch to place
other authors into in-body "From", 2013-07-03).

Teach the make_cover_letter() function to honor the option, instead of
always using the current committer identity. Change variable name from
"committer" to "from" to better reflect the purpose of the variable.

Signed-off-by: Mirko Faina <mroik@delayed.space>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoThe 5th batch
Junio C Hamano [Tue, 17 Feb 2026 21:29:49 +0000 (13:29 -0800)] 
The 5th batch

Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoMerge branch 'jc/doc-rerere-update'
Junio C Hamano [Tue, 17 Feb 2026 21:30:43 +0000 (13:30 -0800)] 
Merge branch 'jc/doc-rerere-update'

Doc update.

* jc/doc-rerere-update:
  rerere: minor documantation update

3 months agoMerge branch 'sd/t7003-test-path-is-helpers'
Junio C Hamano [Tue, 17 Feb 2026 21:30:43 +0000 (13:30 -0800)] 
Merge branch 'sd/t7003-test-path-is-helpers'

Test updates.

* sd/t7003-test-path-is-helpers:
  t7003: modernize path existence checks using test helpers

3 months agoMerge branch 'kh/doc-rerere-options-xref'
Junio C Hamano [Tue, 17 Feb 2026 21:30:43 +0000 (13:30 -0800)] 
Merge branch 'kh/doc-rerere-options-xref'

Doc update.

* kh/doc-rerere-options-xref:
  doc: rerere-options.adoc: link to git-rerere(1)

3 months agoMerge branch 'bk/t2003-modernise'
Junio C Hamano [Tue, 17 Feb 2026 21:30:42 +0000 (13:30 -0800)] 
Merge branch 'bk/t2003-modernise'

Test update.

* bk/t2003-modernise:
  t2003: modernize path existence checks using test helpers

3 months agoMerge branch 'rs/commit-commit-stack'
Junio C Hamano [Tue, 17 Feb 2026 21:30:42 +0000 (13:30 -0800)] 
Merge branch 'rs/commit-commit-stack'

Code clean-up to use the commit_stack API.

* rs/commit-commit-stack:
  commit: use commit_stack

3 months agoMerge branch 'rs/clean-includes'
Junio C Hamano [Tue, 17 Feb 2026 21:30:42 +0000 (13:30 -0800)] 
Merge branch 'rs/clean-includes'

Clean up redundant includes of header files.

* rs/clean-includes:
  remove duplicate includes

3 months agoMerge branch 'rs/xdiff-wo-the-repository'
Junio C Hamano [Tue, 17 Feb 2026 21:30:42 +0000 (13:30 -0800)] 
Merge branch 'rs/xdiff-wo-the-repository'

Reduce dependency on the_repository of xdiff-interface layer.

* rs/xdiff-wo-the-repository:
  xdiff-interface: stop using the_repository

3 months agoMerge branch 'rs/version-wo-the-repository'
Junio C Hamano [Tue, 17 Feb 2026 21:30:41 +0000 (13:30 -0800)] 
Merge branch 'rs/version-wo-the-repository'

Code clean-up.

* rs/version-wo-the-repository:
  version: stop using the_repository

3 months agoMerge branch 'yt/merge-file-outside-a-repository'
Junio C Hamano [Tue, 17 Feb 2026 21:30:41 +0000 (13:30 -0800)] 
Merge branch 'yt/merge-file-outside-a-repository'

"git merge-file" can be run outside a repository, but it ignored
all configuration, even the per-user ones.  The command now uses
available configuration files to find its customization.

* yt/merge-file-outside-a-repository:
  merge-file: honor merge.conflictStyle outside of a repository

3 months agoMerge branch 'ja/doc-synopsis-style-even-more'
Junio C Hamano [Tue, 17 Feb 2026 21:30:41 +0000 (13:30 -0800)] 
Merge branch 'ja/doc-synopsis-style-even-more'

A handful of documentation pages have been modernized to use the
"synopsis" style.

* ja/doc-synopsis-style-even-more:
  doc: convert git-show to synopsis style
  doc: fix some style issues in git-clone and for-each-ref-options
  doc: finalize git-clone documentation conversion to synopsis style
  doc: convert git-submodule to synopsis style

3 months agoMerge branch 'pc/lockfile-pid'
Junio C Hamano [Tue, 17 Feb 2026 21:30:41 +0000 (13:30 -0800)] 
Merge branch 'pc/lockfile-pid'

Allow recording process ID of the process that holds the lock next
to a lockfile for diagnosis.

* pc/lockfile-pid:
  lockfile: add PID file for debugging stale locks

3 months agoenvironment: stop storing `core.attributesFile` globally
Olamide Caleb Bello [Mon, 16 Feb 2026 16:38:25 +0000 (17:38 +0100)] 
environment: stop storing `core.attributesFile` globally

The `core.attributeFile` config value is parsed in
git_default_core_config(), loaded eagerly and stored in the global
variable `git_attributes_file`. Storing this value in a global
variable can lead to it being overwritten by another repository when
more than one Git repository run in the same Git process.

Create a new struct `repo_config_values` to hold this value and
other repository dependent values parsed by `git_default_config()`.
This will ensure the current behaviour remains the same while also
enabling the libification of Git.

An accessor function 'repo_config_values()' s created to ensure
that we do not access an uninitialized repository, or an instance
of a different repository than the current one.

Suggested-by: Phillip Wood <phillip.wood123@gmail.com>
Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Usman Akinyemi <usmanakinyemi202@gmail.com>
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Olamide Caleb Bello <belkid98@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agogitweb: let page header grow on mobile for long wrapped project names
Rito Rhymes [Mon, 16 Feb 2026 15:53:31 +0000 (15:53 +0000)] 
gitweb: let page header grow on mobile for long wrapped project names

On mobile, long project names in the page header can wrap to multiple lines,
but the fixed 25px header height does not grow with wrapped content.

Switch the header from fixed height to min-height so it expands as needed
while keeping the same baseline height for single-line titles.

Signed-off-by: Rito Rhymes <rito@ritovision.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agogitweb: fix mobile footer overflow by wrapping text and clearing floats
Rito Rhymes [Mon, 16 Feb 2026 15:53:30 +0000 (15:53 +0000)] 
gitweb: fix mobile footer overflow by wrapping text and clearing floats

On narrow screens, footer text can wrap, but the fixed 22px footer height
and floated footer blocks can cause overflow.

Switch to min-height and add a clearfix on the footer container so it grows
to contain wrapped float content cleanly.

Signed-off-by: Rito Rhymes <rito@ritovision.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agogitweb: fix mobile page overflow across log/commit/blob/diff views
Rito Rhymes [Mon, 16 Feb 2026 15:53:29 +0000 (15:53 +0000)] 
gitweb: fix mobile page overflow across log/commit/blob/diff views

On mobile-sized viewports, gitweb pages in log/commit/blob/diff views can
overflow horizontally due to desktop-oriented paddings and fixed-width
preformatted content.

Extend the existing mobile media query to rebalance those layouts: reduce
or clear paddings in log/commit sections, and allow horizontal scrolling
for preformatted blob/diff content instead of forcing page-wide overflow.

All layout adjustments in this patch are mobile-scoped, except one global
safeguard: set overflow-wrap:anywhere on div.log_body. Log content can
contain escaped or non-breaking text that behaves like a single long token
and can overflow at any viewport width, including desktop.

Signed-off-by: Rito Rhymes <rito@ritovision.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agogitweb: prevent project search bar from overflowing on mobile
Rito Rhymes [Mon, 16 Feb 2026 15:53:28 +0000 (15:53 +0000)] 
gitweb: prevent project search bar from overflowing on mobile

On narrow screens, the project search input can exceed the available width
and force page-wide horizontal scrolling.

Add a mobile media query and apply side padding to the search container,
then cap the input width to its container with border-box sizing so the
form stays within the viewport.

Signed-off-by: Rito Rhymes <rito@ritovision.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agogitweb: add viewport meta tag for mobile devices
Rito Rhymes [Mon, 16 Feb 2026 15:53:27 +0000 (15:53 +0000)] 
gitweb: add viewport meta tag for mobile devices

Without a viewport meta tag, phone browsers render gitweb at desktop
width and scale the whole page down to fit the screen.

Add a viewport meta tag so the layout viewport tracks device width.
This is the baseline needed for mobile CSS fixes in follow-up commits.

Signed-off-by: Rito Rhymes <rito@ritovision.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agofetch-pack: wire up and enable auto filter logic
Christian Couder [Mon, 16 Feb 2026 13:23:15 +0000 (14:23 +0100)] 
fetch-pack: wire up and enable auto filter logic

Previous commits have set up an infrastructure for `--filter=auto` to
automatically prepare a partial clone filter based on what the server
advertised and the client accepted.

Using that infrastructure, let's now enable the `--filter=auto` option
in `git clone` and `git fetch` by setting `allow_auto_filter` to 1.

Note that these small changes mean that when `git clone --filter=auto`
or `git fetch --filter=auto` are used, "auto" is automatically saved
as the partial clone filter for the server on the client. Therefore
subsequent calls to `git fetch` on the client will automatically use
this "auto" mode even without `--filter=auto`.

Let's also set `allow_auto_filter` to 1 in `transport.c`, as the
transport layer must be able to accept the "auto" filter spec even if
the invoking command hasn't fully parsed it yet.

When an "auto" filter is requested, let's have the "fetch-pack.c" code
in `do_fetch_pack_v2()` compute a filter and send it to the server.

In `do_fetch_pack_v2()` the logic also needs to check for the
"promisor-remote" capability and call `promisor_remote_reply()` to
parse advertised remotes and populate the list of those accepted (and
their filters).

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agopromisor-remote: change promisor_remote_reply()'s signature
Christian Couder [Mon, 16 Feb 2026 13:23:14 +0000 (14:23 +0100)] 
promisor-remote: change promisor_remote_reply()'s signature

The `promisor_remote_reply()` function performs two tasks:
1. It uses filter_promisor_remote() to parse the server's
   "promisor-remote" advertisement and to mark accepted remotes in the
   repository configuration.
2. It assembles a reply string containing the accepted remote names to
   send back to the server.

In a following commit, the fetch-pack logic will need to trigger the
side effect (1) to ensure the repository state is correct, but it will
not need to send a reply (2).

To avoid assembling a reply string when it is not needed, let's change
the signature of promisor_remote_reply(). It will now return `void` and
accept a second `char **accepted_out` argument. Only if that argument
is not NULL will a reply string be assembled and returned back to the
caller via that argument.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agopromisor-remote: keep advertised filters in memory
Christian Couder [Mon, 16 Feb 2026 13:23:13 +0000 (14:23 +0100)] 
promisor-remote: keep advertised filters in memory

Currently, advertised filters are only kept in memory temporarily
during parsing, or persisted to disk if `promisor.storeFields`
contains 'partialCloneFilter'.

In a following commit though, we will add a `--filter=auto` option.
This option will enable the client to use the filters that the server
is suggesting for the promisor remotes the client accepts.

To use them even if `promisor.storeFields` is not configured, these
filters should be stored somewhere for the current session.

Let's add an `advertised_filter` field to `struct promisor_remote`
for that purpose.

To ensure that the filters are available in all cases,
filter_promisor_remote() captures them into a temporary list and
applies them to the `promisor_remote` structs after the potential
configuration reload.

Then the accepted remotes are marked as `accepted` in the repository
state. This ensures that subsequent calls to look up accepted remotes
(like in the filter construction below) actually find them.

In a following commit, we will add a `--filter=auto` option that will
enable a client to use the filters suggested by the server for the
promisor remotes the client accepted.

To enable the client to construct a filter spec based on these filters,
let's also add a `promisor_remote_construct_filter(repo)` function.

This function:

- iterates over all accepted promisor remotes in the repository,
- collects the filters advertised for them (using `advertised_filter`
  added in this commit, and
- generates a single filter spec for them.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agolist-objects-filter-options: support 'auto' mode for --filter
Christian Couder [Mon, 16 Feb 2026 13:23:12 +0000 (14:23 +0100)] 
list-objects-filter-options: support 'auto' mode for --filter

In a following commit, we are going to allow passing "auto" as a
<filterspec> to the `--filter=<filterspec>` option, but only for some
commands. Other commands that support the `--filter=<filterspec>`
option should still die() when 'auto' is passed.

Let's set up the "list-objects-filter-options.{c,h}" infrastructure to
support that:

- Add a new `unsigned int allow_auto_filter : 1;` flag to
  `struct list_objects_filter_options` which specifies if "auto" is
  accepted or not by the current command.
- Change gently_parse_list_objects_filter() to parse "auto" if it's
  accepted.
- Make sure we die() if "auto" is combined with another filter.
- Update list_objects_filter_release() to preserve the
  allow_auto_filter flag, as this function is often called (via
  opt_parse_list_objects_filter) to reset the struct before parsing a
  new value.

Let's also update `list-objects-filter.c` to recognize the new
`LOFC_AUTO` choice. Since "auto" must be resolved to a concrete filter
before filtering actually begins, initializing a filter with
`LOFC_AUTO` is invalid and will trigger a BUG().

Note that ideally combining "auto" with "auto" could be allowed, but in
practice, it's probably not worth the added code complexity. And if we
really want it, nothing prevents us to allow it in future work.

If we ever want to give a meaning to combining "auto" with a different
filter too, nothing prevents us to do that in future work either.

Also note that the new `allow_auto_filter` flag depends on the command,
not user choices, so it should be reset to the command default when
`struct list_objects_filter_options` instances are reset.

While at it, let's add a new "u-list-objects-filter-options.c" file for
`struct list_objects_filter_options` related unit tests. For now it
only tests gently_parse_list_objects_filter() though.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agodoc: fetch: document `--filter=<filter-spec>` option
Christian Couder [Mon, 16 Feb 2026 13:23:11 +0000 (14:23 +0100)] 
doc: fetch: document `--filter=<filter-spec>` option

The `--filter=<filter-spec>` option is documented in most commands that
support it except `git fetch`.

Let's fix that and document this option. To ensure consistency across
commands, let's reuse the exact description currently found in
`git clone`.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agofetch: make filter_options local to cmd_fetch()
Christian Couder [Mon, 16 Feb 2026 13:23:10 +0000 (14:23 +0100)] 
fetch: make filter_options local to cmd_fetch()

The `struct list_objects_filter_options filter_options` variable used
in "builtin/fetch.c" to store the parsed filters specified by
`--filter=<filterspec>` is currently a static variable global to the
file.

As we are going to use it more in a following commit, it could become a
bit less easy to understand how it's managed.

To avoid that, let's make it clear that it's owned by cmd_fetch() by
moving its definition into that function and making it non-static.

This requires passing a pointer to it through the prepare_transport(),
do_fetch(), backfill_tags(), fetch_one_setup_partial(), and fetch_one()
functions, but it's quite straightforward.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoclone: make filter_options local to cmd_clone()
Christian Couder [Mon, 16 Feb 2026 13:23:09 +0000 (14:23 +0100)] 
clone: make filter_options local to cmd_clone()

The `struct list_objects_filter_options filter_options` variable used
in "builtin/clone.c" to store the parsed filters specified by
`--filter=<filterspec>` is currently a static variable global to the
file.

As we are going to use it more in a following commit, it could become
a bit less easy to understand how it's managed.

To avoid that, let's make it clear that it's owned by cmd_clone() by
moving its definition into that function and making it non-static.

The only additional change to make this work is to pass it as an
argument to checkout(). So it's a small quite cheap cleanup anyway.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agopromisor-remote: allow a client to store fields
Christian Couder [Mon, 16 Feb 2026 13:23:08 +0000 (14:23 +0100)] 
promisor-remote: allow a client to store fields

A previous commit allowed a server to pass additional fields through
the "promisor-remote" protocol capability after the "name" and "url"
fields, specifically the "partialCloneFilter" and "token" fields.

Another previous commit, c213820c51 (promisor-remote: allow a client
to check fields, 2025-09-08), has made it possible for a client to
decide if it accepts a promisor remote advertised by a server based
on these additional fields.

Often though, it would be interesting for the client to just store in
its configuration files these additional fields passed by the server,
so that it can use them when needed.

For example if a token is necessary to access a promisor remote, that
token could be updated frequently only on the server side and then
passed to all the clients through the "promisor-remote" capability,
avoiding the need to update it on all the clients manually.

Storing the token on the client side makes sure that the token is
available when the client needs to access the promisor remotes for a
lazy fetch.

To allow this, let's introduce a new "promisor.storeFields"
configuration variable.

Note that for a partial clone filter, it's less interesting to have
it stored on the client. This is because a filter should be used
right away and we already pass a `--filter=<filter-spec>` option to
`git clone` when starting a partial clone. Storing the filter could
perhaps still be interesting for information purposes.

Like "promisor.checkFields" and "promisor.sendFields", the new
configuration variable should contain a comma or space separated list
of field names. Only the "partialCloneFilter" and "token" field names
are supported for now.

When a server advertises a promisor remote, for example "foo", along
with for example "token=XXXXX" to a client, and on the client side
"promisor.storeFields" contains "token", then the client will store
XXXXX for the "remote.foo.token" variable in its configuration file
and reload its configuration so it can immediately use this new
configuration variable.

A message is emitted on stderr to warn users when the config is
changed.

Note that even if "promisor.acceptFromServer" is set to "all", a
promisor remote has to be already configured on the client side for
some of its config to be changed. In any case no new remote is
configured and no new URL is stored.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agopromisor-remote: refactor initialising field lists
Christian Couder [Mon, 16 Feb 2026 13:23:07 +0000 (14:23 +0100)] 
promisor-remote: refactor initialising field lists

In "promisor-remote.c", the fields_sent() and fields_checked()
functions serve similar purposes and contain a small amount of
duplicated code.

As we are going to add a similar function in a following commit,
let's refactor this common code into a new initialize_fields_list()
function.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoshallow: handling fetch relative-deepen
Samo Pogačnik [Sun, 15 Feb 2026 20:11:56 +0000 (20:11 +0000)] 
shallow: handling fetch relative-deepen

When a shallowed repository gets deepened beyond the beginning of a
merged branch, we may end up with some shallows that are hidden behind
the reachable shallow commits. Added test 'fetching deepen beyond
merged branch' exposes that behaviour.

An example showing the problem based on added test:
0. Whole initial git repo to be cloned from
   Graph:
   *   033585d (HEAD -> main) Merge branch 'branch'
   |\
   | * 984f8b1 (branch) five
   | * ecb578a four
   |/
   * 0cb5d20 three
   * 2b4e70d two
   * 61ba98b one

1. Initial shallow clone --depth=3 (all good)
   Shallows:
   2b4e70da2a10e1d3231a0ae2df396024735601f1
   ecb578a3cf37198d122ae5df7efed9abaca17144
   Graph:
   *   033585d (HEAD -> main) Merge branch 'branch'
   |\
   | * 984f8b1 five
   | * ecb578a (grafted) four
   * 0cb5d20 three
   * 2b4e70d (grafted) two

2. Deepen shallow clone with fetch --deepen=1 (NOT OK)
   Shallows:
   0cb5d204f4ef96ed241feb0f2088c9f4794ba758
   61ba98be443fd51c542eb66585a1f6d7e15fcdae
   Graph:
   *   033585d (HEAD -> main) Merge branch 'branch'
   |\
   | * 984f8b1 five
   | * ecb578a four
   |/
   * 0cb5d20 (grafted) three
   ---
   Note that second shallow commit 61ba98be443fd51c542eb66585a1f6d7e15fcdae
   is not reachable.

On the other hand, it seems that equivalent absolute depth driven
fetches result in all the correct shallows. That led to this proposal,
which unifies absolute and relative deepening in a way that the same
get_shallow_commits() call is used in both cases. The difference is
only that depth is adapted for relative deepening by measuring
equivalent depth of current local shallow commits in the current remote
repo. Thus a new function get_shallows_depth() has been added and the
function get_reachable_list() became redundant / removed.

Same example showing the corrected second step:
2. Deepen shallow clone with fetch --deepen=1 (all good)
   Shallow:
   61ba98be443fd51c542eb66585a1f6d7e15fcdae
   Graph:
   *   033585d (HEAD -> main) Merge branch 'branch'
   |\
   | * 984f8b1 five
   | * ecb578a four
   |/
   * 0cb5d20 three
   * 2b4e70d two
   * 61ba98b (grafted) one

The get_shallows_depth() function also shares the logic of the
get_shallow_commits() function, but it focuses on counting depth of
each existing shallow commit. The minimum result is stored as
'data->deepen_relative', which is set not to be zero for relative
deepening anyway. That way we can always sum 'data->deepen_relative'
and 'depth' values, because 'data->deepen_relative' is always 0 in
absolute deepening.
To avoid duplicating logic between get_shallows_depth() and
get_shallow_commits(), get_shallow_commits() was modified so that
it is used by get_shallows_depth().

Signed-off-by: Samo Pogačnik <samo_pogacnik@t-2.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoshallow: free local object_array allocations
Samo Pogačnik [Sun, 15 Feb 2026 20:11:55 +0000 (20:11 +0000)] 
shallow: free local object_array allocations

The local object_array 'stack' in get_shallow_commits() function
does not free its dynamic elements before the function returns.
As a result elements remain allocated and their reference forgotten.

Also note, that test 'fetching deepen beyond merged branch' added by
'shallow: handling fetch relative-deepen' patch fails without this
correction in linux-leaks and linux-reftable-leaks test runs.

Signed-off-by: Samo Pogačnik <samo_pogacnik@t-2.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agodoc: patch-id: see also git-cherry(1)
Kristoffer Haugsbakk [Sat, 14 Feb 2026 11:55:43 +0000 (12:55 +0100)] 
doc: patch-id: see also git-cherry(1)

git-cherry(1) links to this command. These two commands are similar and
we also mention it in the “Examples” section now. Let’s link to it.

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agodoc: patch-id: add script example
Kristoffer Haugsbakk [Sat, 14 Feb 2026 11:55:42 +0000 (12:55 +0100)] 
doc: patch-id: add script example

The utility and usability of git-patch-id(1) was discussed
relatively recently:[1]

    Using "git patch-id" is definitely in the "write a script for it"
    category. I don't think I've ever used it as-is from the command
    line as part of a one-liner. It's very much a command that is
    designed purely for scripting, the interface is just odd and baroque
    and doesn't really make sense for one-liners.

    The typical use of patch-id is to generate two *lists* of patch-ids,
    then sort them and use the patch-id as a key to find commits that
    look the same.

The command doc *could* use an example, and since it is a mapper command
it makes sense for that example to be a little script.

Mapping the commits of some branch to an upstream ref allows us to
demonstrate generating two lists, sorting them, joining them, and
finally discarding the patch ID lookup column with cut(1).

† 1: https://lore.kernel.org/workflows/CAHk-=wiN+8EUoik4UeAJ-HPSU7hczQP+8+_uP3vtAy_=YfJ9PQ@mail.gmail.com/

Inspired-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agodoc: patch-id: emphasize multi-patch processing
Kristoffer Haugsbakk [Sat, 14 Feb 2026 11:55:41 +0000 (12:55 +0100)] 
doc: patch-id: emphasize multi-patch processing

Emphasize that you can pass multiple patches or diffs to this command.

git-patch-id(1) is an efficient pID–commit mapper, able to map
thousands of commits in seconds. But discussions on the command
seem to typically[1] use the standard loop-over-rev-list-and-
shell-out pattern:

    for commit in rev-list:
        prepare a diff from commit | git patch-id

This is unnecessary; we can bulk-process the patches:

    git rev-list --no-merges <ref> |
         git diff-tree --patch --stdin |
         git patch-id --stable

The first version (translated to shell) takes a little over nine
minutes for a commit history of about 78K commits.[2] The other one,
by contrast, takes slightly less than a minute.

Also drop “the” from “standard input”.

† 1: https://stackoverflow.com/a/19758159
† 2: This is `master` of this repository on 2025-10-02

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoadd-patch: allow interfile navigation when selecting hunks
Abraham Samuel Adekunle [Sat, 14 Feb 2026 11:06:55 +0000 (12:06 +0100)] 
add-patch: allow interfile navigation when selecting hunks

After deciding on all hunks in a file, the interactive session
advances automatically to the next file if there is another,
or the process ends.

Now using the `--no-auto-advance` flag with `--patch`, the process
does not advance automatically. A user can choose to go to the next
file by pressing '>' or the previous file by pressing '<', before or
after deciding on all hunks in the current file.

After all hunks have been decided in a file, the user can still
rework with the file by applying the options available in the permit
set for that hunk, and after all the decisions, the user presses 'q'
to submit.
After all hunks have been decided, the user can press '?' which will
show the hunk selection summary in the help patch remainder text
including the total hunks, number of hunks marked for use and number
of hunks marked for skip.

This feature is enabled by passing the `--no-auto-advance` flag
to `--patch` option of the subcommands add, stash, reset,
and checkout.

Signed-off-by: Abraham Samuel Adekunle <abrahamadekunle50@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoadd-patch: allow all-or-none application of patches
Abraham Samuel Adekunle [Sat, 14 Feb 2026 11:06:06 +0000 (12:06 +0100)] 
add-patch: allow all-or-none application of patches

When the flag `--no-auto-advance` is used with `--patch`,
if the user has decided `USE` on a hunk in a file, goes to another
file, and then returns to this file and changes the previous
decision on the hunk to `SKIP`, because the patch has already
been applied, the last decision is not registered and the now
SKIPPED hunk is still applied.

Move the logic for applying patches into a function so that we can
reuse this logic to implement the all or non application of the patches
after the user is done with the hunk selection.

Signed-off-by: Abraham Samuel Adekunle <abrahamadekunle50@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoadd-patch: modify patch_update_file() signature
Abraham Samuel Adekunle [Sat, 14 Feb 2026 11:04:44 +0000 (12:04 +0100)] 
add-patch: modify patch_update_file() signature

The function `patch_update_file()` takes the add_p_state struct
pointer and the current `struct file_diff` pointer and returns an
int.

When using the `--no-auto-advance` flag, we want to be able to request
the next or previous file from the caller.

Modify the function signature to instead take the index of the
current `file_diff` and the `add_p_state` struct pointer so that we
can compute the `file_diff` from the index while also having
access to the file index. This will help us request the next or
previous file from the caller.

Signed-off-by: Abraham Samuel Adekunle <abrahamadekunle50@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agointeractive -p: add new `--auto-advance` flag
Abraham Samuel Adekunle [Sat, 14 Feb 2026 11:03:54 +0000 (12:03 +0100)] 
interactive -p: add new `--auto-advance` flag

When using the interactive add, reset, stash or checkout machinery,
we do not have the option of reworking with a file when selecting
hunks, because the session automatically advances to the next file
or ends if we have just one file.

Introduce the flag `--auto-advance` which auto advances by default,
when interactively selecting patches with the '--patch' option.
However, the `--no-auto-advance` option does not auto advance, thereby
allowing users the option to rework with files.

Signed-off-by: Abraham Samuel Adekunle <abrahamadekunle50@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoref-filter: avoid strrchr() in rstrip_ref_components()
Jeff King [Sun, 15 Feb 2026 09:07:44 +0000 (04:07 -0500)] 
ref-filter: avoid strrchr() in rstrip_ref_components()

To strip path components from our refname string, we repeatedly call
strrchr() to find the trailing slash, shortening the string each time by
assigning NUL over it. This has two downsides:

  1. Calling strrchr() in a loop is quadratic, since each call has to
     call strlen() under the hood to find the end of the string (even
     though we know exactly where it is from the last loop iteration).

  2. We need a temporary buffer, since we're munging the string with NUL
     as we shorten it (which we must do, because strrchr() has no other
     way of knowing what we consider the end of the string).

Using memrchr() would let us fix both of these, but it isn't portable.
So instead, let's just open-code the string traversal from back to
front as we loop.

I doubt that the quadratic nature is a serious concern. You can see it
in practice with something like:

  git init
  git commit --allow-empty -m foo
  echo "$(git rev-parse HEAD) refs/heads$(perl -e 'print "/a" x 500_000')" >.git/packed-refs
  time git for-each-ref --format='%(refname:rstrip=-1)'

That takes ~5.5s to run on my machine before this patch, and ~11ms
after. But I don't think there's a reasonable way for somebody to infect
you with such a garbage ref, as the wire protocol is limited to 64k
pkt-lines. The difference is measurable for me for a 32k-component ref
(about 19ms vs 7ms), so perhaps you could create some chaos by pushing a
lot of them. But we also run into filesystem limits (if the loose
backend is in use), and in practice it seems like there are probably
simpler and more effective ways to waste CPU.

Likewise the extra allocation probably isn't really measurable. In fact,
since our goal is to return an allocated string, we end up having to
make the same allocation anyway (though it is sized to the result,
rather than the input). My main goal was simplicity in avoiding the need
to handle cleaning it up in the early return path.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoref-filter: simplify rstrip_ref_components() memory handling
Jeff King [Sun, 15 Feb 2026 09:05:34 +0000 (04:05 -0500)] 
ref-filter: simplify rstrip_ref_components() memory handling

We're stripping path components from the end of a string, which we do by
assigning a NUL as we parse each component, shortening the string. This
requires an extra temporary buffer to avoid munging our input string.

But the way that we allocate the buffer is unusual. We have an extra
"to_free" variable. Usually this is used when the access variable is
conceptually const, like:

   const char *foo;
   char *to_free = NULL;

   if (...)
           foo = to_free = xstrdup(...);
   else
           foo = some_const_string;
   ...
   free(to_free);

But that's not what's happening here. Our "start" variable always points
to the allocated buffer, and to_free is redundant. Worse, it is marked
as const itself, requiring a cast when we free it.

Let's drop to_free entirely, and mark "start" as non-const, making the
memory handling more clear. As a bonus, this also silences a warning
from glibc-2.43 that our call to strrchr() implicitly strips away the
const-ness of "start".

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoref-filter: simplify lstrip_ref_components() memory handling
Jeff King [Sun, 15 Feb 2026 09:02:23 +0000 (04:02 -0500)] 
ref-filter: simplify lstrip_ref_components() memory handling

We're walking forward in the string, skipping path components from
left-to-right. So when we've stripped as much as we want, the pointer we
have is a complete NUL-terminated string and we can just return it
(after duplicating it, of course). So there is no need for a temporary
allocated string.

But we do make an extra temporary copy due to f0062d3b74 (ref-filter:
free item->value and item->value->s, 2018-10-18). This is probably from
cargo-culting the technique used in rstrip_ref_components(), which
_does_ need a separate string (since it is stripping from the end and
ties off the temporary string with a NUL).

Let's drop the extra allocation. This is slightly more efficient, but
more importantly makes the code much simpler.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoref-filter: factor out refname component counting
Jeff King [Sun, 15 Feb 2026 09:00:52 +0000 (04:00 -0500)] 
ref-filter: factor out refname component counting

The "lstrip" and "rstrip" options to the %(refname) placeholder both
accept a negative length, which asks us to keep that many path
components (rather than stripping that many).

The code to count components and convert the negative value to a
positive was copied from lstrip to rstrip in 1a34728e6b (ref-filter: add
an 'rstrip=<N>' option to atoms which deal with refnames, 2017-01-10).

Let's factor it out into a separate function. This reduces duplication
and also makes the lstrip/rstrip functions much easier to follow, since
the bulk of their code is now the actual stripping.

Note that the computed "remaining" value is currently stored as a
"long", so in theory that's what our function should return. But this is
purely historical. When the variable was added in 0571979bd6 (tag: do
not show ambiguous tag names as "tags/foo", 2016-01-25), we parsed the
value from strtol(), and thus used a long. But these days we take "len"
as an int, and also use an int to count up components. So let's just
consistently use int here. This value could only overflow in a
pathological case (e.g., 4GB worth of "a/a/...") and even then will not
result in out-of-bounds memory access (we keep stripping until we run
out of string to parse).

The minimal Myers diff here is a little hard to read; with --patience
the code movement is shown much more clearly.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agoDocumentation/git-history: document default for "--update-refs="
Patrick Steinhardt [Mon, 16 Feb 2026 06:45:48 +0000 (07:45 +0100)] 
Documentation/git-history: document default for "--update-refs="

While we document the values that can be passed to the "--update-refs="
option, we don't give the user any hint what the default behaviour is.
Document it.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agobuiltin/history: rename "--ref-action=" to "--update-refs="
Patrick Steinhardt [Mon, 16 Feb 2026 06:45:47 +0000 (07:45 +0100)] 
builtin/history: rename "--ref-action=" to "--update-refs="

With the preceding commit we have changed "--ref-action=" to only
control which refs are supposed to be updated, not what happens with
them. As a consequence, the option is now somewhat misnamed, as we don't
control the action itself anymore.

Rename it to "--update-refs=" to better align it with its new use.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agobuiltin/history: replace "--ref-action=print" with "--dry-run"
Patrick Steinhardt [Mon, 16 Feb 2026 06:45:46 +0000 (07:45 +0100)] 
builtin/history: replace "--ref-action=print" with "--dry-run"

The git-history(1) command has the ability to perform a dry-run
that will not end up modifying any references. Instead, we'll only print
any ref updates that would happen as a consequence of performing the
operation.

This mode is somewhat hidden though behind the "--ref-action=print"
option. This command line option has its origin in git-replay(1), where
it's probably an okayish interface as this command is sitting more on
the plumbing side of tools. But git-history(1) is a user-facing tool,
and this way of achieving a dry-run is way too technical and thus not
very discoverable.

Besides usability issues, it also has another issue: the dry-run mode
will always operate as if the user wanted to rewrite all branches. But
in fact, the user also has the option to only update the HEAD reference,
and they might want to perform a dry-run of such an operation, too. We
could of course introduce "--ref-action=print-head", but that would
become even less ergonomic.

Replace "--ref-action=print" with a new "--dry-run" toggle. This new
toggle works with both "--ref-action={head,branches}" and is way more
discoverable.

Add a test to verify that both "--ref-action=" values behave as
expected.

This patch is best viewed with "--ignore-space-change".

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 months agobuiltin/history: check for merges before asking for user input
Patrick Steinhardt [Mon, 16 Feb 2026 06:45:45 +0000 (07:45 +0100)] 
builtin/history: check for merges before asking for user input

The replay infrastructure is not yet capable of replaying merge commits.
Unfortunately, we only notice that we're about to replay merges after we
have already asked the user for input, so any commit message that the
user may have written will be discarded in that case.

Fix this by checking whether the revwalk contains merge commits before
we ask for user input.

Adapt one of the tests that is expected to fail because of this check
to use false(1) as editor. If the editor had been executed by Git, it
would fail with the error message "Aborting commit as launching the
editor failed."

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>