]> git.ipfire.org Git - thirdparty/git.git/log
thirdparty/git.git
5 months agoMerge branch 'qj/doc-my1stcontrib-email-verify'
Junio C Hamano [Tue, 4 Nov 2025 15:48:07 +0000 (07:48 -0800)] 
Merge branch 'qj/doc-my1stcontrib-email-verify'

The "MyFirstContribution" tutorial tells the reader how to send out
their patches; the section gained a hint to verify the message
reached the mailing list.

* qj/doc-my1stcontrib-email-verify:
  MyFirstContribution: add note on confirming patches

5 months agoMerge branch 'tz/test-prepare-gnupghome'
Junio C Hamano [Tue, 4 Nov 2025 15:48:07 +0000 (07:48 -0800)] 
Merge branch 'tz/test-prepare-gnupghome'

Tests did not set up GNUPGHOME correctly, which is fixed but some
flaky tests are exposed in t1016, which needs to be addressed
before this topic can move forward.

* tz/test-prepare-gnupghome:
  t/lib-gpg: call prepare_gnupghome() in GPG2 prereq
  t/lib-gpg: add prepare_gnupghome() to create GNUPGHOME dir

5 months agoMerge branch 'jt/repo-structure'
Junio C Hamano [Tue, 4 Nov 2025 15:48:06 +0000 (07:48 -0800)] 
Merge branch 'jt/repo-structure'

"git repo structure", a new command.

* jt/repo-structure:
  builtin/repo: add progress meter for structure stats
  builtin/repo: add keyvalue and nul format for structure stats
  builtin/repo: add object counts in structure output
  builtin/repo: introduce structure subcommand
  ref-filter: export ref_kind_from_refname()
  ref-filter: allow NULL filter pattern
  builtin/repo: rename repo_info() to cmd_repo_info()

5 months agoMerge branch 'tu/credential-install'
Junio C Hamano [Tue, 4 Nov 2025 15:48:06 +0000 (07:48 -0800)] 
Merge branch 'tu/credential-install'

Contributed credential helpers (obviously in contrib/) now have "cd
$there && make install" target.

* tu/credential-install:
  contrib/credential: add install target

5 months agoMerge branch 'cc/doc-submitting-patches-with-ai'
Junio C Hamano [Tue, 4 Nov 2025 15:48:06 +0000 (07:48 -0800)] 
Merge branch 'cc/doc-submitting-patches-with-ai'

AI guidelines.

* cc/doc-submitting-patches-with-ai:
  SubmittingPatches: add section about AI

5 months agoMerge branch 'kn/refs-optim-cleanup' into kn/maintenance-is-needed
Junio C Hamano [Tue, 4 Nov 2025 15:38:48 +0000 (07:38 -0800)] 
Merge branch 'kn/refs-optim-cleanup' into kn/maintenance-is-needed

* kn/refs-optim-cleanup:
  t/pack-refs-tests: move the 'test_done' to callees
  refs: rename 'pack_refs_opts' to 'refs_optimize_opts'
  refs: move to using the '.optimize' functions

5 months agoMerge branch 'ps/ref-peeled-tags' into kn/maintenance-is-needed
Junio C Hamano [Tue, 4 Nov 2025 15:38:12 +0000 (07:38 -0800)] 
Merge branch 'ps/ref-peeled-tags' into kn/maintenance-is-needed

* ps/ref-peeled-tags: (23 commits)
  t7004: do not chdir around in the main process
  ref-filter: fix stale parsed objects
  ref-filter: parse objects on demand
  ref-filter: detect broken tags when dereferencing them
  refs: don't store peeled object IDs for invalid tags
  object: add flag to `peel_object()` to verify object type
  refs: drop infrastructure to peel via iterators
  refs: drop `current_ref_iter` hack
  builtin/show-ref: convert to use `reference_get_peeled_oid()`
  ref-filter: propagate peeled object ID
  upload-pack: convert to use `reference_get_peeled_oid()`
  refs: expose peeled object ID via the iterator
  refs: refactor reference status flags
  refs: fully reset `struct ref_iterator::ref` on iteration
  refs: introduce `.ref` field for the base iterator
  refs: introduce wrapper struct for `each_ref_fn`
  builtin/repo: add progress meter for structure stats
  builtin/repo: add keyvalue and nul format for structure stats
  builtin/repo: add object counts in structure output
  builtin/repo: introduce structure subcommand
  ...

5 months agot/pack-refs-tests: move the 'test_done' to callees
Karthik Nayak [Mon, 20 Oct 2025 08:18:31 +0000 (10:18 +0200)] 
t/pack-refs-tests: move the 'test_done' to callees

In ac0bad0af4 (t0601: refactor tests to be shareable, 2025-09-19), we
refactored 't/t0601-reffiles-pack-refs.sh' to move all of the tests to
't/pack-refs-tests.sh', which became a common test suite which was also
used by 't/t1463-refs-optimize.sh'.

This also moved the 'test_done' directive to 't/pack-refs-tests.sh'.
Which inhibits additional tests from being added to either of the tests.
Let's move the directive out to both the tests, so that we can add
additional specific tests to them. Also the test flow logic shouldn't be
part of tests which can be embedded in other test scripts.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agorefs: rename 'pack_refs_opts' to 'refs_optimize_opts'
Karthik Nayak [Mon, 20 Oct 2025 08:18:30 +0000 (10:18 +0200)] 
refs: rename 'pack_refs_opts' to 'refs_optimize_opts'

The previous commit removed all references to 'pack_refs()' within
the refs subsystem. Continue this cleanup by also renaming
'pack_refs_opts' to 'refs_optimize_opts' and the respective flags
accordingly. Keeping the naming consistent will make the code easier to
maintain.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agorefs: move to using the '.optimize' functions
Karthik Nayak [Mon, 20 Oct 2025 08:18:29 +0000 (10:18 +0200)] 
refs: move to using the '.optimize' functions

The `struct ref_store` variable exposes two ways to optimize a reftable
backend:

  1. pack_refs
  2. optimize

The former was specific to the 'files' + 'packed' refs backend. The
latter is more generic and covers all backends. While the naming is
different, both of these functions perform the same functionality.

Consolidate this code to only maintain the 'optimize' functions. Do this
by modifying the backends so that they exclusively implement the
`optimize` callback, only. All users of the refs subsystem already use
the 'optimize' function so there is no changes needed on the callee
side. Finally, cleanup all references to the 'pack_refs' field of the
structure and code around it.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoMerge branch 'ps/ref-peeled-tags' into kn/refs-optim-cleanup
Junio C Hamano [Tue, 4 Nov 2025 15:33:41 +0000 (07:33 -0800)] 
Merge branch 'ps/ref-peeled-tags' into kn/refs-optim-cleanup

* ps/ref-peeled-tags: (92 commits)
  t7004: do not chdir around in the main process
  ref-filter: fix stale parsed objects
  ref-filter: parse objects on demand
  ref-filter: detect broken tags when dereferencing them
  refs: don't store peeled object IDs for invalid tags
  object: add flag to `peel_object()` to verify object type
  refs: drop infrastructure to peel via iterators
  refs: drop `current_ref_iter` hack
  builtin/show-ref: convert to use `reference_get_peeled_oid()`
  ref-filter: propagate peeled object ID
  upload-pack: convert to use `reference_get_peeled_oid()`
  refs: expose peeled object ID via the iterator
  refs: refactor reference status flags
  refs: fully reset `struct ref_iterator::ref` on iteration
  refs: introduce `.ref` field for the base iterator
  refs: introduce wrapper struct for `each_ref_fn`
  builtin/repo: add progress meter for structure stats
  builtin/repo: add keyvalue and nul format for structure stats
  builtin/repo: add object counts in structure output
  builtin/repo: introduce structure subcommand
  ...

5 months agot7004: do not chdir around in the main process
Junio C Hamano [Tue, 4 Nov 2025 15:28:59 +0000 (07:28 -0800)] 
t7004: do not chdir around in the main process

Move down to no-contains subdirectory inside a subshell, just like
the previous step that created and used it does.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoref-filter: fix stale parsed objects
Patrick Steinhardt [Tue, 4 Nov 2025 14:36:13 +0000 (15:36 +0100)] 
ref-filter: fix stale parsed objects

In 054f5f457e (ref-filter: parse objects on demand, 2025-10-23) we have
started to skip parsing some objects in case we don't need to access
their values in the first place. This was done by introducing a new
member `struct expand_data::maybe_object` that gets populated on demand
via `get_or_parse_object()`.

This has led to a regression though where the object now gets reused
because we don't reset it properly. The `oi` structure is declared in
global scope, and there is no single place where we reset it before
invoking `get_object()`. The consequence is that the `maybe_object`
member doesn't get reset across calls, so subsequent calls will end up
reusing the same object.

This is only an issue for a subset of retrieved values, as not all of
the infrastructure ends up calling `get_or_parse_object()`. So the
effect is limited, which is probably why the issue wasn't detected
earlier.

Fix the issue by resetting `maybe_object` in `get_object()`.

Reported-by: Junio C Hamano <gitster@pobox.com>
Based-on-patch-by: Jeff King <peff@peff.net>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoref-filter: parse objects on demand
Patrick Steinhardt [Thu, 23 Oct 2025 07:16:23 +0000 (09:16 +0200)] 
ref-filter: parse objects on demand

When formatting an arbitrary object we parse that object regardless of
whether or not we actually need any parsed data. In fact, many of the
atoms we have don't require any.

Refactor the code so that we parse the data on demand when we see an
atom that wants to access the objects. This leads to a small speedup,
for example in the Chromium repository with around 40000 refs:

    Benchmark 1: for-each-ref --format='%(raw)' (HEAD~)
      Time (mean ± σ):     388.7 ms ±   1.1 ms    [User: 322.2 ms, System: 65.0 ms]
      Range (min … max):   387.3 ms … 390.8 ms    10 runs

    Benchmark 2: for-each-ref --format='%(raw)' (HEAD)
      Time (mean ± σ):     344.7 ms ±   0.7 ms    [User: 287.8 ms, System: 55.1 ms]
      Range (min … max):   343.9 ms … 345.7 ms    10 runs

    Summary
      for-each-ref --format='%(raw)' (HEAD) ran
        1.13 ± 0.00 times faster than for-each-ref --format='%(raw)' (HEAD~)

With this change, we now spend ~90% of the time decompressing objects,
which is almost as good as it gets regarding git-for-each-ref(1)'s own
infrastructure.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoref-filter: detect broken tags when dereferencing them
Patrick Steinhardt [Thu, 23 Oct 2025 07:16:22 +0000 (09:16 +0200)] 
ref-filter: detect broken tags when dereferencing them

Users can ask git-for-each-ref(1) to peel tags and return information of
the tagged object by adding an asterisk to the format, like for example
"%(*$objectname)". If so, git-for-each-ref(1) peels that object to the
first non-tag object and then returns its values.

As mentioned in preceding commits, it can happen that the tagged object
type and the claimed object type differ, effectively resulting in a
corrupt tag. git-for-each-ref(1) would notice this mismatch, print an
error and then bail out when trying to peel the tag.

But we only notice this corruption in some very specific edge cases!
While we have a test in "t/for-each-ref-tests.sh" that verifies the
above scenario, this test is specifically crafted to detect the issue at
hand. Namely, we create two tags:

  - One tag points to a specific object with the correct type.

  - The other tag points to the *same* object with a different type.

The fact that both tags point to the same object is important here:
`peel_object()` wouldn't notice the corruption if the tagged objects
were different.

The root cause is that `peel_object()` calls `lookup_${type}()`
eventually, where the type is the same type declared in the tag object.
Consequently, when we have two tags pointing to the same object but with
different declared types we'll call two different lookup functions. The
first lookup will store the object with an unverified type A, whereas
the second lookup will try to look up the object with a different
unverified type B. And it is only now that we notice the discrepancy in
object types, even though type A could've already been the wrong type.

Fix the issue by verifying the object type in `populate_value()`. With
this change we'll also notice type mismatches when only dereferencing a
tag once.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agorefs: don't store peeled object IDs for invalid tags
Patrick Steinhardt [Thu, 23 Oct 2025 07:16:21 +0000 (09:16 +0200)] 
refs: don't store peeled object IDs for invalid tags

Both the "files" and "reftable" backend store peeled object IDs for
references that point to tags:

  - The "files" backend stores the value when packing refs, where each
    peeled object ID is prefixed with "^".

  - The "reftable" backend stores the value whenever writing a new
    reference that points to a tag via a special ref record type.

Both of these backends use `peel_object()` to find the peeled object ID.
But as explained in the preceding commit, that function does not detect
the case where the tag's tagged object and its claimed type mismatch.

The consequence of storing these bogus peeled object IDs is that we're
less likely to detect such corruption in other parts of Git.
git-for-each-ref(1) for example does not notice anymore that the tag is
broken when using "--format=%(*objectname)" to dereference tags.

One could claim that this is good, because it still allows us to mostly
use the tag as intended. But the biggest problem here is that we now
have different behaviour for such a broken tag depending on whether or
not we have its peeled value in the refdb.

Fix the issue by verifying the object type when peeling the object. If
that verification fails we simply skip storing the peeled value in
either of the reference formats.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoobject: add flag to `peel_object()` to verify object type
Patrick Steinhardt [Thu, 23 Oct 2025 07:16:20 +0000 (09:16 +0200)] 
object: add flag to `peel_object()` to verify object type

When peeling a tag to a non-tag object we repeatedly call
`parse_object()` on the tagged object until we find the first object
that isn't a tag. While this feels sensible at first, there is a big
catch here: `parse_object()` doesn't actually verify the type of the
tagged object.

The relevant code path here eventually ends up in `parse_tag_buffer()`.
Here, we parse the various fields of the tag, including the "type". Once
we've figured out the type and the tagged object ID, we call one of the
`lookup_${type}()` functions for whatever type we have found. There is
two possible outcomes in the successful case:

  1. The object is already part of our cached objects. In that case we
     double-check whether the type we're trying to look up matches the
     type that was cached.

  2. The object is _not_ part of our cached objects. In that case, we
     simply create a new object with the expected type, but we don't
     parse that object.

In the first case we might notice type mismatches, but only in the case
where our cache has the object with the correct type. In the second
case, we'll blindly assume that the type is correct and then go with it.
We'll only notice that the type might be wrong when we try to parse the
object at a later point.

Now arguably, we could change `parse_tag_buffer()` to verify the tagged
object's type for us. But that would have the effect that such a tag
cannot be parsed at all anymore, and we have a small bunch of tests for
exactly this case that assert we still can open such tags. So this
change does not feel like something we can retroactively tighten, even
though one shouldn't ever hit such corrupted tags.

Instead, add a new `flags` field to `peel_object()` that allows the
caller to opt in to strict object verification. This will be wired up at
a subset of callsites over the next few commits.

Note that this change also inlines `deref_tag_noverify()`. There's only
been two callsites of that function, the one we're changing and one in
our test helpers. The latter callsite can trivially use `deref_tag()`
instead, so by inlining the function we avoid having to pass down the
flag.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agorefs: drop infrastructure to peel via iterators
Patrick Steinhardt [Thu, 23 Oct 2025 07:16:19 +0000 (09:16 +0200)] 
refs: drop infrastructure to peel via iterators

Now that the peeled object ID gets propagated via the `struct reference`
there is no need anymore to call into the reference iterator itself to
dereference an object. Remove this infrastructure.

Most of the changes are straight-forward deletions of code. There is one
exception though in `refs/packed-backend.c::write_with_updates()`. Here
we stop peeling the iterator and instead just pass the peeled object ID
of that iterator directly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agorefs: drop `current_ref_iter` hack
Patrick Steinhardt [Thu, 23 Oct 2025 07:16:18 +0000 (09:16 +0200)] 
refs: drop `current_ref_iter` hack

In preceding commits we have refactored all callers of
`peel_iterated_oid()` to instead use `reference_get_peeled_oid()`. This
allows us to thus get rid of the former function.

Getting rid of that function is nice, but even nicer is that this also
allows us to get rid of the `current_ref_iter` hack. This global
variable tracked the currently-active ref iterator so that we can use it
to peel an object ID. Now that the peeled object ID is propagated via
`struct reference` though we don't have to depend on this hack anymore,
which makes for a more robust and easier-to-understand infrastructure.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agobuiltin/show-ref: convert to use `reference_get_peeled_oid()`
Patrick Steinhardt [Thu, 23 Oct 2025 07:16:17 +0000 (09:16 +0200)] 
builtin/show-ref: convert to use `reference_get_peeled_oid()`

The git-show-ref(1) command has multiple different modes:

  - It knows to show all references matching a pattern.

  - It knows to list all references that are an exact match to whatever
    the user has provided.

  - It knows to check for reference existence.

The first two commands use mostly the same infrastructure to print the
references via `show_one()`. But while the former mode uses a proper
iterator and thus has a `struct reference` available in its context, the
latter calls `refs_read_ref()` and thus doesn't. Consequently, we cannot
easily use `reference_get_peeled_oid()` to print the peeled value.

Adapt the code so that we manually construct a `struct reference` when
verifying refs. We wouldn't ever have the peeled value available anyway
as we're not using an iterator here, so we can simply plug in the values
we _do_ have.

With this change we now have a `struct reference` available at both
callsites of `show_one()` and can thus pass it, which allows us to use
`reference_get_peeled_oid()` instead of `peel_iterated_oid()`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoref-filter: propagate peeled object ID
Patrick Steinhardt [Thu, 23 Oct 2025 07:16:16 +0000 (09:16 +0200)] 
ref-filter: propagate peeled object ID

When queueing a reference in the "ref-filter" subsystem we end up
creating a new ref array item that contains the reference's info. One
bit of info that we always discard though is the peeled object ID, and
because of that we are forced to use `peel_iterated_oid()`.

Refactor the code to propagate the peeled object ID via the ref array,
if available. This allows us to manually peel tags without having to go
through the object database.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoupload-pack: convert to use `reference_get_peeled_oid()`
Patrick Steinhardt [Thu, 23 Oct 2025 07:16:15 +0000 (09:16 +0200)] 
upload-pack: convert to use `reference_get_peeled_oid()`

The `write_v0_ref()` callback is invoked from two callsites:

  - Once via `send_ref()` which is a callback passed to
    `for_each_namespaced_ref_1()` and `refs_head_ref_namespaced()`.

  - Once manually to announce capabilities.

When sending references to the client we also send the peeled value of
tags. As we don't have a `struct reference` available in the second
case, we cannot easily peel by calling `reference_get_peeled_oid()`, but
we instead have to depend on on global state via `peel_iterated_oid()`.

We do have a reference available though in the first case, it's only the
second case that keeps us from using `reference_get_peeled_oid()`. But
that second case only announces capabilities anyway, so we're not really
handling a reference at all here.

Adapt that case to construct a reference manually and pass that to
`write_v0_ref()`. Start to use `reference_get_peeled_oid()` now that we
always have a `struct reference` available.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agorefs: expose peeled object ID via the iterator
Patrick Steinhardt [Thu, 23 Oct 2025 07:16:14 +0000 (09:16 +0200)] 
refs: expose peeled object ID via the iterator

Both the "files" and "reftable" backend are able to store peeled values
for tags in the respective formats. This allows for a more efficient
lookup of the target object of such a tag without having to manually
peel via the object database.

The infrastructure to access these peeled object IDs is somewhat funky
though. When iterating through objects, we store a pointer reference to
the current iterator in a global variable. The callbacks invoked by that
iterator are then expected to call `peel_iterated_oid()`, which checks
whether the globally-stored iterator's current reference refers to the
one handed into that function. If so, we ask the iterator to peel the
object, otherwise we manually peel the object via the object database.
Depending on global state like this is somewhat weird and also quite
fragile.

Introduce a new `struct reference::peeled_oid` field that can be
populated by the reference backends. This field can be accessed via a
new function `reference_get_peeled_oid()` that either uses that value,
if set, or alternatively peels via the ODB. With this change we don't
have to rely on global state anymore, but make the peeled object ID
available to the callback functions directly.

Adjust trivial callers that already have a `struct reference` available.
Remaining callers will be adjusted in subsequent commits.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agorefs: refactor reference status flags
Patrick Steinhardt [Thu, 23 Oct 2025 07:16:13 +0000 (09:16 +0200)] 
refs: refactor reference status flags

The reference flags encode information like whether or not a reference
is a symbolic reference or whether it may be broken. This information is
stored in a `int flags` bitfield, which is in conflict with our modern
best practices; we tend to use an unsigned integer to store flags.

Change the type of the field to be `unsigned`. While at it, refactor the
individual flags to be part of an `enum` instead of using preprocessor
defines.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agorefs: fully reset `struct ref_iterator::ref` on iteration
Patrick Steinhardt [Thu, 23 Oct 2025 07:16:12 +0000 (09:16 +0200)] 
refs: fully reset `struct ref_iterator::ref` on iteration

With the introduction of the `struct ref_iterator::ref` field it now is
a whole lot easier to introduce new fields that become accessible to the
caller without having to adapt every single callsite. But there's a
downside: when a new field is introduced we always have to adapt all
backends to set that field.

This isn't something we can avoid in the general case: when the new
field is expected to be populated by all backends we of course cannot
avoid doing so. But new fields may be entirely optional, in which case
we'd still have such churn. And furthermore, it is very easy right now
to leak state from a previous iteration into the next iteration.

Address this issue by ensuring that the reference backends all fully
reset the field on every single iteration. This ensures that no state
from previous iterations can leak into the next one. And it ensures that
any newly introduced fields will be zeroed out by default.

Note that we don't have to explicitly adapt the "files" backend, as it
uses the `cache_ref_iterator` internally. Furthermore, other "wrapping"
iterators like for example the `prefix_ref_iterator` copy around the
whole reference, so these don't need to be adapted either.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agorefs: introduce `.ref` field for the base iterator
Patrick Steinhardt [Thu, 23 Oct 2025 07:16:11 +0000 (09:16 +0200)] 
refs: introduce `.ref` field for the base iterator

The base iterator has a couple of fields that tracks the name, target,
object ID and flags for the current reference. Due to this design we
have to create a new `struct reference` whenever we want to hand over
that reference to the callback function, which is tedious and not very
efficient.

Convert the structure to instead contain a `struct reference` as member.
This member is expected to be populated by the implementations of the
iterator and is handed over to the callback directly.

While at it, simplify `should_pack_ref()` to take a `struct reference`
directly instead of passing its respective fields.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agorefs: introduce wrapper struct for `each_ref_fn`
Patrick Steinhardt [Thu, 23 Oct 2025 07:16:10 +0000 (09:16 +0200)] 
refs: introduce wrapper struct for `each_ref_fn`

The `each_ref_fn` callback function type is used across our code base
for several different functions that iterate through reference. There's
a bunch of callbacks implementing this type, which makes any changes to
the callback signature extremely noisy. An example of the required churn
is e8207717f1 (refs: add referent to each_ref_fn, 2024-08-09): adding a
single argument required us to change 48 files.

It was already proposed back then [1] that we might want to introduce a
wrapper structure to alleviate the pain going forward. While this of
course requires the same kind of global refactoring as just introducing
a new parameter, it at least allows us to more change the callback type
afterwards by just extending the wrapper structure.

One counterargument to this refactoring is that it makes the structure
more opaque. While it is obvious which callsites need to be fixed up
when we change the function type, it's not obvious anymore once we use
a structure. That being said, we only have a handful of sites that
actually need to populate this wrapper structure: our ref backends,
"refs/iterator.c" as well as very few sites that invoke the iterator
callback functions directly.

Introduce this wrapper structure so that we can adapt the iterator
interfaces more readily.

[1]: <ZmarVcF5JjsZx0dl@tanuki>

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoobject-file: refactor writing objects via a stream
Patrick Steinhardt [Mon, 3 Nov 2025 07:42:08 +0000 (08:42 +0100)] 
object-file: refactor writing objects via a stream

We have two different ways to write an object into the database:

  - We either provide the full buffer and write the object all at once.

  - Or we provide an input stream that has a `read()` function so that
    we can chunk the object.

The latter is especially used for large objects, where it may be too
expensive to hold the complete object in memory all at once.

While we already have `odb_write_object()` at the ODB-layer, we don't
have an equivalent for streaming an object. Introduce a new function
`odb_write_object_stream()` to address this gap so that callers don't
have to be aware of the inner workings of how to stream an object to
disk with a specific object source.

Rename `stream_loose_object()` to `odb_source_loose_write_stream()` to
clarify its scope. This matches our modern best practices around how to
name functions.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoobject-file: rename `write_object_file()`
Patrick Steinhardt [Mon, 3 Nov 2025 07:42:07 +0000 (08:42 +0100)] 
object-file: rename `write_object_file()`

Rename `write_object_file()` to `odb_source_loose_write_object()` so
that it becomes clear that this is tied to a specific loose object
source. This matches our modern naming schema for functions.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoobject-file: refactor freshening of objects
Patrick Steinhardt [Mon, 3 Nov 2025 07:42:06 +0000 (08:42 +0100)] 
object-file: refactor freshening of objects

When writing an object that already exists in our object database we
skip the write and instead only update mtimes of the object, either in
its packed or loose object format. This logic is wholly contained in
"object-file.c", but that file is really only concerned with loose
objects. So it does not really make sense that it also contains the
logic to freshen a packed object.

Introduce a new `odb_freshen_object()` function that sits on the object
database level and two functions `packfile_store_freshen_object()` and
`odb_source_loose_freshen_object()`. Like this, the format-specific
functions can be part of their respective subsystems, while the backend
agnostic function to freshen an object sits at the object database
layer.

Note that this change also moves the logic that iterates through object
sources from the object source layer into the object database layer.
This change is intentional: object sources should ideally only have to
worry about themselves, and coordination of different sources should be
handled on the object database level.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoobject-file: rename `has_loose_object()`
Patrick Steinhardt [Mon, 3 Nov 2025 07:42:05 +0000 (08:42 +0100)] 
object-file: rename `has_loose_object()`

Rename `has_loose_object()` to `odb_source_loose_has_object()` so that
it becomes clear that this is tied to a specific loose object source.
This matches our modern naming schema for functions.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoobject-file: read objects via the loose object source
Patrick Steinhardt [Mon, 3 Nov 2025 07:42:04 +0000 (08:42 +0100)] 
object-file: read objects via the loose object source

When reading an object via `loose_object_info()` or `map_loose_object()`
we hand in the whole repository. We then iterate through each of the
object sources to figure out whether that source has the object in
question.

This logic is reversing responsibility though: a specific backend should
only care about one specific source, where the object sources themselves
are then managed by the object database.

Refactor the code accordingly by passing an object source to both of
these functions instead. The different sources are then handled by
either `do_oid_object_info_extended()`, which sits on the object
database level, and by `open_istream_loose()`. The latter function
arguably is still at the wrong level, but this will be cleaned up at a
later point in time.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoobject-file: move loose object map into loose source
Patrick Steinhardt [Mon, 3 Nov 2025 07:42:03 +0000 (08:42 +0100)] 
object-file: move loose object map into loose source

The loose object map is used to map from the repository's canonical
object hash to the compatibility hash. As the name indicates, this map
is only used for loose objects, and as such it is tied to a specific
loose object source.

Same as with preceding commits, move this map into the loose object
source accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoobject-file: hide internals when we need to reprepare loose sources
Patrick Steinhardt [Mon, 3 Nov 2025 07:42:02 +0000 (08:42 +0100)] 
object-file: hide internals when we need to reprepare loose sources

There are two different situations where we have to clear the cache of
loose objects:

  - When freeing the loose object source itself to avoid memory leaks.

  - When repreparing the loose object source so that any potentially-
    stale data is getting evicted from the cache.

The former is already handled by `odb_source_loose_free()`. But the
latter case is still done manually by in `odb_reprepare()`, so we are
leaking internals into that code.

Introduce a new `odb_source_loose_reprepare()` function as an equivalent
to `packfile_store_prepare()` to hide these implementation details.
Furthermore, while at it, rename the function `odb_clear_loose_cache()`
to `odb_source_loose_clear()`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoobject-file: move loose object cache into loose source
Patrick Steinhardt [Mon, 3 Nov 2025 07:42:01 +0000 (08:42 +0100)] 
object-file: move loose object cache into loose source

Our loose objects use a cache that (optionally) stores all objects for
each of the opened sharding directories. This cache is located in the
`struct odb_source`, but now that we have `struct odb_source_loose` it
makes sense to move it into the latter structure so that all state that
relates to loose objects is entirely self-contained.

Do so. While at it, rename corresponding functions to have a prefix that
relates to `struct odb_source_loose`.

Note that despite this prefix, the functions still accept a `struct
odb_source` as input. This is done intentionally: once we introduce
pluggable object databases, we will continue to accept this struct but
then do a cast inside these functions to `struct odb_source_loose`. This
design is similar to how we do it for our ref backends.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoobject-file: introduce `struct odb_source_loose`
Patrick Steinhardt [Mon, 3 Nov 2025 07:42:00 +0000 (08:42 +0100)] 
object-file: introduce `struct odb_source_loose`

Currently, all state that relates to loose objects is held directly by
the `struct odb_source`. Introduce a new `struct odb_source_loose` to
hold the state instead so that it is entirely self-contained.

This structure will eventually morph into the backend for accessing
loose objects. As such, this is part of the refactorings to introduce
pluggable object databases.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoobject-file: move `fetch_if_missing`
Patrick Steinhardt [Mon, 3 Nov 2025 07:41:59 +0000 (08:41 +0100)] 
object-file: move `fetch_if_missing`

The `fetch_if_missing` global variable is declared in "object-file.h"
but defined in "odb.c". The variable relates to the whole object
database instead of only loose objects, so move the declaration into
"odb.h" accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoodb: adjust naming to free object sources
Patrick Steinhardt [Mon, 3 Nov 2025 07:41:58 +0000 (08:41 +0100)] 
odb: adjust naming to free object sources

The functions `free_object_directory()` and `free_object_directories()`
are responsible for freeing a single object source or all object sources
connected to an object database, respectively. The associated structure
has been renamed from `struct object_directory` to `struct odb_source`
in a1e2581a1e (object-store: rename `object_directory` to `odb_source`,
2025-07-01) though, so the names are somewhat stale nowadays.

Rename them to mention the new struct name instead. Furthermore, while
at it, adapt them to our modern naming schema where we first have the
subject followed by a verb.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoodb: introduce `odb_source_new()`
Patrick Steinhardt [Mon, 3 Nov 2025 07:41:57 +0000 (08:41 +0100)] 
odb: introduce `odb_source_new()`

We have three different locations where we create a new ODB source.
Deduplicate the logic via a new `odb_source_new()` function.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoodb: fix subtle logic to check whether an alternate is usable
Patrick Steinhardt [Mon, 3 Nov 2025 07:41:56 +0000 (08:41 +0100)] 
odb: fix subtle logic to check whether an alternate is usable

When adding an alternate to the object database we first check whether
or not the path is usable. A path is usable if:

  - It actually exists.

  - We don't have it in our object sources yet.

While the former check is trivial enough, the latter part is somewhat
subtle and prone for bugs. This is because the function doesn't only
check whether or not the given path is usable. But if it _is_ usable, we
also store that path in the map of object sources immediately.

The tricky part here is that the path that gets stored in the map is
_not_ copied. Instead, we rely on the fact that subsequent code uses
`strbuf_detach()` to store the exact same allocated memory in the
created object source. Consequently, the memory is owned by the source
but _also_ stored in the map. This subtlety is easy to miss, so if one
decides to refactor this code one can easily end up breaking this
mechanism.

Make the relationship more explicit by not storing the path as part of
`alt_odb_usable()`. Instead, store the path after we have created the
source so that we can use the source's path pointer directly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agolast-modified: implement faster algorithm
Toon Claes [Thu, 23 Oct 2025 07:50:14 +0000 (09:50 +0200)] 
last-modified: implement faster algorithm

The current implementation of git-last-modified(1) works by doing a
revision walk, and inspecting the diff at each level of that walk to
annotate entries remaining in the hashmap of paths. In other words, if
the diff at some level touches a path which has not yet been associated
with a commit, then that commit becomes associated with the path.

While a perfectly reasonable implementation, it can perform poorly in
either one of two scenarios:

  1. There are many entries of interest, in which case there is simply
     a lot of work to do.

  2. Or, there are (even a few) entries which have not been updated in a
     long time, and so we must walk through a lot of history in order to
     find a commit that touches that path.

This patch rewrites the last-modified implementation that addresses the
second point. The idea behind the algorithm is to propagate a set of
'active' paths (a path is 'active' if it does not yet belong to a
commit) up to parents and do a truncated revision walk.

The walk is truncated because it does not produce a revision for every
change in the original pathspec, but rather only for active paths.

More specifically, consider a priority queue of commits sorted by
generation number. First, enqueue the set of boundary commits with all
paths in the original spec marked as interesting.

Then, while the queue is not empty, do the following:

  1. Pop an element, say, 'c', off of the queue, making sure that 'c'
     isn't reachable by anything in the '--not' set.

  2. For each parent 'p' (with index 'parent_i') of 'c', do the
     following:

     a. Compute the diff between 'c' and 'p'.
     b. Pass any active paths that are TREESAME from 'c' to 'p'.
     c. If 'p' has any active paths, push it onto the queue.

  3. Any path that remains active on 'c' is associated to that commit.

This ends up being equivalent to doing something like 'git log -1 --
$path' for each path simultaneously. But, it allows us to go much faster
than the original implementation by limiting the number of diffs we
compute, since we can avoid parts of history that would have been
considered by the revision walk in the original implementation, but are
known to be uninteresting to us because we have already marked all paths
in that area to be inactive.

To avoid computing many first-parent diffs, add another trick on top of
this and check if all paths active in 'c' are DEFINITELY NOT in c's
Bloom filter. Since the commit-graph only stores first-parent diffs in
the Bloom filters, we can only apply this trick to first-parent diffs.

Comparing the performance of this new algorithm shows about a 2.5x
improvement on git.git:

    Benchmark 1: master   no bloom
      Time (mean ± σ):      2.868 s ±  0.023 s    [User: 2.811 s, System: 0.051 s]
      Range (min … max):    2.847 s …  2.926 s    10 runs

    Benchmark 2: master with bloom
      Time (mean ± σ):     949.9 ms ±  15.2 ms    [User: 907.6 ms, System: 39.5 ms]
      Range (min … max):   933.3 ms … 971.2 ms    10 runs

    Benchmark 3: HEAD     no bloom
      Time (mean ± σ):     782.0 ms ±   6.3 ms    [User: 740.7 ms, System: 39.2 ms]
      Range (min … max):   776.4 ms … 798.2 ms    10 runs

    Benchmark 4: HEAD   with bloom
      Time (mean ± σ):     307.1 ms ±   1.7 ms    [User: 276.4 ms, System: 29.9 ms]
      Range (min … max):   303.7 ms … 309.5 ms    10 runs

    Summary
      HEAD   with bloom ran
        2.55 ± 0.02 times faster than HEAD     no bloom
        3.09 ± 0.05 times faster than master with bloom
        9.34 ± 0.09 times faster than master   no bloom

In short, the existing implementation is comparably fast *with* Bloom
filters as the new implementation is *without* Bloom filters. So, most
repositories should get a dramatic speed-up by just deploying this (even
without computing Bloom filters), and all repositories should get faster
still when computing Bloom filters.

When comparing a more extreme example of
`git last-modified -- COPYING t`, the difference is even 5 times better:

    Benchmark 1: master
      Time (mean ± σ):      4.372 s ±  0.057 s    [User: 4.286 s, System: 0.062 s]
      Range (min … max):    4.308 s …  4.509 s    10 runs

    Benchmark 2: HEAD
      Time (mean ± σ):     826.3 ms ±  22.3 ms    [User: 784.1 ms, System: 39.2 ms]
      Range (min … max):   810.6 ms … 881.2 ms    10 runs

    Summary
      HEAD ran
        5.29 ± 0.16 times faster than master

As an added benefit, results are more consistent now. For example
implementation in 'master' gives:

    $ git log --max-count=1 --format=%H -- pkt-line.h
    15df15fe07ef66b51302bb77e393f3c5502629de

    $ git last-modified -- pkt-line.h
    15df15fe07ef66b51302bb77e393f3c5502629de pkt-line.h

    $ git last-modified | grep pkt-line.h
    5b49c1af03e600c286f63d9d9c9fb01403230b9f pkt-line.h

With the changes in this patch the results of git-last-modified(1)
always match those of `git log --max-count=1`.

One thing to note though, the results might be outputted in a different
order than before. This is not considerd to be an issue because nowhere
is documented the order is guaranteed.

Based-on-patches-by: Derrick Stolee <stolee@gmail.com>
Based-on-patches-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Toon Claes <toon@iotcl.com>
Acked-by: Taylor Blau <me@ttaylorr.com>
[jc: tweaked use of xcalloc() to unbreak coccicheck]
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoGit 2.52-rc0 v2.52.0-rc0
Junio C Hamano [Mon, 3 Nov 2025 05:40:21 +0000 (21:40 -0800)] 
Git 2.52-rc0

Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoMerge branch 'rs/merge-base-optim'
Junio C Hamano [Mon, 3 Nov 2025 14:49:55 +0000 (06:49 -0800)] 
Merge branch 'rs/merge-base-optim'

The code to walk revision graph to compute merge base has been
optimized.

* rs/merge-base-optim:
  commit-reach: avoid commit_list_insert_by_date()

5 months agoMerge branch 'jk/diff-patch-dry-run-cleanup'
Junio C Hamano [Mon, 3 Nov 2025 14:49:55 +0000 (06:49 -0800)] 
Merge branch 'jk/diff-patch-dry-run-cleanup'

Finishing touches to fixes to the recent regression in "git diff -w
--quiet" and anything that needs to internally generate patch to
see if it turns empty.

* jk/diff-patch-dry-run-cleanup:
  diff: simplify run_external_diff() quiet logic
  diff: drop dry-run redirection to /dev/null
  diff: replace diff_options.dry_run flag with NULL file
  diff: drop save/restore of color_moved in dry-run mode
  diff: send external diff output to diff_options.file

5 months agoMerge branch 'ps/maintenance-geometric'
Junio C Hamano [Mon, 3 Nov 2025 14:49:55 +0000 (06:49 -0800)] 
Merge branch 'ps/maintenance-geometric'

"git maintenance" command learns the "geometric" strategy where it
avoids doing maintenance tasks that rebuilds everything from
scratch.

* ps/maintenance-geometric:
  t7900: fix a flaky test due to git-repack always regenerating MIDX
  builtin/maintenance: introduce "geometric" strategy
  builtin/maintenance: make "gc" strategy accessible
  builtin/maintenance: extend "maintenance.strategy" to manual maintenance
  builtin/maintenance: run maintenance tasks depending on type
  builtin/maintenance: improve readability of strategies
  builtin/maintenance: don't silently ignore invalid strategy
  builtin/maintenance: make the geometric factor configurable
  builtin/maintenance: introduce "geometric-repack" task
  builtin/gc: make `too_many_loose_objects()` reusable without GC config
  builtin/gc: remove global `repack` variable

5 months agoMerge branch 'jk/match-pathname-fix'
Junio C Hamano [Mon, 3 Nov 2025 14:49:54 +0000 (06:49 -0800)] 
Merge branch 'jk/match-pathname-fix'

The wildmatch code had a corner case bug that mistakenly makes
"foo**/bar" match with "foobar", which has been corrected.

* jk/match-pathname-fix:
  match_pathname(): give fnmatch one char of prefix context
  match_pathname(): reorder prefix-match check

5 months agoMerge branch 'kh/doc-patch-id-1'
Junio C Hamano [Mon, 3 Nov 2025 14:49:54 +0000 (06:49 -0800)] 
Merge branch 'kh/doc-patch-id-1'

* kh/doc-patch-id-1:
  doc: patch-id: convert to the modern synopsis style

5 months agoMerge branch 'rs/add-patch-quit'
Junio C Hamano [Mon, 3 Nov 2025 14:49:54 +0000 (06:49 -0800)] 
Merge branch 'rs/add-patch-quit'

The 'q'(uit) command in "git add -p" has been improved to quit
without doing any meaningless work before leaving, and giving EOF
(typically control-D) to the prompt is made to behave the same way.

* rs/add-patch-quit:
  add-patch: quit on EOF
  add-patch: quit without skipping undecided hunks

5 months agoThe 27th batch
Junio C Hamano [Thu, 30 Oct 2025 14:34:16 +0000 (07:34 -0700)] 
The 27th batch

Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoMerge branch 'rz/bisect-help-unknown'
Junio C Hamano [Thu, 30 Oct 2025 15:00:20 +0000 (08:00 -0700)] 
Merge branch 'rz/bisect-help-unknown'

"git bisect" command did not react correctly to "git bisect help"
and "git bisect unknown", which has been corrected.

* rz/bisect-help-unknown:
  bisect: fix handling of `help` and invalid subcommands

5 months agoMerge branch 'kf/log-shortlog-completion-fix'
Junio C Hamano [Thu, 30 Oct 2025 15:00:20 +0000 (08:00 -0700)] 
Merge branch 'kf/log-shortlog-completion-fix'

"git shortlog" knows "--committer" and "--author" options, which
the command line completion (in contrib/) did not handle well,
which has been corrected.

* kf/log-shortlog-completion-fix:
  completion: complete some 'git log' options

5 months agoMerge branch 'ly/diff-name-only-with-diff-from-content'
Junio C Hamano [Thu, 30 Oct 2025 15:00:19 +0000 (08:00 -0700)] 
Merge branch 'ly/diff-name-only-with-diff-from-content'

Regression fixes for a topic that has already been merged.

* ly/diff-name-only-with-diff-from-content:
  diff: stop output garbled message in dry run mode

5 months agoMerge branch 'ps/remove-packfile-store-get-packs'
Junio C Hamano [Thu, 30 Oct 2025 15:00:19 +0000 (08:00 -0700)] 
Merge branch 'ps/remove-packfile-store-get-packs'

Two slightly different ways to get at "all the packfiles" in API
has been cleaned up.

* ps/remove-packfile-store-get-packs:
  packfile: rename `packfile_store_get_all_packs()`
  packfile: introduce macro to iterate through packs
  packfile: drop `packfile_store_get_packs()`
  builtin/grep: simplify how we preload packs
  builtin/gc: convert to use `packfile_store_get_all_packs()`
  object-name: convert to use `packfile_store_get_all_packs()`

5 months agoMerge branch 'ob/gpg-interface-cleanup'
Junio C Hamano [Thu, 30 Oct 2025 15:00:19 +0000 (08:00 -0700)] 
Merge branch 'ob/gpg-interface-cleanup'

strbuf_split*() to split a string into multiple strbufs is often a
wrong API to use.  A few uses of it have been removed by
simplifying the code.

* ob/gpg-interface-cleanup:
  gpg-interface: do not use misdesigned strbuf_split*()
  gpg-interface: do not use misdesigned strbuf_split*()

5 months agoMerge branch 'ps/symlink-symref-deprecation'
Junio C Hamano [Thu, 30 Oct 2025 15:00:19 +0000 (08:00 -0700)] 
Merge branch 'ps/symlink-symref-deprecation'

"Symlink symref" has been added to the list of things that will
disappear at Git 3.0 boundary.

* ps/symlink-symref-deprecation:
  refs/files: deprecate writing symrefs as symbolic links

5 months agoMerge branch 'ey/commit-graph-changed-paths-config'
Junio C Hamano [Thu, 30 Oct 2025 15:00:18 +0000 (08:00 -0700)] 
Merge branch 'ey/commit-graph-changed-paths-config'

A new configuration variable commitGraph.changedPaths allows to
turn "--changed-paths" on by default for "git commit-graph".

* ey/commit-graph-changed-paths-config:
  commit-graph: add new config for changed-paths & recommend it in scalar

5 months agopackfile: track packs via the MRU list exclusively
Patrick Steinhardt [Thu, 30 Oct 2025 10:38:45 +0000 (11:38 +0100)] 
packfile: track packs via the MRU list exclusively

We track packfiles via two different lists:

  - `struct packfile_store::packs` is a list that sorts local packs
    first. In addition, these packs are sorted so that younger packs are
    sorted towards the front.

  - `struct packfile_store::mru` is a list that sorts packs so that
    most-recently used packs are at the front.

The reasoning behind the ordering in the `packs` list is that younger
objects stored in the local object store tend to be accessed more
frequently, and that is certainly true for some cases. But there are
going to be lots of cases where that isn't true. Especially when
traversing history it is likely that one needs to access many older
objects, and due to our housekeeping it is very likely that almost all
of those older objects will be contained in one large pack that is
oldest.

So whether or not the ordering makes sense really depends on the use
case at hand. A flexible approach like our MRU list addresses that need,
as it will sort packs towards the front that are accessed all the time.
Intuitively, this approach is thus able to satisfy more use cases more
efficiently.

This reasoning casts some doubt on whether or not it really makes sense
to track packs via two different lists. It causes confusion, and it is
not clear whether there are use cases where the `packs` list really is
such an obvious choice.

Merge these two lists into one most-recently-used list.

Note that there is one important edge case: `for_each_packed_object()`
uses the MRU list to iterate through packs, and then it lists each
object in those packs. This would have the effect that we now sort the
current pack towards the front, thus modifying the list of packfiles we
are iterating over, with the consequence that we'll see an infinite
loop. This edge case is worked around by introducing a new field that
allows us to skip updating the MRU.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agopackfile: always add packfiles to MRU when adding a pack
Patrick Steinhardt [Thu, 30 Oct 2025 10:38:44 +0000 (11:38 +0100)] 
packfile: always add packfiles to MRU when adding a pack

When preparing the packfile store we know to also prepare the MRU list
of packfiles with all packs that are currently loaded in the store via
`packfile_store_prepare_mru()`. So we know that the list of packs in the
MRU list should match the list of packs in the non-MRU list.

But there are some direct or indirect callsites that add a packfile to
the store via `packfile_store_add_pack()` without adding the pack to the
MRU. And while functions that access the MRU (e.g. `find_pack_entry()`)
know to call `packfile_store_prepare()`, which knows to prepare the MRU
via `packfile_store_prepare_mru()`, that operation will be turned into a
no-op because the packfile store is already prepared. So this will not
cause us to add the packfile to the MRU, and consequently we won't be
able to find the packfile in our MRU list.

There are only a handful of callers outside of "packfile.c" that add a
packfile to the store:

  - "builtin/fast-import.c" adds multiple packs of imported objects, but
    it knows to look up objects via `packfile_store_get_packs()`. This
    function does not use the MRU, so we're good.

  - "builtin/index-pack.c" adds the indexed pack to the store in case it
    needs to perform consistency checks on its objects.

  - "http.c" adds the fetched pack to the store so that we can access
    its objects.

In all of these cases we actually want to access the contained objects.
And luckily, reading these objects works as expected:

  1. We eventually end up in `do_oid_object_info_extended()`.

  2. Calling `find_pack_entry()` fails because the MRU list doesn't
     contain the newly added packfile.

  3. The callers don't pass `OBJECT_INFO_QUICK`, so we end up
     repreparing the object database. This will also cause us to
     reprepare the MRU list.

  4. We now retry reading the object via `find_pack_entry()`, and now we
     succeed because the MRU list got populated.

This logic feels quite fragile: we intentionally add the packfile to the
store, but we then ultimately rely on repreparing the entire store only
to make the packfile accessible. While we do the correct thing in
`do_oid_object_info_extended()`, other sites that access the MRU may not
know to reprepare.

But besides being fragile it's also a waste of resources: repreparing
the object database requires us to re-read the alternates file and
discard any caches.

Refactor the code so that we unconditionally add packfiles to the MRU
when adding them to a packfile store. This makes the logic less fragile
and ensures that we don't have to reprepare the store to make the pack
accessible.

Note that this does not allow us to drop `packfile_store_prepare_mru()`
just yet: while the MRU list is already populated with all packs now,
the order in which we add these packs is indeterministic for most of the
part. So by first calling `sort_pack()` on the other packfile list and
then re-preparing the MRU list we inherit its sorting.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agopackfile: move list of packs into the packfile store
Patrick Steinhardt [Thu, 30 Oct 2025 10:38:43 +0000 (11:38 +0100)] 
packfile: move list of packs into the packfile store

Move the list of packs into the packfile store. This follows the same
logic as in a previous commit, where we moved the most-recently-used
list of packs, as well.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agobuiltin/pack-objects: simplify logic to find kept or nonlocal objects
Patrick Steinhardt [Thu, 30 Oct 2025 10:38:42 +0000 (11:38 +0100)] 
builtin/pack-objects: simplify logic to find kept or nonlocal objects

The function `has_sha1_pack_kept_or_nonlocal()` takes an object ID and
then searches through packed objects to figure out whether the object
exists in a kept or non-local pack. As a performance optimization we
remember the packfile that contains a given object ID so that the next
call to the function first checks that same packfile again.

The way this is written is rather hard to follow though, as the caching
mechanism is intertwined with the loop that iterates through the packs.
Consequently, we need to do some gymnastics to re-start the iteration if
the cached pack does not contain the objects.

Refactor this so that we check the cached packfile at the beginning. We
don't have to re-verify whether the packfile meets the properties as we
have already verified those when storing the pack in `last_found` in the
first place. So all we need to do is to use `find_pack_entry_one()` to
check whether the pack contains the object ID, and to skip the cached
pack in the loop so that we don't search it twice.

Furthermore, stop using the `(void *)1` sentinel value and instead use a
simple `NULL` pointer to indicate that we don't have a last-found pack
yet.

This refactoring significantly simplifies the logic and makes it much
easier to follow.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agopackfile: fix approximation of object counts
Patrick Steinhardt [Thu, 30 Oct 2025 10:38:41 +0000 (11:38 +0100)] 
packfile: fix approximation of object counts

When approximating the number of objects in a repository we only take
into account two data sources, the multi-pack index and the packfile
indices, as both of these data structures allow us to easily figure out
how many objects they contain.

But the way we currently approximate the number of objects is broken in
presence of a multi-pack index. This is due to two separate reasons:

  - We have recently introduced initial infrastructure for incremental
    multi-pack indices. Starting with that series, `num_objects` only
    counts the number of objects of a specific layer of the MIDX chain,
    so we do not take into account objects from parent layers.

    This issue is fixed by adding `num_objects_in_base`, which contains
    the sum of all objects in previous layers.

  - When using the multi-pack index we may count objects contained in
    packfiles twice: once via the multi-pack index, but then we again
    count them via the packfile itself.

    This issue is fixed by skipping any packfiles that have an MIDX.

Overall, given that we _always_ count the packs, we can only end up
overestimating the number of objects, and the overestimation is limited
to a factor of two at most.

The consequences of those issues are very limited though, as we only
approximate object counts in a small number of cases:

  - When writing a commit-graph we use the approximate object count to
    display the upper limit of a progress display.

  - In `repo_find_unique_abbrev_r()` we use it to specify a lower limit
    of how many hex digits we want to abbreviate to. Given that we use
    power-of-two here to derive the lower limit we may end up with an
    abbreviated hash that is one digit longer than required.

  - In `estimate_repack_memory()` we may end up overestimating how much
    memory a repack needs to pack objects. Conseuqently, we may end up
    dropping some packfiles from a repack.

None of these are really game-changing. But it's nice to fix those
issues regardless.

While at it, convert the code to use `repo_for_each_pack()`.
Furthermore, use `odb_prepare_alternates()` instead of explicitly
preparing the packfile store. We really only want to prepare the object
database sources, and `get_multi_pack_index()` already knows to prepare
the packfile store for us.

Helped-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agohttp: refactor subsystem to use `packfile_list`s
Patrick Steinhardt [Thu, 30 Oct 2025 10:38:40 +0000 (11:38 +0100)] 
http: refactor subsystem to use `packfile_list`s

The dumb HTTP protocol directly fetches packfiles from the remote server
and temporarily stores them in a list of packfiles. Those packfiles are
not yet added to the repository's packfile store until we finalize the
whole fetch.

Refactor the code to instead use a `struct packfile_list` to store those
packs. This prepares us for a subsequent change where the `->next`
pointer of `struct packed_git` will go away.

Note that this refactoring creates some temporary duplication of code,
as we now have both `packfile_list_find_oid()` and `find_oid_pack()`.
The latter function will be removed in a subsequent commit though.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agopackfile: move the MRU list into the packfile store
Patrick Steinhardt [Thu, 30 Oct 2025 10:38:39 +0000 (11:38 +0100)] 
packfile: move the MRU list into the packfile store

Packfiles have two lists associated to them:

  - A list that keeps track of packfiles in the order that they were
    added to a packfile store.

  - A list that keeps track of packfiles in most-recently-used order so
    that packfiles that are more likely to contain a specific object are
    ordered towards the front.

Both of these lists are hosted by `struct packed_git` itself, So to
identify all packfiles in a repository you simply need to grab the first
packfile and then iterate the `->next` pointers or the MRU list. This
pattern has the problem that all packfiles are part of the same list,
regardless of whether or not they belong to the same object source.

With the upcoming pluggable object database effort this needs to change:
packfiles should be contained by a single object source, and reading an
object from any such packfile should use that source to look up the
object. Consequently, we need to break up the global lists of packfiles
into per-object-source lists.

A first step towards this goal is to move those lists out of `struct
packed_git` and into the packfile store. While the packfile store is
currently sitting on the `struct object_database` level, the intent is
to push it down one level into the `struct odb_source` in a subsequent
patch series.

Introduce a new `struct packfile_list` that is used to manage lists of
packfiles and use it to store the list of most-recently-used packfiles
in `struct packfile_store`. For now, the new list type is only used in a
single spot, but we'll expand its usage in subsequent patches.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agopackfile: use a `strmap` to store packs by name
Patrick Steinhardt [Thu, 30 Oct 2025 10:38:38 +0000 (11:38 +0100)] 
packfile: use a `strmap` to store packs by name

To allow fast lookups of a packfile by name we use a hashmap that has
the packfile name as key and the pack itself as value. But while this is
the perfect use case for a `strmap`, we instead use `struct hashmap` and
store the hashmap entry in the packfile itself.

Simplify the code by using a `strmap` instead.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agogpg-interface: mark a string for translation
Christian Couder [Thu, 30 Oct 2025 12:33:32 +0000 (13:33 +0100)] 
gpg-interface: mark a string for translation

Previous commits have marked a number of error or warning messages in
"builtin/fast-export.c" and "builtin/fast-import.c" for translation.

As "gpg-interface.c" code is used by the fast-export and fast-import
code, we should make sure that error or warning messages are also all
marked for translation in "gpg-interface.c".

To ensure that, let's mark for translation an error message in a
die() function.

With this, all the error and warning messages emitted by fast-export
and fast-import can be properly translated.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agofast-import: mark strings for translation
Christian Couder [Thu, 30 Oct 2025 12:33:31 +0000 (13:33 +0100)] 
fast-import: mark strings for translation

Some error or warning messages in "builtin/fast-import.c" are marked
for translation, but many are not.

To be more consistent and provide a better experience to people using a
translated version, let's mark all the remaining error or warning
messages for translation.

While at it, let's make the following small changes:

  - replace "GIT" or "git" in a few error messages to just "Git",
  - replace "Expected from command, got %s" to "expected 'from'
    command, got '%s'", which makes it clearer that "from" is a command
    and should not be translated,
  - downcase error and warning messages that start with an uppercase,
  - fix test cases in "t9300-fast-import.sh" that broke because an
    error or warning message was downcased,
  - split error and warning messages that are too long,
  - adjust the indentation of some arguments of the error functions.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agofast-export: mark strings for translation
Christian Couder [Thu, 30 Oct 2025 12:33:30 +0000 (13:33 +0100)] 
fast-export: mark strings for translation

Some error or warning messages in "builtin/fast-export.c" are marked
for translation, but many are not.

To be more consistent and provide a better experience to people using a
translated version, let's mark all the remaining error or warning
messages for translation.

While at it:

  - improve how some arguments to some error functions are indented,
  - remove "Error:" at the start of an error message,
  - downcase error and warning messages that start with an uppercase.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agogpg-interface: use left shift to define GPG_VERIFY_*
Christian Couder [Thu, 30 Oct 2025 12:33:29 +0000 (13:33 +0100)] 
gpg-interface: use left shift to define GPG_VERIFY_*

In "gpg-interface.h", the definitions of the GPG_VERIFY_* boolean flags
are currently using 1, 2 and 4 while we often prefer the bitwise left
shift operator, `<<`, for that purpose to make it clearer that they are
boolean.

Let's use the left shift operator here too. Let's also fix an indent
issue with "4" while at it.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agogpg-interface: simplify ssh fingerprint parsing
Christian Couder [Thu, 30 Oct 2025 12:33:28 +0000 (13:33 +0100)] 
gpg-interface: simplify ssh fingerprint parsing

In "gpg-interface.c", the 'parse_ssh_output()' function takes a
'struct signature_check *sigc' argument and populates many members of
this 'sigc' using information parsed from 'sigc->output' which
contains the ouput of an `ssh-keygen -Y ...` command that was used to
verify an SSH signature.

When it populates 'sigc->fingerprint' though, it uses
`xstrdup(strstr(line, "key ") + 4)` while `strstr(line, "key ")` has
already been computed a few lines above and is already available in
the `key` variable.

Let's simplify this.

Signed-off-by: Christian Couder <chriscool@tuxfamily.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoThe 26th batch
Junio C Hamano [Wed, 29 Oct 2025 19:40:39 +0000 (12:40 -0700)] 
The 26th batch

Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoMerge branch 'tb/incremental-midx-part-3.1'
Junio C Hamano [Wed, 29 Oct 2025 19:38:24 +0000 (12:38 -0700)] 
Merge branch 'tb/incremental-midx-part-3.1'

Clean-up "git repack" machinery to prepare for incremental update
of midx files.

* tb/incremental-midx-part-3.1: (49 commits)
  builtin/repack.c: clean up unused `#include`s
  repack: move `write_cruft_pack()` out of the builtin
  repack: move `write_filtered_pack()` out of the builtin
  repack: move `pack_kept_objects` to `struct pack_objects_args`
  repack: move `finish_pack_objects_cmd()` out of the builtin
  builtin/repack.c: pass `write_pack_opts` to `finish_pack_objects_cmd()`
  repack: extract `write_pack_opts_is_local()`
  repack: move `find_pack_prefix()` out of the builtin
  builtin/repack.c: use `write_pack_opts` within `write_cruft_pack()`
  builtin/repack.c: introduce `struct write_pack_opts`
  repack: 'write_midx_included_packs' API from the builtin
  builtin/repack.c: inline packs within `write_midx_included_packs()`
  builtin/repack.c: pass `repack_write_midx_opts` to `midx_included_packs`
  builtin/repack.c: inline `remove_redundant_bitmaps()`
  builtin/repack.c: reorder `remove_redundant_bitmaps()`
  repack: keep track of MIDX pack names using existing_packs
  builtin/repack.c: use a string_list for 'midx_pack_names'
  builtin/repack.c: extract opts struct for 'write_midx_included_packs()'
  builtin/repack.c: remove ref snapshotting from builtin
  repack: remove pack_geometry API from the builtin
  ...

5 months agotest-tool: fix leak in delete-gpgsig command
Jeff King [Wed, 29 Oct 2025 19:10:31 +0000 (15:10 -0400)] 
test-tool: fix leak in delete-gpgsig command

We read the input into a strbuf, so we must free it. Without this, t1016
complains in SANITIZE=leak mode.

The bug was introduced in 7673ecd2dc (t1016-compatObjectFormat: add
tests to verify the conversion between objects, 2023-10-01). But nobody
seems to have noticed, probably because CI did not run these tests until
the fix in 6cd8369ef3 (t/lib-gpg: call prepare_gnupghome() in GPG2
prereq, 2024-07-03).

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agodoc: document backslash in gitignore patterns
Jeff King [Wed, 29 Oct 2025 15:32:37 +0000 (11:32 -0400)] 
doc: document backslash in gitignore patterns

Because gitignore patterns are passed to fnmatch, the handling of
backslashes is the same as it is there: it can be used to escape
metacharacters. We do reference fnmatch(3) for more details, but it may
be friendlier to point out this implication explicitly (especially for
people who want to know about backslash handling and search the
documentation for that word). There are also two cases that I've seen
some other backslash-escaping systems handle differently, so let's
describe those:

  1. A backslash before any character treats that character literally,
     even if it's not otherwise a meta-character. As opposed to
     including the backslash itself (like "foo\bar" in shell expands to
     "foo\bar") or forbidding it ("foo\zar" is required to produce a
     diagnostic in C).

  2. A backslash at the end of the string is an invalid pattern (and not
     a literal backslash).

This second one in particular was a point of confusion between our
implementation and the one in JGit. Our wildmatch behavior matches what
POSIX specifies for fnmatch, so the code and documentation are in line.
But let's add a test to cover this case. Note that the behavior here
differs between wildmatch itself (which is what gitignore will use) and
pathspec matching (which will only turn to wildmatch if a literal match
fails). So we match "foo\" to "foo\" in pathspecs, but not via
gitignore.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agot1016-compatObjectFormat: really freeze time for reproduciblity
Eric W. Biederman [Tue, 28 Oct 2025 16:01:45 +0000 (11:01 -0500)] 
t1016-compatObjectFormat: really freeze time for reproduciblity

The strategy in t1016-compatObjectFormat is to build two trees with
identical commits, one tree encoded in sha1 the other tree encoded
in sha256 and to use the compatibility code to test and see if
the two trees are identical.

GPG signatures include the current time as part of the signature.

To make gpg deterministic I forced the use of gpg --faked-system-time.
Unfortunately I did not look closely enough.

By default gpg still allows time to move forward with --faked-system-time.
So in those rare instances when the system is heavily loaded and gpg runs
slower than other times, signatures over the exact same data differ
due to timestamps with a minuscule difference.

Reading through the gpg documentation with a close eye, time can be
frozen by including an exclamation point at the end of the argument to
--faked-system-time.

Add the exclamation point so gpg really runs with a fixed notion of time,
resulting in the exact same data having identical gpg signatures.

That is enough that I can run "t1016-compatObjectFormat.sh --stress"
and I don't see any failures.

It is possible a future change to gpg will make replay protection more
robust and not provide a way to allow two separate runs of gpg to
produce exactly the same signature for exactly the same data.  If that
happens a deeper comparison of the two repositories will need to be
performed.  A comparison that simply verifies the signatures and
compares the data for equality.  For now that is a lot of work
for no gain so I am just documenting the possibility.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agobisect: update usage and docs to match each other
Ruoyu Zhong [Tue, 28 Oct 2025 22:27:41 +0000 (22:27 +0000)] 
bisect: update usage and docs to match each other

Update the usage string of `git bisect` and documentation to match each
other. While at it, also:

1. Move the synopsis of `git bisect` subcommands to the synopsis
   section, so that the test `t0450-txt-doc-vs-help.sh` can pass.

2. Document the `git bisect next` subcommand, which exists in the code
   but is missing from the documentation.

See also: [1].

[1]: https://lore.kernel.org/git/3DA38465-7636-4EEF-B074-53E4628F5355@gmail.com/

Suggested-by: Ben Knoble <ben.knoble@gmail.com>
Signed-off-by: Ruoyu Zhong <zhongruoyu@outlook.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agodoc: git-checkout: fix placeholder markup
Kristoffer Haugsbakk [Tue, 28 Oct 2025 18:19:19 +0000 (19:19 +0100)] 
doc: git-checkout: fix placeholder markup

The placeholder markup is underscore (_), not backtick (`) as well.

The inline-verbatim markup (backticks) handle interior formatting. This
means in this case that it applies HTML `<code>` to the underscores and
`<em>` to the placeholder.

That is the effect, anyway; we can see from the rest of 042d6f34 (doc:
git-checkout: clarify `-b` and `-B`, 2025-09-10) that this was probably
an unintended mix-up.

Acked-by: Julia Evans <julia@jvns.ca>
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoThe 25th batch
Junio C Hamano [Tue, 28 Oct 2025 17:28:54 +0000 (10:28 -0700)] 
The 25th batch

Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoMerge branch 'ps/ci-rust'
Junio C Hamano [Tue, 28 Oct 2025 17:29:09 +0000 (10:29 -0700)] 
Merge branch 'ps/ci-rust'

CI improvements to handle the recent Rust integration better.

* ps/ci-rust:
  rust: support for Windows
  ci: verify minimum supported Rust version
  ci: check for common Rust mistakes via Clippy
  rust/varint: add safety comments
  ci: check formatting of our Rust code
  ci: deduplicate calls to `apt-get update`

5 months agoMerge branch 'cc/fast-import-strip-signed-tags'
Junio C Hamano [Tue, 28 Oct 2025 17:29:09 +0000 (10:29 -0700)] 
Merge branch 'cc/fast-import-strip-signed-tags'

"git fast-import" is taught to handle signed tags, just like it
recently learned to handle signed commits, in different ways.

* cc/fast-import-strip-signed-tags:
  fast-import: add '--signed-tags=<mode>' option
  fast-export: handle all kinds of tag signatures
  t9350: properly count annotated tags
  lib-gpg: allow tests with GPGSM or GPGSSH prereq first
  doc: git-tag: stop focusing on GPG signed tags

5 months agoMerge branch 'ds/sparse-checkout-clean'
Junio C Hamano [Tue, 28 Oct 2025 17:29:08 +0000 (10:29 -0700)] 
Merge branch 'ds/sparse-checkout-clean'

"git sparse-checkout" subcommand learned a new "clean" action to
prune otherwise unused working-tree files that are outside the
areas of interest.

* ds/sparse-checkout-clean:
  sparse-index: improve advice message instructions
  t: expand tests around sparse merges and clean
  sparse-index: point users to new 'clean' action
  sparse-checkout: add --verbose option to 'clean'
  dir: add generic "walk all files" helper
  sparse-checkout: match some 'clean' behavior
  sparse-checkout: add basics of 'clean' command
  sparse-checkout: remove use of the_repository

5 months agoMerge branch 'ps/remove-packfile-store-get-packs' into ps/packed-git-in-object-store
Junio C Hamano [Tue, 28 Oct 2025 17:00:56 +0000 (10:00 -0700)] 
Merge branch 'ps/remove-packfile-store-get-packs' into ps/packed-git-in-object-store

* ps/remove-packfile-store-get-packs: (55 commits)
  packfile: rename `packfile_store_get_all_packs()`
  packfile: introduce macro to iterate through packs
  packfile: drop `packfile_store_get_packs()`
  builtin/grep: simplify how we preload packs
  builtin/gc: convert to use `packfile_store_get_all_packs()`
  object-name: convert to use `packfile_store_get_all_packs()`
  builtin/repack.c: clean up unused `#include`s
  repack: move `write_cruft_pack()` out of the builtin
  repack: move `write_filtered_pack()` out of the builtin
  repack: move `pack_kept_objects` to `struct pack_objects_args`
  repack: move `finish_pack_objects_cmd()` out of the builtin
  builtin/repack.c: pass `write_pack_opts` to `finish_pack_objects_cmd()`
  repack: extract `write_pack_opts_is_local()`
  repack: move `find_pack_prefix()` out of the builtin
  builtin/repack.c: use `write_pack_opts` within `write_cruft_pack()`
  builtin/repack.c: introduce `struct write_pack_opts`
  repack: 'write_midx_included_packs' API from the builtin
  builtin/repack.c: inline packs within `write_midx_included_packs()`
  builtin/repack.c: pass `repack_write_midx_opts` to `midx_included_packs`
  builtin/repack.c: inline `remove_redundant_bitmaps()`
  ...

5 months agot7900: fix a flaky test due to git-repack always regenerating MIDX
Patrick Steinhardt [Mon, 27 Oct 2025 08:30:50 +0000 (09:30 +0100)] 
t7900: fix a flaky test due to git-repack always regenerating MIDX

When a supposedly no-op "git repack" runs across a second boundary,
because the command always touches the MIDX file and updates its
timestamp, "ls -l $GIT_DIR/objects/pack/" before and after the
operation can change, which causes such a test to fail.  Only
compare the *.pack files in the directory before and after the
operation to work around this flakyness.

Arguably, git-repack(1) should learn to not rewrite the MIDX in case
we know it is already up-to-date. But this is not a new problem
introduced via the new geometric maintenance task, so for now it
should be good enough to paper over the issue.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
[jc: taken from diff to v4 from v3 that was already merged to 'next']
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoMyFirstContribution: add note on confirming patches
Queen Ediri Jessa [Mon, 27 Oct 2025 11:16:00 +0000 (12:16 +0100)] 
MyFirstContribution: add note on confirming patches

Add a note after the `git send-email` section explaining how
contributors can confirm that their patches reached the mailing
list by checking https://lore.kernel.org/git/. This helps
contributors verify that their emails were successfully delivered.

Signed-off-by: Queen Ediri Jessa <qjessa662@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agorefs: add missing remove_on_disk implementation for debug backend
Xinyu Ruan [Fri, 24 Oct 2025 08:38:14 +0000 (08:38 +0000)] 
refs: add missing remove_on_disk implementation for debug backend

The debug ref backend (refs_be_debug) was missing the remove_on_disk
function pointer, which caused a segmentation fault when running
'GIT_TRACE_REFS=1 git refs migrate --ref-format=reftable' commands.

Signed-off-by: Xinyu Ruan <r200981113@gmail.com>
Acked-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoSync with Git 2.51.2
Junio C Hamano [Mon, 27 Oct 2025 03:05:40 +0000 (20:05 -0700)] 
Sync with Git 2.51.2

Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoGit 2.51.2 v2.51.2
Junio C Hamano [Mon, 27 Oct 2025 00:47:52 +0000 (17:47 -0700)] 
Git 2.51.2

Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agoMerge branch 'so/t2401-use-test-path-helpers' into maint-2.51
Junio C Hamano [Mon, 27 Oct 2025 02:48:21 +0000 (19:48 -0700)] 
Merge branch 'so/t2401-use-test-path-helpers' into maint-2.51

Test modernization.

* so/t2401-use-test-path-helpers:
  t2401: update path checks using test_path helpers

5 months agoMerge branch 'js/ci-github-actions-update' into maint-2.51
Junio C Hamano [Mon, 27 Oct 2025 02:48:20 +0000 (19:48 -0700)] 
Merge branch 'js/ci-github-actions-update' into maint-2.51

CI update.

* js/ci-github-actions-update:
  build(deps): bump actions/github-script from 7 to 8
  build(deps): bump actions/setup-python from 5 to 6
  build(deps): bump actions/checkout from 4 to 5
  build(deps): bump actions/download-artifact from 4 to 5

5 months agoMerge branch 'kh/doc-continued-paragraph-fix' into maint-2.51
Junio C Hamano [Mon, 27 Oct 2025 02:48:20 +0000 (19:48 -0700)] 
Merge branch 'kh/doc-continued-paragraph-fix' into maint-2.51

Doc mark-up fixes.

* kh/doc-continued-paragraph-fix:
  doc: fix accidental literal blocks

5 months agoMerge branch 'js/unreachable-workaround-for-no-symlink-head' into maint-2.51
Junio C Hamano [Mon, 27 Oct 2025 02:48:20 +0000 (19:48 -0700)] 
Merge branch 'js/unreachable-workaround-for-no-symlink-head' into maint-2.51

Code clean-up.

* js/unreachable-workaround-for-no-symlink-head:
  refs: forbid clang to complain about unreachable code

5 months agoMerge branch 'ps/t7528-ssh-agent-uds-workaround' into maint-2.51
Junio C Hamano [Mon, 27 Oct 2025 02:48:20 +0000 (19:48 -0700)] 
Merge branch 'ps/t7528-ssh-agent-uds-workaround' into maint-2.51

Recent OpenSSH creates the Unix domain socket to communicate with
ssh-agent under $HOME instead of /tmp, which causes our test to
fail doe to overly long pathname in our test environment, which has
been worked around by using "ssh-agent -T".

* ps/t7528-ssh-agent-uds-workaround:
  t7528: work around ETOOMANY in OpenSSH 10.1 and newer

5 months agoMerge branch 'tb/unicode-width-table-17' into maint-2.51
Junio C Hamano [Mon, 27 Oct 2025 02:48:19 +0000 (19:48 -0700)] 
Merge branch 'tb/unicode-width-table-17' into maint-2.51

Unicode width table update.

* tb/unicode-width-table-17:
  unicode: update the width tables to Unicode 17

5 months agoMerge branch 'jk/status-z-short-fix' into maint-2.51
Junio C Hamano [Mon, 27 Oct 2025 02:48:19 +0000 (19:48 -0700)] 
Merge branch 'jk/status-z-short-fix' into maint-2.51

The "--short" option of "git status" that meant output for humans
and "-z" option to show NUL delimited output format did not mix
well, and colored some but not all things.  The command has been
updated to color all elements consistently in such a case.

* jk/status-z-short-fix:
  status: make coloring of "-z --short" consistent

5 months agoMerge branch 'jk/diff-no-index-with-pathspec-fix' into maint-2.51
Junio C Hamano [Mon, 27 Oct 2025 02:48:19 +0000 (19:48 -0700)] 
Merge branch 'jk/diff-no-index-with-pathspec-fix' into maint-2.51

An earlier addition to "git diff --no-index A B" to limit the
output with pathspec after the two directories misbehaved when
these directories were given with a trailing slash, which has been
corrected.

* jk/diff-no-index-with-pathspec-fix:
  diff --no-index: fix logic for paths ending in '/'

5 months agoMerge branch 'ps/gitlab-ci-disable-windows-monitoring' into maint-2.51
Junio C Hamano [Mon, 27 Oct 2025 02:48:18 +0000 (19:48 -0700)] 
Merge branch 'ps/gitlab-ci-disable-windows-monitoring' into maint-2.51

Windows "real-time monitoring" interferes with the execution of
tests and affects negatively in both correctness and performance,
which has been disabled in Gitlab CI.

* ps/gitlab-ci-disable-windows-monitoring:
  gitlab-ci: disable realtime monitoring to unbreak Windows jobs

5 months agoMerge branch 'jc/diff-from-contents-fix' into maint-2.51
Junio C Hamano [Mon, 27 Oct 2025 02:48:18 +0000 (19:48 -0700)] 
Merge branch 'jc/diff-from-contents-fix' into maint-2.51

The code to squelch output from "git diff -w --name-status"
etc. for paths that "git diff -w -p" would have stayed silent
leaked output from dry-run patch generation, which has been
corrected.

* jc/diff-from-contents-fix:
  diff: make sure the other caller of diff_flush_patch_quietly() is silent

5 months agoMerge branch 'jk/diff-from-contents-fix' into maint-2.51
Junio C Hamano [Mon, 27 Oct 2025 02:48:18 +0000 (19:48 -0700)] 
Merge branch 'jk/diff-from-contents-fix' into maint-2.51

Recently we attempted to improve "git diff -w" and friends to
handle cases where patch output would be suppressed, but it
introduced a bug that emits unnecessary output, which has been
corrected.

* jk/diff-from-contents-fix:
  diff: restore redirection to /dev/null for diff_from_contents

5 months agoadd-patch: quit on EOF
René Scharfe [Sat, 25 Oct 2025 05:48:28 +0000 (07:48 +0200)] 
add-patch: quit on EOF

If we reach the end of the input, e.g. because the user pressed ctrl-D
on Linux, there is no point in showing any more prompts, as we won't get
any reply.  Do the same as option 'q' would: Quit.

Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agomatch_pathname(): give fnmatch one char of prefix context
Jeff King [Sun, 26 Oct 2025 15:42:22 +0000 (11:42 -0400)] 
match_pathname(): give fnmatch one char of prefix context

In match_pathname(), which we use for matching .gitignore and
.gitattribute patterns, we are comparing paths with fnmatch patterns
(actually our extended wildmatch, which will be important).  There's an
extra optimization there: we pre-compute the number of non-wildcard
characters at the beginning of the pattern and do an fspathncmp() on
that prefix.

That lets us avoid fnmatch entirely on patterns without wildcards, and
shrinks the amount of work we hand off to fnmatch. For a pattern like
"foo*.txt" and a path "foobar.txt", we'd cut away the matching "foo"
prefix and just pass "*.txt" and "bar.txt" to fnmatch().

But this misses a subtle corner case. In fnmatch(), we'll think
"bar.txt" is the start of the path, but it's not. This doesn't matter
for the pattern above, but consider the wildmatch pattern "foo**/bar"
and the path "foobar". These two should not match, because there is no
file named "bar", and the "**" applies only to the containing directory
name. But after removing the "foo" prefix, fnmatch will get "**/bar" and
"bar", which it does consider a match, because "**/" can match zero
directories.

We can solve this by giving fnmatch a bit more context. As long as it
has one byte of the matched prefix, then it will know that "bar" is not
the start of the path. In this example it would get "o**/bar" and
"obar", and realize that they cannot match.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
5 months agomatch_pathname(): reorder prefix-match check
Jeff King [Sun, 26 Oct 2025 15:41:46 +0000 (11:41 -0400)] 
match_pathname(): reorder prefix-match check

As an optimization, we use fspathncmp() to match a prefix of the pattern
that does not contain any wildcards, and then pass the remainder to
fnmatch(). If it has matched the whole thing, we can return early.

Let's shift this early-return check to before we tweak the pattern and
name strings. That will gives us more flexibility with that tweaking.

It might also save a few instructions, but I couldn't measure any
improvement in doing so (and I wouldn't be surprised if an optimizing
compiler could figure that out itself).

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>