]> git.ipfire.org Git - thirdparty/git.git/log
thirdparty/git.git
2 days ago.mailmap: fix and expand mappings for Jean-Noël Avila
Kristoffer Haugsbakk [Wed, 21 Jan 2026 21:51:09 +0000 (22:51 +0100)] 
.mailmap: fix and expand mappings for Jean-Noël Avila

The latest release candidate notes say that there is a new contributor:

    Jean-Noël Avila via GitGitGadget, ...

But this is a familiar face, just in a G.G. Gadget trench coat.

Also map the rest of the idents in the history.

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 days agoGit 2.53-rc1 v2.53.0-rc1
Junio C Hamano [Tue, 20 Jan 2026 23:22:31 +0000 (15:22 -0800)] 
Git 2.53-rc1

Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 days agoMerge branch 'js/prep-symlink-windows'
Junio C Hamano [Wed, 21 Jan 2026 16:29:00 +0000 (08:29 -0800)] 
Merge branch 'js/prep-symlink-windows'

Further preparation to upstream symbolic link support on Windows.

* js/prep-symlink-windows:
  trim_last_path_component(): avoid hard-coding the directory separator
  strbuf_readlink(): support link targets that exceed 2*PATH_MAX
  strbuf_readlink(): avoid calling `readlink()` twice in corner-cases
  init: do parse _all_ core.* settings early
  mingw: do resolve symlinks in `getcwd()`

3 days agoMerge branch 'ps/read-object-info-improvements'
Junio C Hamano [Wed, 21 Jan 2026 16:29:00 +0000 (08:29 -0800)] 
Merge branch 'ps/read-object-info-improvements'

The object-info API has been cleaned up.

* ps/read-object-info-improvements:
  packfile: drop repository parameter from `packed_object_info()`
  packfile: skip unpacking object header for disk size requests
  packfile: disentangle return value of `packed_object_info()`
  packfile: always populate pack-specific info when reading object info
  packfile: extend `is_delta` field to allow for "unknown" state
  packfile: always declare object info to be OI_PACKED
  object-file: always set OI_LOOSE when reading object info

3 days agoMerge branch 'ps/packfile-store-in-odb-source'
Junio C Hamano [Wed, 21 Jan 2026 16:28:58 +0000 (08:28 -0800)] 
Merge branch 'ps/packfile-store-in-odb-source'

The packfile_store data structure is moved from object store to odb
source.

* ps/packfile-store-in-odb-source:
  packfile: move MIDX into packfile store
  packfile: refactor `find_pack_entry()` to work on the packfile store
  packfile: inline `find_kept_pack_entry()`
  packfile: only prepare owning store in `packfile_store_prepare()`
  packfile: only prepare owning store in `packfile_store_get_packs()`
  packfile: move packfile store into object source
  packfile: refactor misleading code when unusing pack windows
  packfile: refactor kept-pack cache to work with packfile stores
  packfile: pass source to `prepare_pack()`
  packfile: create store via its owning source

3 days agoMerge branch 'kt/http-backend-errors'
Junio C Hamano [Wed, 21 Jan 2026 16:28:58 +0000 (08:28 -0800)] 
Merge branch 'kt/http-backend-errors'

Some error messages from the http transport layer lacked the
terminating newline, which has been corrected.

* kt/http-backend-errors:
  http-backend: write newlines to stderr when responding with errors

3 days agoMerge branch 'ps/t1410-cleanup'
Junio C Hamano [Wed, 21 Jan 2026 16:28:58 +0000 (08:28 -0800)] 
Merge branch 'ps/t1410-cleanup'

Test clean-up.

* ps/t1410-cleanup:
  t1410: use test helpers in reflog rewind test

3 days agoMerge branch 'ps/ref-consistency-checks'
Junio C Hamano [Wed, 21 Jan 2026 16:28:58 +0000 (08:28 -0800)] 
Merge branch 'ps/ref-consistency-checks'

Update code paths that check data integrity around refs subsystem.
cf. <CAOLa=ZShPP3BPXa=YnC-vuX4zF=pUTFdUidZwOdna8bfVTNM9w@mail.gmail.com>

* ps/ref-consistency-checks:
  builtin/fsck: drop `fsck_head_link()`
  builtin/fsck: move generic HEAD check into `refs_fsck()`
  builtin/fsck: move generic object ID checks into `refs_fsck()`
  refs/reftable: introduce generic checks for refs
  refs/reftable: fix consistency checks with worktrees
  refs/reftable: extract function to retrieve backend for worktree
  refs/reftable: adapt includes to become consistent
  refs/files: introduce function to perform normal ref checks
  refs/files: extract generic symref target checks
  fsck: drop unused fields from `struct fsck_ref_report`
  refs/files: perform consistency checks for root refs
  refs/files: improve error handling when verifying symrefs
  refs/files: extract function to check single ref
  refs/files: remove useless indirection
  refs/files: remove `refs_check_dir` parameter
  refs/files: move fsck functions into global scope
  refs/files: simplify iterating through root refs

3 days agoMerge branch 'tb/macos-iconv-workarounds'
Junio C Hamano [Wed, 21 Jan 2026 16:28:57 +0000 (08:28 -0800)] 
Merge branch 'tb/macos-iconv-workarounds'

The iconv library on macOS fails to correctly handle stateful
ISO/IEC 2022 encoded strings.  Work it around instead of replacing
it wholesale from homebrew.

* tb/macos-iconv-workarounds:
  utf8.c: enable workaround for iconv under macOS 14/15
  utf8.c: prepare workaround for iconv under macOS 14/15

3 days agoMerge branch 'cs/rebased-subtree-split'
Junio C Hamano [Wed, 21 Jan 2026 16:28:57 +0000 (08:28 -0800)] 
Merge branch 'cs/rebased-subtree-split'

The split command in "git subtree" (in contrib/) has been taught to
deal better with rebased history.

* cs/rebased-subtree-split:
  contrib/subtree: detect rewritten subtree commits

3 days agoMerge branch 'je/doc-reset'
Junio C Hamano [Wed, 21 Jan 2026 16:28:57 +0000 (08:28 -0800)] 
Merge branch 'je/doc-reset'

Documentation updates.

* je/doc-reset:
  doc: git-reset: clarify `git reset <pathspec>`
  doc: git-reset: clarify `git reset [mode]`
  doc: git-reset: clarify intro
  doc: git-reset: reorder the forms

3 days agoMerge branch 'en/fsck-snapshot-ref-state'
Junio C Hamano [Wed, 21 Jan 2026 16:28:57 +0000 (08:28 -0800)] 
Merge branch 'en/fsck-snapshot-ref-state'

"git fsck" used inconsistent set of refs to show a confused
warning, which has been corrected.

* en/fsck-snapshot-ref-state:
  fsck: snapshot default refs before object walk

8 days agoMerge a handful more topics after -rc0
Junio C Hamano [Fri, 16 Jan 2026 19:34:19 +0000 (11:34 -0800)] 
Merge a handful more topics after -rc0

Signed-off-by: Junio C Hamano <gitster@pobox.com>
8 days agoMerge branch 'ml/doc-blame-markup'
Junio C Hamano [Fri, 16 Jan 2026 20:40:28 +0000 (12:40 -0800)] 
Merge branch 'ml/doc-blame-markup'

Doc mark-up update.

* ml/doc-blame-markup:
  doc: git-blame: convert to new doc format
  doc: blame-options: convert to new doc format

8 days agoMerge branch 'kh/doc-patch-id'
Junio C Hamano [Fri, 16 Jan 2026 20:40:28 +0000 (12:40 -0800)] 
Merge branch 'kh/doc-patch-id'

"git patch-id" documentation updates.

* kh/doc-patch-id:
  doc: patch-id: --verbatim locks in --stable
  doc: patch-id: spell out the git-diff-tree(1) form
  doc: patch-id: use definite article for the result
  patch-id: use “patch ID” throughout
  doc: patch-id: capitalize Git version
  doc: patch-id: don’t use semicolon between bullet points

8 days agoMerge branch 'bc/doc-stash-import-export'
Junio C Hamano [Fri, 16 Jan 2026 20:40:27 +0000 (12:40 -0800)] 
Merge branch 'bc/doc-stash-import-export'

Update a FAQ entry on synching two separate repositories using the
"git stash export/import" recently introduced.

* bc/doc-stash-import-export:
  gitfaq: document using stash import/export to sync working tree

8 days agoMerge branch 'kj/t7101-modernize'
Junio C Hamano [Fri, 16 Jan 2026 20:40:27 +0000 (12:40 -0800)] 
Merge branch 'kj/t7101-modernize'

Test update.

* kj/t7101-modernize:
  t7101: modernize test path checks

8 days agoMerge branch 'ds/builtin-doc-update'
Junio C Hamano [Fri, 16 Jan 2026 20:40:27 +0000 (12:40 -0800)] 
Merge branch 'ds/builtin-doc-update'

Update in-code comment doc to match the current API.

* ds/builtin-doc-update:
  builtin.h: update documentation

8 days agoMerge branch 'ac/t1420-use-more-direct-check'
Junio C Hamano [Fri, 16 Jan 2026 20:40:27 +0000 (12:40 -0800)] 
Merge branch 'ac/t1420-use-more-direct-check'

Test update.

* ac/t1420-use-more-direct-check:
  t1420: modernize the lost-found test

8 days agoMerge branch 'jk/cat-file-avoid-bitmap-when-unneeded'
Junio C Hamano [Fri, 16 Jan 2026 20:40:26 +0000 (12:40 -0800)] 
Merge branch 'jk/cat-file-avoid-bitmap-when-unneeded'

Fix for a performance regression in "git cat-file".

* jk/cat-file-avoid-bitmap-when-unneeded:
  cat-file: only use bitmaps when filtering

8 days agoMerge branch 'jk/t-perf-fixes'
Junio C Hamano [Fri, 16 Jan 2026 20:40:26 +0000 (12:40 -0800)] 
Merge branch 'jk/t-perf-fixes'

Perf-test fixes.

* jk/t-perf-fixes:
  t/perf/run: preserve GIT_PERF_* from environment
  t/perf/perf-lib: fix assignment of TEST_OUTPUT_DIRECTORY

9 days agoRevert "Merge branch 'ar/run-command-hook'"
Junio C Hamano [Thu, 15 Jan 2026 19:12:53 +0000 (11:12 -0800)] 
Revert "Merge branch 'ar/run-command-hook'"

This reverts commit f406b8955295d01089ba2baf35eceadff2d11cae,
reversing changes made to 1627809eeff75e6ec936fc609e7be46d5eb2fa9e.

It seems to have caused a few regressions, two of the three known
ones we have proposed solutions for.  Let's give ourselves a bit
more room to maneuver during the pre-release freeze period and
restart once the 2.53 ships.

9 days agoGit 2.53-rc0 v2.53.0-rc0
Junio C Hamano [Thu, 15 Jan 2026 13:59:37 +0000 (05:59 -0800)] 
Git 2.53-rc0

Signed-off-by: Junio C Hamano <gitster@pobox.com>
9 days agoMerge branch 'ps/clar-integers'
Junio C Hamano [Thu, 15 Jan 2026 15:12:41 +0000 (07:12 -0800)] 
Merge branch 'ps/clar-integers'

Import newer version of "clar", unit testing framework.

* ps/clar-integers:
  gitattributes: disable blank-at-eof errors for clar test expectations
  t/unit-tests: demonstrate use of integer comparison assertions
  t/unit-tests: update clar to 39f11fe

9 days agoMerge branch 'kh/replay-invalid-onto-advance'
Junio C Hamano [Thu, 15 Jan 2026 15:12:41 +0000 (07:12 -0800)] 
Merge branch 'kh/replay-invalid-onto-advance'

Improve the error message when a bad argument is given to the
`--onto` option of "git replay".  Test coverage of "git replay" has
been improved.

* kh/replay-invalid-onto-advance:
  t3650: add more regression tests for failure conditions
  replay: die if we cannot parse object
  replay: improve code comment and die message
  replay: die descriptively when invalid commit-ish is given
  replay: find *onto only after testing for ref name
  replay: remove dead code and rearrange

9 days agoMerge branch 'ps/odb-misc-fixes'
Junio C Hamano [Thu, 15 Jan 2026 15:12:40 +0000 (07:12 -0800)] 
Merge branch 'ps/odb-misc-fixes'

Miscellaneous fixes on object database layer.

* ps/odb-misc-fixes:
  odb: properly close sources before freeing them
  builtin/gc: fix condition for whether to write commit graphs

9 days agoMerge branch 'pt/t7800-difftool-test-racefix'
Junio C Hamano [Thu, 15 Jan 2026 15:12:40 +0000 (07:12 -0800)] 
Merge branch 'pt/t7800-difftool-test-racefix'

Test fixup.

* pt/t7800-difftool-test-racefix:
  t7800: fix racy "difftool --dir-diff syncs worktree" test

12 days agoutf8.c: enable workaround for iconv under macOS 14/15
Torsten Bögershausen [Mon, 12 Jan 2026 16:25:53 +0000 (17:25 +0100)] 
utf8.c: enable workaround for iconv under macOS 14/15

The previous commit introduced a workaround in utf8.c to deal
with broken iconv implementations.

It is enabled when a MacOS version is used that has a buggy
iconv library and there is no external library provided
(and linked against) from neither MacPorts nor Homebrew nor Fink.
For Homebrew, MacPorts and Fink we check if libiconv exist.
Introduce 2 new macros: HAS_GOOD_LIBICONV and NEEDS_GOOD_LIBICONV.

For Homebrew HAS_GOOD_LIBICONV is set when the libiconv directory
exist.
MacPorts can be installed with or without libiconv, so check if
libiconv.dylib exists (which is a softlink)

Fink compiles and installs libiconv by default.
Note that a fresh installation of Fink now defaults to /opt/sw.
Older versions used /sw as default, so leave the check and setting
of BASIC_CFLAGS and BASIC_LDFLAGS as is.
For the new default check for the existance of /opt/sw as well.
Add a check for /opt/sw/lib/libiconv.dylib which sets HAS_GOOD_LIBICONV

Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agoutf8.c: prepare workaround for iconv under macOS 14/15
Torsten Bögershausen [Mon, 12 Jan 2026 16:25:51 +0000 (17:25 +0100)] 
utf8.c: prepare workaround for iconv under macOS 14/15

MacOS14 (Sonoma) has started to ship an iconv library with bugs.
The same bugs exists even in MacOS 15 (Sequoia)

A bug report running the Git test suite says:

three tests of t3900 fail on macOS 26.1 for me:

  not ok 17 - ISO-2022-JP should be shown in UTF-8 now
  not ok 25 - ISO-2022-JP should be shown in UTF-8 now
  not ok 38 - commit --fixup into ISO-2022-JP from UTF-8

Here's the verbose output of the first one:

=================
expecting success of 3900.17 'ISO-2022-JP should be shown in UTF-8 now':
                compare_with ISO-2022-JP "$TEST_DIRECTORY"/t3900/2-UTF-8.txt

 --- /Users/x/src/git/t/t3900/2-UTF-8.txt 2024-10-01 19:43:24.605230684 +0000
 +++ current     2025-12-08 21:52:45.786161909 +0000
@@ -1,5 +1,5 @@
 はれひほふ

 しているのが、いるので。
 -濱浜ほれぷりぽれまびぐりろへ。
 +濱浜ほれぷりぽれまび$0$j$m$X!#
not ok 17 - ISO-2022-JP should be shown in UTF-8 now
1..17
=================

compare_with runs git show to display a commit message, which in this
case here was encoded using ISO-2022-JP and is supposed to be reencoded
to UTF-8, but git show only does that half-way -- the "$0$j$m$X!#" part
is from the original ISO-2022-JP representation.

That botched conversion is done by utf8.c::reencode_string_iconv().  It
calls iconv(3) to do the actual work, initially with an output buffer of
the same size as the input.  If the output needs more space the function
enlarges the buffer and calls iconv(3) again.

iconv(3) won't tell us how much space it needs, but it will report what
part it already managed to convert, so we can increase the buffer and
continue from there.  ISO-2022-JP has escape codes for switching between
character sets, so it's a stateful encoding.  I guess the iconv(3) on my
machine forgets the state at the end of part one and then messes up part
two.

[end of citation]

Working around the buggy iconv shipped with the OS can be done in
two  ways:
a) Link Git against a different version of iconv
b) Improve the handling when iconv needs a larger output buffer

a) is already done by default when either Fink [1] or MacPorts [2]
   or Homebrew [3] is installed.
b) is implemented here, in case that no fixed iconv is available:
   When the output buffer is too short, increase it (as before)
   and start from scratch (this is new).

This workound needs to be enabled with
'#define ICONV_RESTART_RESET'
and a makefile knob will be added in the next commit

Suggested-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Torsten Bögershausen <tboegi@web.de>
[1] https://www.finkproject.org/
[2] https://www.macports.org/
[3] https://brew.sh/

Signed-off-by: Torsten Bögershausen <tboegi@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agobuiltin/fsck: drop `fsck_head_link()`
Patrick Steinhardt [Mon, 12 Jan 2026 09:03:06 +0000 (10:03 +0100)] 
builtin/fsck: drop `fsck_head_link()`

The function `fsck_head_link()` was historically used to perform a
couple of consistency checks for refs. (Almost) all of these checks have
now been moved into the refs subsystem. There's only a single check
remaining that verifies whether `refs_resolve_ref_unsafe()` returns a
`NULL` pointer. This may happen in a couple of cases:

  - When `refs_is_safe()` declares the ref to be unsafe. We already have
    checks for this as we verify refnames with `check_refname_format()`.

  - When the ref doesn't exist. A repository without "HEAD" is
    completely broken though, and we would notice this error ahead of
    time already.

  - In case the caller passes `RESOLVE_REF_READING` and the ref is a
    symref that doesn't resolve. We don't pass this flag though.

As such, this check doesn't cover anything anymore that isn't already
covered by `refs_fsck()`. Drop it, which also allows us to inline the
call to `refs_resolve_ref_unsafe()`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agobuiltin/fsck: move generic HEAD check into `refs_fsck()`
Patrick Steinhardt [Mon, 12 Jan 2026 09:03:05 +0000 (10:03 +0100)] 
builtin/fsck: move generic HEAD check into `refs_fsck()`

Move the check that detects "HEAD" refs that do not point at a branch
into `refs_fsck()`. This follows the same motivation as the preceding
commit.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agobuiltin/fsck: move generic object ID checks into `refs_fsck()`
Patrick Steinhardt [Mon, 12 Jan 2026 09:03:04 +0000 (10:03 +0100)] 
builtin/fsck: move generic object ID checks into `refs_fsck()`

While most of the logic that verifies the consistency of refs is
driven by `refs_fsck()`, we still have a small handful of checks in
`fsck_head_link()`. These checks don't use the git-fsck(1) reporting
infrastructure, and as such it's impossible to for example disable
some of those checks.

One such check detects refs that point to the all-zeroes object ID.
Extract this check into the generic `refs_fsck_ref()` function that is
used by both the "files" and "reftable" backends.

Note that this will cause us to not return an error code from
`fsck_head_link()` anymore in case this error was detected. This is fine
though: the only caller of this function does not check the error code
anyway. To demonstrate this, adapt the function to drop its return value
altogether. The function will be removed in a subsequent commit anyway.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agorefs/reftable: introduce generic checks for refs
Patrick Steinhardt [Mon, 12 Jan 2026 09:03:03 +0000 (10:03 +0100)] 
refs/reftable: introduce generic checks for refs

In a preceding commit we have extracted generic checks for both direct
and symbolic refs that apply for all backends. Wire up those checks for
the "reftable" backend.

Note that this is done by iterating through all refs manually with the
low-level reftable ref iterator. We explicitly don't want to use the
higher-level iterator that is exposed to users of the reftable backend
as that iterator may swallow for example broken refs.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agorefs/reftable: fix consistency checks with worktrees
Patrick Steinhardt [Mon, 12 Jan 2026 09:03:02 +0000 (10:03 +0100)] 
refs/reftable: fix consistency checks with worktrees

The ref consistency checks are driven via `cmd_refs_verify()`. That
function loops through all worktrees (including the main worktree) and
then checks the ref store for each of them individually. It follows that
the backend is expected to only verify refs that belong to the specified
worktree.

While the "files" backend handles this correctly, the "reftable" backend
doesn't. In fact, it completely ignores the passed worktree and instead
verifies refs of _all_ worktrees. The consequence is that we'll end up
every ref store N times, where N is the number of worktrees.

Or rather, that would be the case if we actually iterated through the
worktree reftable stacks correctly. But we use `strmap_for_each_entry()`
to iterate through the stacks, but the map is in fact not even properly
populated. So instead of checking stacks N^2 times, we actually only end
up checking the reftable stack of the main worktree.

Fix this bug by only verifying the stack of the passed-in worktree and
constructing the backends via `backend_for_worktree()`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agorefs/reftable: extract function to retrieve backend for worktree
Patrick Steinhardt [Mon, 12 Jan 2026 09:03:01 +0000 (10:03 +0100)] 
refs/reftable: extract function to retrieve backend for worktree

Pull out the logic to retrieve a backend for a given worktree. This
function will be used in a subsequent commit.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agorefs/reftable: adapt includes to become consistent
Patrick Steinhardt [Mon, 12 Jan 2026 09:03:00 +0000 (10:03 +0100)] 
refs/reftable: adapt includes to become consistent

Adapt the includes to be sorted and to use include paths that are
relative to the "refs/" directory.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agorefs/files: introduce function to perform normal ref checks
Patrick Steinhardt [Mon, 12 Jan 2026 09:02:59 +0000 (10:02 +0100)] 
refs/files: introduce function to perform normal ref checks

In a subsequent commit we'll introduce new generic checks for direct
refs. These checks will be independent of the actual backend.

Introduce a new function `refs_fsck_ref()` that will be used for this
purpose. At the current point in time it's still empty, but it will get
populated in a subsequent commit.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agorefs/files: extract generic symref target checks
Patrick Steinhardt [Mon, 12 Jan 2026 09:02:58 +0000 (10:02 +0100)] 
refs/files: extract generic symref target checks

The consistency checks for the "files" backend contain a couple of
verifications for symrefs that verify generic properties of the target
reference. These properties need to hold for every backend, no matter
whether it's using the "files" or "reftable" backend.

Reimplementing these checks for every single backend doesn't really make
sense. Extract it into a generic `refs_fsck_symref()` function that can
be used by other backends, as well. The "reftable" backend will be wired
up in a subsequent commit.

While at it, improve the consistency checks so that we don't complain
about refs pointing to a non-ref target in case the target refname
format does not verify. Otherwise it's very likely that we'll generate
both error messages, which feels somewhat redundant in this case.

Note that the function has a couple of `UNUSED` parameters. These will
become referenced in a subsequent commit.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agofsck: drop unused fields from `struct fsck_ref_report`
Patrick Steinhardt [Mon, 12 Jan 2026 09:02:57 +0000 (10:02 +0100)] 
fsck: drop unused fields from `struct fsck_ref_report`

The `struct fsck_ref_report` has a couple fields that are intended to
improve the error reporting for broken ref reports by showing which
object ID or target reference the ref points to. These fields are never
set though and are thus essentially unused.

Remove them.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agorefs/files: perform consistency checks for root refs
Patrick Steinhardt [Mon, 12 Jan 2026 09:02:56 +0000 (10:02 +0100)] 
refs/files: perform consistency checks for root refs

While the "files" backend already knows to perform consistency checks
for the "refs/" hierarchy, it doesn't verify any of its root refs. Plug
this omission.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agorefs/files: improve error handling when verifying symrefs
Patrick Steinhardt [Mon, 12 Jan 2026 09:02:55 +0000 (10:02 +0100)] 
refs/files: improve error handling when verifying symrefs

The error handling when verifying symbolic refs is a bit on the wild
side:

  - `fsck_report_ref()` can be told to ignore specific errors. If an
    error has been ignored and a previous check raised an unignored
    error, then assigning `ret = fsck_report_ref()` will cause us to
    swallow the previous error.

  - When the target reference is not valid we bail out early without
    checking for other errors.

Fix both of these issues by consistently or'ing the return value and not
bailing out early.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agorefs/files: extract function to check single ref
Patrick Steinhardt [Mon, 12 Jan 2026 09:02:54 +0000 (10:02 +0100)] 
refs/files: extract function to check single ref

When checking the consistency of references we create a directory
iterator and then verify each single reference in a loop. The logic to
perform the actual checks is embedded into that loop, which makes it
hard to reuse. But In a subsequent commit we're about to introduce a
second path that wants to verify references.

Prepare for this by extracting the logic to check a single reference
into a standalone function.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agorefs/files: remove useless indirection
Patrick Steinhardt [Mon, 12 Jan 2026 09:02:53 +0000 (10:02 +0100)] 
refs/files: remove useless indirection

The function `files_fsck_refs()` only has a single callsite and forwards
all of its arguments as-is, so it's basically a useless indirection.
Inline the function call.

While at it, also remove the bitwise or that we have for return values.
We don't really want to or them at all, but rather just want to return
an error in case either of the functions has failed.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agorefs/files: remove `refs_check_dir` parameter
Patrick Steinhardt [Mon, 12 Jan 2026 09:02:52 +0000 (10:02 +0100)] 
refs/files: remove `refs_check_dir` parameter

The parameter `refs_check_dir` determines which directory we want to
check references for. But as we always want to check the complete
refs hierarchy, this parameter is always set to "refs".

Drop the parameter and hardcode it.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agorefs/files: move fsck functions into global scope
Patrick Steinhardt [Mon, 12 Jan 2026 09:02:51 +0000 (10:02 +0100)] 
refs/files: move fsck functions into global scope

When performing consistency checks we pass the functions that perform
the verification down the calling stack. This is somewhat unnecessary
though, as the set of functions doesn't ever change.

Simplify the code by moving the array into global scope and remove the
parameter.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agorefs/files: simplify iterating through root refs
Patrick Steinhardt [Mon, 12 Jan 2026 09:02:50 +0000 (10:02 +0100)] 
refs/files: simplify iterating through root refs

When iterating through root refs we first need to determine the
directory in which the refs live. This is done by retrieving the root of
the loose refs via `refs->loose->root->name`, and putting it through
`files_ref_path()` to derive the final path.

This is somewhat redundant though: the root name of the loose files
cache is always going to be the empty string. As such, we always end up
passing that empty string to `files_ref_path()` as the ref hierarchy we
want to start. And this actually makes sense: `files_ref_path()` already
computes the location of the root directory, so of course we need to
pass the empty string for the ref hierarchy itself. So going via the
loose ref cache to figure out that the root of a ref hierarchy is empty
is only causing confusion.

But next to the added confusion, it can also lead to a segfault. The
loose ref cache is populated lazily, so it may not always be set. It
seems to be sheer luck that this is a condition we do not currently hit.
The right thing to do would be to call `get_loose_ref_cache()`, which
knows to populate the cache if required.

Simplify the code and fix the potential segfault by simply removing the
indirection via the loose ref cache completely.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agopackfile: drop repository parameter from `packed_object_info()`
Patrick Steinhardt [Mon, 12 Jan 2026 09:00:47 +0000 (10:00 +0100)] 
packfile: drop repository parameter from `packed_object_info()`

The function `packed_object_info()` takes a packfile and offset and
returns the object info for the corresponding object. Despite these two
parameters though it also takes a repository pointer. This is redundant
information though, as `struct packed_git` already has a repository
pointer that is always populated.

Drop the redundant parameter.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agopackfile: skip unpacking object header for disk size requests
Patrick Steinhardt [Mon, 12 Jan 2026 09:00:46 +0000 (10:00 +0100)] 
packfile: skip unpacking object header for disk size requests

While most of the object info requests for a packed object require us to
unpack its headers, reading its disk size doesn't. We still unpack the
object header in that case though, which is unnecessary work.

Skip reading the header if only the disk size is requested. This leads
to a small speedup when reading disk size, only. The following benchmark
was done in the Git repository:

    Benchmark 1: ./git rev-list --disk-usage HEAD (rev = HEAD~)
      Time (mean ± σ):     105.2 ms ±   0.6 ms    [User: 91.4 ms, System: 13.3 ms]
      Range (min … max):   103.7 ms … 106.0 ms    27 runs

    Benchmark 2: ./git rev-list --disk-usage HEAD (rev = HEAD)
      Time (mean ± σ):      96.7 ms ±   0.4 ms    [User: 86.2 ms, System: 10.0 ms]
      Range (min … max):    96.2 ms …  98.1 ms    30 runs

    Summary
      ./git rev-list --disk-usage HEAD (rev = HEAD) ran
        1.09 ± 0.01 times faster than ./git rev-list --disk-usage HEAD (rev = HEAD~)

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agopackfile: disentangle return value of `packed_object_info()`
Patrick Steinhardt [Mon, 12 Jan 2026 09:00:45 +0000 (10:00 +0100)] 
packfile: disentangle return value of `packed_object_info()`

The `packed_object_info()` function returns the type of the packed
object. While we use an `enum object_type` to store the return value,
this type is not to be confused with the actual object type. It _may_
contain the object type, but it may just as well encode that the given
packed object is stored as a delta.

We have removed the only caller that relied on this returned object type
in the preceding commit, so let's simplify semantics and return either 0
on success or a negative error code otherwise.

This unblocks a small optimization where we can skip reading the object
type altogether.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agopackfile: always populate pack-specific info when reading object info
Patrick Steinhardt [Mon, 12 Jan 2026 09:00:44 +0000 (10:00 +0100)] 
packfile: always populate pack-specific info when reading object info

When reading object information via `packed_object_info()` we may not
populate the object info's packfile-specific fields. This leads to
inconsistent object info depending on whether the info was populated via
`packfile_store_read_object_info()` or `packed_object_info()`.

Fix this inconsistency so that we can always assume the pack info to be
populated when reading object info from a pack.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agopackfile: extend `is_delta` field to allow for "unknown" state
Patrick Steinhardt [Mon, 12 Jan 2026 09:00:43 +0000 (10:00 +0100)] 
packfile: extend `is_delta` field to allow for "unknown" state

The `struct object_info::u::packed::is_delta` field determines whether
or not a specific object is stored as a delta. It only stores whether or
not the object is stored as delta, so it is treated as a boolean value.

This boolean is insufficient though: when reading a packed object via
`packfile_store_read_object_info()` we know to skip parsing the actual
object when the user didn't request any object-specific data. In that
case we won't read the object itself, but will only look up its position
in the packfile. Consequently, we do not know whether it is a delta or
not.

This isn't really an issue right now, as the check for an empty request
is broken. But a subsequent commit will fix it, and once we do we will
have the need to also represent an "unknown" delta state.

Prepare for this change by introducing a new enum that encodes the
object type. We don't use the "unknown" state just yet, but will start
to do so in a subsequent commit.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agopackfile: always declare object info to be OI_PACKED
Patrick Steinhardt [Mon, 12 Jan 2026 09:00:42 +0000 (10:00 +0100)] 
packfile: always declare object info to be OI_PACKED

When reading object info via a packfile we yield one of two types:

  - The object can either be OI_PACKED, which is what a caller would
    typically expect.

  - Or it can be OI_DBCACHED if it is stored in the delta base cache.

The latter really is an implementation detail though, and callers
typically don't care at all about the difference. Furthermore, the
information whether or not it is part of the delta base cache can
already be derived via the `is_delta` field, so the fact that we discern
between OI_PACKED and OI_DBCACHED only further complicates the
interface.

There aren't all that many callers that care about the `whence` field in
the first place. In fact, there's only three:

  - `packfile_store_read_object_info()` checks for `whence == OI_PACKED`
    and then populates the packfile information of the object info
    structure. We now start to do this also for deltified objects, which
    gives its callers strictly more information.

  - `repack_local_links()` wants to determine whether the object is part
    of a promisor pack and checks for `whence == OI_PACKED`. If so, it
    verifies that the packfile is a promisor pack. It's arguably wrong
    to declare that an object is not part of a promisor pack only
    because it is stored in the delta base cache.

  - `is_not_in_promisor_pack_obj()` does the same, but checks that a
    specific object is _not_ part of a promisor pack. The same reasoning
    as above applies.

Drop the OI_DBCACHED enum completely. None of the callers seem to care
about the distinction.

Note that this also fixes a segfault introduced in 8c1b84bc97
(streaming: move logic to read packed objects streams into backend,
2025-11-23), which refactors how we stream packed objects. The intent is
to only read packed objects in case they are stored non-deltified as
we'd otherwise have to deflate them first. But the check for whether or
not the object is stored as a delta was unconditionally done via
`oi.u.packed.is_delta`, which is only valid in case `oi.whence` is
`OI_PACKED`. But under some circumstances we got `OI_DBCACHED` here,
which means that none of the `oi.u.packed` fields were initialized at
all. Consequently, we assumed the object was not stored as a delta, and
then try to read the object from `oi.u.packed.pack`, which is a `NULL`
pointer and thus causes a segfault.

Add a test case for this issue so that this cannot regress in the
future anymore.

Reported-by: Matt Smiley <msmiley@gitlab.com>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agoobject-file: always set OI_LOOSE when reading object info
Patrick Steinhardt [Mon, 12 Jan 2026 09:00:41 +0000 (10:00 +0100)] 
object-file: always set OI_LOOSE when reading object info

There are some early returns in `odb_source_loose_read_object_info()`
in cases where we don't have to open the loose object. These return
paths do not set `struct object_info::whence` to `OI_LOOSE` though, so
it becomes impossible for the caller to tell the format of such an
object.

The root cause of this really is that we have so many different return
paths in the function. As a consequence, it's harder than necessary to
make sure that all successful exit paths sot up the `whence` field as
expected.

Address this by refactoring the function to have a single exit path.
Like this, we can trivially set up the `whence` field when we exit
successfully from the function.

Note that we also:

  - Rename `status` to `ret` to match our usual coding style, but also
    to show that the old `status` variable is now always getting the
    expected value. Furthermore, the value is not initialized anymore,
    which has the consequence that most compilers will warn for exit
    paths where we forgot to set it.

  - Move the setup of scratch pointers closer to `parse_loose_header()`
    to show where it's needed.

  - Guard a couple of variables on cleanup so that they only get
    released in case they have been set up.

  - Reset `oi->delta_base_oid` towards the end of the function, together
    with all the other object info pointers.

Overall, all these changes result in a diff that is somewhat hard to
read. But the end result is significantly easier to read and reason
about, so I'd argue this one-time churn is worth it.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agoThe 17th batch
Junio C Hamano [Mon, 12 Jan 2026 05:54:28 +0000 (21:54 -0800)] 
The 17th batch

Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agoMerge branch 'js/mailmap-karsten-blees'
Junio C Hamano [Mon, 12 Jan 2026 13:19:52 +0000 (05:19 -0800)] 
Merge branch 'js/mailmap-karsten-blees'

Mailmap update for Karsten

* js/mailmap-karsten-blees:
  .mailmap: replace Karsten Blees' default address

12 days agoMerge branch 'ps/t1300-2021-use-test-path-is-helpers'
Junio C Hamano [Mon, 12 Jan 2026 13:19:52 +0000 (05:19 -0800)] 
Merge branch 'ps/t1300-2021-use-test-path-is-helpers'

Test updates.

* ps/t1300-2021-use-test-path-is-helpers:
  t1300: use test helpers instead of `test` command

12 days agoMerge branch 'rs/commit-stack'
Junio C Hamano [Mon, 12 Jan 2026 13:19:52 +0000 (05:19 -0800)] 
Merge branch 'rs/commit-stack'

Code clean-up, unifying various hand-rolled "list of commit
objects" and use the commit_stack API.

* rs/commit-stack:
  commit-reach: use commit_stack
  commit-graph: use commit_stack
  commit: add commit_stack_grow()
  shallow: use commit_stack
  pack-bitmap-write: use commit_stack
  commit: add commit_stack_init()
  test-reach: use commit_stack
  remote: use commit_stack for src_commits
  remote: use commit_stack for sent_tips
  remote: use commit_stack for local_commits
  name-rev: use commit_stack
  midx: use commit_stack
  log: use commit_stack
  revision: export commit_stack

12 days agoMerge branch 'sb/bundle-uri-without-uri'
Junio C Hamano [Mon, 12 Jan 2026 13:19:52 +0000 (05:19 -0800)] 
Merge branch 'sb/bundle-uri-without-uri'

Diagnose invalid bundle-URI that lack the URI entry, instead of
crashing.

* sb/bundle-uri-without-uri:
  bundle-uri: validate that bundle entries have a uri

12 days agoMerge branch 'ja/doc-synopsis-style-more'
Junio C Hamano [Mon, 12 Jan 2026 13:19:51 +0000 (05:19 -0800)] 
Merge branch 'ja/doc-synopsis-style-more'

More doc style updates.

* ja/doc-synopsis-style-more:
  doc: convert git-remote to synopsis style
  doc: convert git stage to use synopsis block
  doc: convert git-status tables to AsciiDoc format
  doc: convert git-status to synopsis style
  doc: fix t0450-txt-doc-vs-help to select only first synopsis block

12 days agot1410: use test helpers in reflog rewind test
Pushkar Singh [Sun, 11 Jan 2026 19:07:52 +0000 (19:07 +0000)] 
t1410: use test helpers in reflog rewind test

Replace raw `test -f` and `! test -f` checks in the rewind test with
`test_path_is_file` and `test_path_is_missing`. This provides clearer
failure diagnostics and keeps the test consistent with the rest of
the test suite.

Signed-off-by: Pushkar Singh <pushkarkumarsingh1970@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agohttp-backend: write newlines to stderr when responding with errors
KJ Tsanaktsidis [Mon, 12 Jan 2026 01:44:39 +0000 (01:44 +0000)] 
http-backend: write newlines to stderr when responding with errors

The not_found and forbidden methods currently do not write a newline to
stderr after the error message. This means that if git-http-backend is
invoked through something like fcgiwrap, and the stderr of that fcgiwrap
process is sent to a logging daemon (e.g. journald), the error messages
of several git-http-backend invocations will just get strung together,
e.g.

> Not a git repository: '/var/lib/git/foo.git'Not a git repository: '/var/lib/git/foo.git'Not a git repository: '/var/lib/git/foo.git'

I think it's git-http-backend's responsibility to format these messages
properly, rather than it being fcgiwrap's job to notice that the script
didn't terminate stderr with a newline and do so itself.

Signed-off-by: KJ Tsanaktsidis <kj@kjtsanaktsidis.id.au>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks ago.mailmap: replace Karsten Blees' default address
Johannes Schindelin [Sat, 10 Jan 2026 11:06:44 +0000 (11:06 +0000)] 
.mailmap: replace Karsten Blees' default address

As per a recent email by Karsten, the @dcon.de address no longer works:
https://lore.kernel.org/git/77e768b2-6693-454f-9e11-fb0acdec703c@gmail.com

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agocontrib/subtree: detect rewritten subtree commits
Colin Stagner [Sat, 10 Jan 2026 01:18:11 +0000 (19:18 -0600)] 
contrib/subtree: detect rewritten subtree commits

    git subtree split --prefix P

detects splits that are outside of path prefix `P` and prunes
them from history graph processing. This improves the performance
of repeated `split --rejoin` with many different prefixes.

Both before and after 83f9dad7d6 (contrib/subtree: fix split with
squashed subtrees, 2025-09-09), the pruning logic does not detect
**rebased** or **cherry-picked** git-subtree commits. If `split`
encounters any of these commits, the split output may have
incomplete history.

All commits authored by

    git subtree merge [--squash] --prefix Q

have a first or second parent that has *only* subtree commits
as ancestors. When splitting a completely different path `P/`,
it is safe to ignore:

1. the merged tree
2. the subtree parent
3. *all* of that parent's ancestry, which applies only to
   path `Q/` and not `P/`.

But this relationship no longer holds if the git-subtree commit
is rebased or otherwise reauthored. After a rebase, the former
git-subtree commit will have other unrelated commits as ancestors.
Ignoring these commits may exclude the history of `P/`,
leading to incomplete `subtree split` output.

The pruning logic relies solely on the `git-subtree-*:` trailers
to detect git-subtree commits, which it blindly accepts without
further validation. The split logic also takes its time about
being wrong: `cmd_split()` execs a `git show` for *every* commit
in the split range… twice. This is inefficient in a shell script.

Add a "reality check" to ignore rebased or rewritten commits:

* Rewrites of non-merge commits cannot be detected, so the new
  detector no longer looks for them.

* Merges carry a `git-subtree-mainline:` trailer with the hash of
  the **first parent**. If this hash differs, or if the "merge"
  commit no longer has multiple parents, a rewrite has occurred.

To increase speed, package this logic in a new method,
`find_other_splits()`. Perform the check up-front by iterating
over a single `git log`. Add ignored subtrees to:

1. the `notree` cache, which excludes them from the `split` history

2. a `prune` negative refs list. The negative refs prevent
   recursing into other subtrees. Since there are potentially a
   *lot* of these, cache them on disk and use rev-list's
   `--stdin` mode.

Reported-by: George <george@mail.dietrich.pub>
Signed-off-by: Colin Stagner <ask+git@howdoi.land>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agotrim_last_path_component(): avoid hard-coding the directory separator
Karsten Blees [Fri, 9 Jan 2026 20:05:09 +0000 (20:05 +0000)] 
trim_last_path_component(): avoid hard-coding the directory separator

Currently, this function hard-codes the directory separator as the
forward slash.

However, on Windows the backslash character is valid, too. And we want
to call this function in the upcoming support for symlinks on Windows
with the symlink targets (which naturally use the canonical directory
separator on Windows, which is _not_ the forward slash).

Prepare that function to be useful also in that context.

Signed-off-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agostrbuf_readlink(): support link targets that exceed 2*PATH_MAX
Johannes Schindelin [Fri, 9 Jan 2026 20:05:08 +0000 (20:05 +0000)] 
strbuf_readlink(): support link targets that exceed 2*PATH_MAX

The `strbuf_readlink()` function refuses to read link targets that
exceed 2*PATH_MAX (even if a sufficient size was specified by the
caller).

The reason that that limit is 2*PATH_MAX instead of PATH_MAX is that
the symlink targets do not need to be normalized. After running
`ln -s a/../a/../a/../a/../b c`, the target of the symlink `c` will not
be normalized to `b` but instead be much longer. As such, symlink
targets' lengths can far exceed PATH_MAX.

They are frequently much longer than 2*PATH_MAX on Windows, which
actually supports paths up to 32,767 characters, but sets PATH_MAX to
260 for backwards compatibility. For full details, see
https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation

Let's just hard-code the limit used by `strbuf_readlink()` to 32,767 and
make it independent of the current platform's PATH_MAX.

Based-on-a-patch-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agostrbuf_readlink(): avoid calling `readlink()` twice in corner-cases
Karsten Blees [Fri, 9 Jan 2026 20:05:07 +0000 (20:05 +0000)] 
strbuf_readlink(): avoid calling `readlink()` twice in corner-cases

The `strbuf_readlink()` function calls `readlink()`` twice if the hint
argument specifies the exact size of the link target (e.g. by passing
stat.st_size as returned by `lstat()`). This is necessary because
`readlink(..., hint) == hint` could mean that the buffer was too small.

Use `hint + 1` as buffer size to prevent this.

Signed-off-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agoinit: do parse _all_ core.* settings early
Johannes Schindelin [Fri, 9 Jan 2026 20:05:06 +0000 (20:05 +0000)] 
init: do parse _all_ core.* settings early

In Git for Windows, `has_symlinks` is set to 0 by default. Therefore, we
need to parse the config setting `core.symlinks` to know if it has been
set to `true`. In `git init`, we must do that before copying the
templates because they might contain symbolic links.

Even if the support for symbolic links on Windows has not made it to
upstream Git yet, we really should make sure that all the `core.*`
settings are parsed before proceeding, as they might very well change
the behavior of `git init` in a way the user intended.

This fixes https://github.com/git-for-windows/git/issues/3414

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agomingw: do resolve symlinks in `getcwd()`
Johannes Schindelin [Fri, 9 Jan 2026 20:05:05 +0000 (20:05 +0000)] 
mingw: do resolve symlinks in `getcwd()`

As pointed out in https://github.com/git-for-windows/git/issues/1676,
the `git rev-parse --is-inside-work-tree` command currently fails when
the current directory's path contains symbolic links.

The underlying reason for this bug is that `getcwd()` is supposed to
resolve symbolic links, but our `mingw_getcwd()` implementation did not.

We do have all the building blocks for that, though: the
`GetFinalPathByHandleW()` function will resolve symbolic links. However,
we only called that function if `GetLongPathNameW()` failed, for
historical reasons: the latter function was supported for a long time,
but the former API function was introduced only with Windows Vista, and
we used to support also Windows XP. With that support having been
dropped, we are free to call the symbolic link-resolving function right
away.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agofsck: snapshot default refs before object walk
Elijah Newren [Fri, 9 Jan 2026 17:49:13 +0000 (17:49 +0000)] 
fsck: snapshot default refs before object walk

Fsck has a race when operating on live repositories; consider the
following simple script that writes new commits as fsck runs:

    #!/bin/bash
    git fsck &
    PID=$!

    while ps -p $PID >/dev/null; do
        sleep 3
        git commit -q --allow-empty -m "Another commit"
    done

Since fsck walks objects for connectivity and then reads the refs at the
end to check, this can cause fsck to get confused and think that the new
refs refer to missing commits and that new reflog entries are invalid.
Running the above script in a clone of git.git results in the following
(output ellipsized to remove additional errors of the same type):

    $ ./fsck-while-writing.sh
    Checking ref database: 100% (1/1), done.
    Checking object directories: 100% (256/256), done.
    warning in tag d6602ec5194c87b0fc87103ca4d67251c76f233a: missingTaggerEntry: invalid format - expected 'tagger' line
    Checking objects: 100% (835091/835091), done.
    error: HEAD: invalid reflog entry 2aac9f9286e2164fbf8e4f1d1df53044ace2b310
    error: HEAD: invalid reflog entry 2aac9f9286e2164fbf8e4f1d1df53044ace2b310
    error: HEAD: invalid reflog entry da0f5b80d61844a6f0ad2ddfd57e4fdfa246ea68
    error: HEAD: invalid reflog entry da0f5b80d61844a6f0ad2ddfd57e4fdfa246ea68
    [...]
    error: HEAD: invalid reflog entry 87c8a5c2f6b79d9afa9e941590b9a097b6f7ac09
    error: HEAD: invalid reflog entry d80887a48865e6ad165274b152cbbbed29f8a55a
    error: HEAD: invalid reflog entry d80887a48865e6ad165274b152cbbbed29f8a55a
    error: HEAD: invalid reflog entry 6724f2dfede88bfa9445a333e06e78536c0c6c0d
    error: refs/heads/mybranch invalid reflog entry 2aac9f9286e2164fbf8e4f1d1df53044ace2b310
    error: refs/heads/mybranch: invalid reflog entry 2aac9f9286e2164fbf8e4f1d1df53044ace2b310
    error: refs/heads/mybranch: invalid reflog entry da0f5b80d61844a6f0ad2ddfd57e4fdfa246ea68
    error: refs/heads/mybranch: invalid reflog entry da0f5b80d61844a6f0ad2ddfd57e4fdfa246ea68
    [...]
    error: refs/heads/mybranch: invalid reflog entry 87c8a5c2f6b79d9afa9e941590b9a097b6f7ac09
    error: refs/heads/mybranch: invalid reflog entry d80887a48865e6ad165274b152cbbbed29f8a55a
    error: refs/heads/mybranch: invalid reflog entry d80887a48865e6ad165274b152cbbbed29f8a55a
    error: refs/heads/mybranch: invalid reflog entry 6724f2dfede88bfa9445a333e06e78536c0c6c0d
    Checking connectivity: 833846, done.
    missing commit 6724f2dfede88bfa9445a333e06e78536c0c6c0d
    Verifying commits in commit graph: 100% (242243/242243), done.

We can minimize the race opportunities by taking a snapshot of refs at
program invocation, doing the connectivity check, and then checking the
snapshotted refs afterward.  This avoids races with regular refs between
fsck and adding objects to the database, though it still leaves a race
between a gc and fsck.  We are less concerned about folks simultaneously
running gc with fsck; though, if it becomes an issue, we could lock fsck
during gc.  We definitely do not want to lock fsck during operations
that may add objects to the object store; that would be problematic for
forges.

Note that refs aren't the only problem, though; reflog entries and index
entries could be problematic as well.  For now we punt on index entries
just leaving a TODO comment, and for reflogs we use a coarse solution of
taking the time at the beginning of the program and ignoring reflog
entries newer than that time.  That may be imperfect if dealing with a
network filesystem, so we leave TODO comment for those that want to
improve that handling as well.

As a high level overview:
  * In addition to fsck_handle_ref(), which now is only a few lines long
    to process a ref, there's also a snapshot_ref() which is called
    early in the program for each ref and takes all the error checking
    logic.
  * The iterating over refs that used to be in get_default_heads() plus
    a loop over the arguments now appears in shapshot_refs().
  * There's a new process_refs() as well that kind of looks like the old
    get_default_heads() though it is streamlined due to the work done by
    snapshot_refs().

This combination of changes modifies the output of running the script
(from the beginning of this commit message) to:

    $ ./fsck-while-writing.sh
    Checking ref database: 100% (1/1), done.
    Checking object directories: 100% (256/256), done.
    warning in tag d6602ec5194c87b0fc87103ca4d67251c76f233a: missingTaggerEntry: invalid format - expected 'tagger' line
    Checking objects: 100% (835091/835091), done.
    Checking connectivity: 833846, done.
    Verifying commits in commit graph: 100% (242243/242243), done.

While worries about live updates while running fsck is likely of most
interest for forge operators, it may also benefit those with
automated jobs (such as git maintenance) or even casual users who want
to do other work in their clone while fsck is running.

Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agopackfile: move MIDX into packfile store
Patrick Steinhardt [Fri, 9 Jan 2026 08:33:18 +0000 (09:33 +0100)] 
packfile: move MIDX into packfile store

The multi-pack index still is tracked as a member of the object database
source, but ultimately the MIDX is always tied to one specific packfile
store.

Move the structure into `struct packfile_store` accordingly. This
ensures that the packfile store now keeps track of all data related to
packfiles.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agopackfile: refactor `find_pack_entry()` to work on the packfile store
Patrick Steinhardt [Fri, 9 Jan 2026 08:33:17 +0000 (09:33 +0100)] 
packfile: refactor `find_pack_entry()` to work on the packfile store

The function `find_pack_entry()` doesn't work on a specific packfile
store, but instead works on the whole repository. This causes a bit of a
conceptual mismatch in its callers:

  - `packfile_store_freshen_object()` supposedly acts on a store, and
    its callers know to iterate through all sources already.

  - `packfile_store_read_object_info()` behaves likewise.

The only exception that doesn't know to handle iteration through sources
is `has_object_pack()`, but that function is trivial to adapt.

Refactor the code so that `find_pack_entry()` works on the packfile
store level instead.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agopackfile: inline `find_kept_pack_entry()`
Patrick Steinhardt [Fri, 9 Jan 2026 08:33:16 +0000 (09:33 +0100)] 
packfile: inline `find_kept_pack_entry()`

The `find_kept_pack_entry()` function is only used in
`has_object_kept_pack()`, which is only a trivial wrapper itself. Inline
the latter into the former.

Furthermore, reorder the code so that we can drop the declaration of the
function in "packfile.h". This allows us to make the function file-local.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agopackfile: only prepare owning store in `packfile_store_prepare()`
Patrick Steinhardt [Fri, 9 Jan 2026 08:33:15 +0000 (09:33 +0100)] 
packfile: only prepare owning store in `packfile_store_prepare()`

When calling `packfile_store_prepare()` we prepare not only the provided
packfile store, but also all those of all other sources part of the same
object database. This was required when the store was still sitting on
the object database level. But now that it sits on the source level it's
not anymore.

Refactor the code so that we only prepare the single packfile store
passed by the caller. Adapt callers accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agopackfile: only prepare owning store in `packfile_store_get_packs()`
Patrick Steinhardt [Fri, 9 Jan 2026 08:33:14 +0000 (09:33 +0100)] 
packfile: only prepare owning store in `packfile_store_get_packs()`

When calling `packfile_store_get_packs()` we prepare not only the
provided packfile store, but also all those of all other sources part of
the same object database. This was required when the store was still
sitting on the object database level. But now that it sits on the source
level it's not anymore.

Adapt the code so that we only prepare the MIDX of the provided store.
All callers only work in the context of a single store or call the
function in a loop over all sources, so this change shouldn't have any
practical effects.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agopackfile: move packfile store into object source
Patrick Steinhardt [Fri, 9 Jan 2026 08:33:13 +0000 (09:33 +0100)] 
packfile: move packfile store into object source

The packfile store is a member of `struct object_database`, which means
that we have a single store per database. This doesn't really make much
sense though: each source connected to the database has its own set of
packfiles, so there is a conceptual mismatch here. This hasn't really
caused much of a problem in the past, but with the advent of pluggable
object databases this is becoming more of a problem because some of the
sources may not even use packfiles in the first place.

Move the packfile store down by one level from the object database into
the object database source. This ensures that each source now has its
own packfile store, and we can eventually start to abstract it away
entirely so that the caller doesn't even know what kind of store it
uses.

Note that we only need to adjust a relatively small number of callers,
way less than one might expect. This is because most callers are using
`repo_for_each_pack()`, which handles enumeration of all packfiles that
exist in the repository. So for now, none of these callers need to be
adapted. The remaining callers that iterate through the packfiles
directly and that need adjustment are those that are a bit more tangled
with packfiles. These will be adjusted over time.

Note that this patch only moves the packfile store, and there is still a
bunch of functions that seemingly operate on a packfile store but that
end up iterating over all sources. These will be adjusted in subsequent
commits.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agopackfile: refactor misleading code when unusing pack windows
Patrick Steinhardt [Fri, 9 Jan 2026 08:33:12 +0000 (09:33 +0100)] 
packfile: refactor misleading code when unusing pack windows

The function `unuse_one_window()` is responsible for unmapping one of
the packfile windows, which is done when we have exceeded the allowed
number of window.

The function receives a `struct packed_git` as input, which serves as an
additional packfile that should be considered to be closed. If not
given, we seemingly skip that and instead go through all of the
repository's packfiles. The conditional that checks whether we have a
packfile though does not make much sense anymore, as we dereference the
packfile regardless of whether or not it is a `NULL` pointer to derive
the repository's packfile store.

The function was originally introduced via f0e17e86e1 (pack: move
release_pack_memory(), 2017-08-18), and here we indeed had a caller that
passed a `NULL` pointer. That caller was later removed via 9827d4c185
(packfile: drop release_pack_memory(), 2019-08-12), so starting with
that commit we always pass a `struct packed_git`. In 9c5ce06d74
(packfile: use `repository` from `packed_git` directly, 2024-12-03) we
then inadvertently started to rely on the fact that the pointer is never
`NULL` because we use it now to identify the repository.

Arguably, it didn't really make sense in the first place that the caller
provides a packfile, as the selected window would have been overridden
anyway by the subsequent loop over all packfiles if there was an older
window. So the overall logic is quite misleading overall. The only case
where it _could_ make a difference is when there were two packfiles with
the same `last_used` value, but that case doesn't ever happen because
the `pack_used_ctr` is strictly increasing.

Refactor the code so that we instead pass in the object database to
help make the code less misleading.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agopackfile: refactor kept-pack cache to work with packfile stores
Patrick Steinhardt [Fri, 9 Jan 2026 08:33:11 +0000 (09:33 +0100)] 
packfile: refactor kept-pack cache to work with packfile stores

The kept pack cache is a cache of packfiles that are marked as kept
either via an accompanying ".kept" file or via an in-memory flag. The
cache can be retrieved via `kept_pack_cache()`, where one needs to pass
in a repository.

Ultimately though the kept-pack cache is a property of the packfile
store, and this causes problems in a subsequent commit where we want to
move down the packfile store to be a per-object-source entity.

Prepare for this and refactor the kept-pack cache to work on top of a
packfile store instead. While at it, rename both the function and flags
specific to the kept-pack cache so that they can be properly attributed
to the respective subsystems.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agopackfile: pass source to `prepare_pack()`
Patrick Steinhardt [Fri, 9 Jan 2026 08:33:10 +0000 (09:33 +0100)] 
packfile: pass source to `prepare_pack()`

When preparing a packfile we pass various pieces attached to the pack's
object database source via the `struct prepare_pack_data`. Refactor this
code to instead pass in the source directly. This reduces the number of
variables we need to pass and allows for a subsequent refactoring where
we start to prepare the pack via the source.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agopackfile: create store via its owning source
Patrick Steinhardt [Fri, 9 Jan 2026 08:33:09 +0000 (09:33 +0100)] 
packfile: create store via its owning source

In subsequent patches we're about to move the packfile store from the
object database layer into the object database source layer. Once done,
we'll have one packfile store per source, where the source is owning the
store.

Prepare for this future and refactor `packfile_store_new()` to be
initialized via an object database source instead of via the object
database itself.

This refactoring leads to a weird in-between state where the store is
owned by the object database but created via the source. But this makes
subsequent refactorings easier because we can now start to access the
owning source of a given store.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agobuiltin.h: update documentation
Derrick Stolee [Fri, 9 Jan 2026 03:39:01 +0000 (03:39 +0000)] 
builtin.h: update documentation

The documentation for the builtin API was moved from the technical
documentation and into a comment in builtin.h by ec14d4ecb5 (builtin.h: take
over documentation from api-builtin.txt, 2017-08-02). This documentation
wasn't updated as part of the major overhaul to include a repository struct
in 9b1cb5070f (builtin: add a repository parameter for builtin functions,
2024-09-13).

There was a brief update regarding the move from *.txt to *.adoc by
e8015223c7 (builtin.h: *.txt -> *.adoc fixes, 2025-03-03).

I noticed that there was quite a bit missing from the old documentation,
which is still visible on git-scm.com [1].

[1] https://github.com/git/git-scm.com/issues/2124

This change updates the documentation in the following ways:

 1. Updates the cmd_foo() prototype to include a repository.
 2. Adds some newlines to have uniformity in the list of flags.
 3. Adds a description of the NO_PARSEOPT flag.
 4. Describes the tests that perform checks on all builtins, which may trip
    up a contributor working on a new builtin.

I double-checked these instructions against a toy example in my local branch
to be sure that it was complete.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agot7101: modernize test path checks
K Jayatheerth [Fri, 9 Jan 2026 03:20:27 +0000 (08:50 +0530)] 
t7101: modernize test path checks

Replace old-style `test -[df]` and `! test -[df]` assertions with
the modern `test_path_is_file`, `test_path_is_dir`, and
`test_path_is_missing` helpers.

These helpers provide more informative error messages in case of
failure (e.g., "File 'foo' is missing" instead of just exit code 1).

While at it, fix a typo and an incorrect path
reference in one of the test descriptions.

Signed-off-by: K Jayatheerth <jayatheerthkulkarni2005@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agogitfaq: document using stash import/export to sync working tree
brian m. carlson [Fri, 9 Jan 2026 01:46:08 +0000 (01:46 +0000)] 
gitfaq: document using stash import/export to sync working tree

Git 2.51 learned how to import and export stashes.  This is a
secure and robust way to transfer working tree states across machines
and comes with almost none of the pitfalls of rsync or other tools.
Recommend this as an alternative in the FAQ.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agodoc: git-blame: convert to new doc format
Michael Lyons [Thu, 8 Jan 2026 15:30:21 +0000 (10:30 -0500)] 
doc: git-blame: convert to new doc format

- Use _<placeholder>_ instead of <placeholder> in the description
- Use _underscores_ around math associated with <placeholders>
- Use `backticks` for keywords and more complex option
descriptions. The new rendering engine will apply synopsis rules to
these spans.

Signed-off-by: Michael Lyons <git@michael.lyo.nz>
Acked-by: Jean-Noël AVILA <jn.avila@free.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agodoc: blame-options: convert to new doc format
Michael Lyons [Thu, 8 Jan 2026 15:30:20 +0000 (10:30 -0500)] 
doc: blame-options: convert to new doc format

- Use _<placeholder>_ instead of <placeholder> in the description
- Modify some samples to use <placeholders>
- Use `backticks` for keywords and more complex option
descriptions. The new rendering engine will apply synopsis rules to
these spans.

Signed-off-by: Michael Lyons <git@michael.lyo.nz>
Acked-by: Jean-Noël AVILA <jn.avila@free.fr>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agodoc: patch-id: --verbatim locks in --stable
Kristoffer Haugsbakk [Thu, 8 Jan 2026 06:28:20 +0000 (07:28 +0100)] 
doc: patch-id: --verbatim locks in --stable

The default `--unstable` is a legacy format that predates `--stable`.
That’s why 2871f4d4 (builtin: patch-id: add --verbatim as a command mode,
2022-10-24) made `--verbatim` lock in[1] `--stable`:

    Users of --unstable mainly care about compatibility with old git
    versions, which unstripping the whitespace would break. Thus there
    isn't a usecase for the combination of --verbatim and --unstable,
    and we don't expose this so as to not add maintainence burden.

† 1: imply `--stable`, disallow `--unstable`

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agodoc: patch-id: spell out the git-diff-tree(1) form
Kristoffer Haugsbakk [Thu, 8 Jan 2026 06:28:19 +0000 (07:28 +0100)] 
doc: patch-id: spell out the git-diff-tree(1) form

You specifically need `--patch` since the default output is a raw diff.

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agodoc: patch-id: use definite article for the result
Kristoffer Haugsbakk [Thu, 8 Jan 2026 06:28:18 +0000 (07:28 +0100)] 
doc: patch-id: use definite article for the result

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agopatch-id: use “patch ID” throughout
Kristoffer Haugsbakk [Thu, 8 Jan 2026 06:28:17 +0000 (07:28 +0100)] 
patch-id: use “patch ID” throughout

The “Description” section decided to introduce and use the term “patch
ID” for the ID value itself.  Let’s use the same term on the options as
well.

Also make to sure to use bare “ID” instead of “id”.

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agodoc: patch-id: capitalize Git version
Kristoffer Haugsbakk [Thu, 8 Jan 2026 06:28:16 +0000 (07:28 +0100)] 
doc: patch-id: capitalize Git version

Git versions are always capitalized.

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agodoc: patch-id: don’t use semicolon between bullet points
Kristoffer Haugsbakk [Thu, 8 Jan 2026 06:28:15 +0000 (07:28 +0100)] 
doc: patch-id: don’t use semicolon between bullet points

These bullet points are full-fledged paragraphs with sentences.  It’s
best to restrict semicolon-termination to the case when the bullet list
amounts to a list of items.[1]

† 1: Like “List: ... • first; ... • second; and ... • third.”

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agoThe 16th batch
Junio C Hamano [Thu, 8 Jan 2026 06:58:11 +0000 (15:58 +0900)] 
The 16th batch

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agoMerge branch 'en/ort-recursive-d-f-conflict-fix'
Junio C Hamano [Thu, 8 Jan 2026 07:40:12 +0000 (16:40 +0900)] 
Merge branch 'en/ort-recursive-d-f-conflict-fix'

The ort merge machinery hit an assertion failure in a history with
criss-cross merges renamed a directory and a non-directory, which
has been corrected.

* en/ort-recursive-d-f-conflict-fix:
  merge-ort: fix corner case recursive submodule/directory conflict handling

2 weeks agoMerge branch 'dd/t5403-modernise'
Junio C Hamano [Thu, 8 Jan 2026 07:40:12 +0000 (16:40 +0900)] 
Merge branch 'dd/t5403-modernise'

Test micro-clean-up.

* dd/t5403-modernise:
  t5403: use test_path_is_file instead of test -f

2 weeks agoMerge branch 'ds/diff-lazy-fetch-with-name-only-fix'
Junio C Hamano [Thu, 8 Jan 2026 07:40:11 +0000 (16:40 +0900)] 
Merge branch 'ds/diff-lazy-fetch-with-name-only-fix'

Running "git diff" with "--name-only" and other options that allows
us not to look at the blob contents, while objects that are lazily
fetched from a promisor remote, caused use-after-free, which has
been corrected.

* ds/diff-lazy-fetch-with-name-only-fix:
  diff: avoid segfault with freed entries

2 weeks agoMerge branch 'rs/tag-wo-the-repository'
Junio C Hamano [Thu, 8 Jan 2026 07:40:11 +0000 (16:40 +0900)] 
Merge branch 'rs/tag-wo-the-repository'

Code clean-up.

* rs/tag-wo-the-repository:
  tag: stop using the_repository
  tag: support arbitrary repositories in parse_tag()
  tag: support arbitrary repositories in gpg_verify_tag()
  tag: use algo of repo parameter in parse_tag_buffer()

2 weeks agoMerge branch 'ps/odb-misc-fixes' into ps/packfile-store-in-odb-source
Junio C Hamano [Wed, 7 Jan 2026 00:37:29 +0000 (09:37 +0900)] 
Merge branch 'ps/odb-misc-fixes' into ps/packfile-store-in-odb-source

* ps/odb-misc-fixes:
  odb: properly close sources before freeing them
  builtin/gc: fix condition for whether to write commit graphs

2 weeks agot1420: modernize the lost-found test
Andrew Chitester [Tue, 6 Jan 2026 13:26:58 +0000 (08:26 -0500)] 
t1420: modernize the lost-found test

This test indirectly checks that the lost-found folder has 2 files in it
and then checks that the expected two files exist. Make this more
deliberate by removing the old test -f and compare the actual ls of the
lost-found directory with the expected files.

Signed-off-by: Andrew Chitester <andchi@fastmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agoodb: properly close sources before freeing them
Patrick Steinhardt [Tue, 6 Jan 2026 12:58:50 +0000 (13:58 +0100)] 
odb: properly close sources before freeing them

It is possible to hit a memory leak when reading data from a submodule
via git-grep(1):

  Direct leak of 192 byte(s) in 1 object(s) allocated from:
    #0 0x55555562e726 in calloc (git+0xda726)
    #1 0x555555964734 in xcalloc ../wrapper.c:154:8
    #2 0x555555835136 in load_multi_pack_index_one ../midx.c:135:2
    #3 0x555555834fd6 in load_multi_pack_index ../midx.c:382:6
    #4 0x5555558365b6 in prepare_multi_pack_index_one ../midx.c:716:17
    #5 0x55555586c605 in packfile_store_prepare ../packfile.c:1103:3
    #6 0x55555586c90c in packfile_store_reprepare ../packfile.c:1118:2
    #7 0x5555558546b3 in odb_reprepare ../odb.c:1106:2
    #8 0x5555558539e4 in do_oid_object_info_extended ../odb.c:715:4
    #9 0x5555558533d1 in odb_read_object_info_extended ../odb.c:862:8
    #10 0x5555558540bd in odb_read_object ../odb.c:920:6
    #11 0x55555580a330 in grep_source_load_oid ../grep.c:1934:12
    #12 0x55555580a13a in grep_source_load ../grep.c:1986:10
    #13 0x555555809103 in grep_source_is_binary ../grep.c:2014:7
    #14 0x555555807574 in grep_source_1 ../grep.c:1625:8
    #15 0x555555807322 in grep_source ../grep.c:1837:10
    #16 0x5555556a5c58 in run ../builtin/grep.c:208:10
    #17 0x55555562bb42 in void* ThreadStartFunc<false>(void*) lsan_interceptors.cpp.o
    #18 0x7ffff7a9a979 in start_thread (/nix/store/xx7cm72qy2c0643cm1ipngd87aqwkcdp-glibc-2.40-66/lib/libc.so.6+0x9a979) (BuildId: cddea92d6cba8333be952b5a02fd47d61054c5ab)
    #19 0x7ffff7b22d2b in __GI___clone3 (/nix/store/xx7cm72qy2c0643cm1ipngd87aqwkcdp-glibc-2.40-66/lib/libc.so.6+0x122d2b) (BuildId: cddea92d6cba8333be952b5a02fd47d61054c5ab)

The root caues of this leak is the way we set up and release the
submodule:

  1. We use `repo_submodule_init()` to initialize a new repository. This
     repository is stored in `repos_to_free`.

  2. We now read data from the submodule repository.

  3. We then call `repo_clear()` on the submodule repositories.

  4. `repo_clear()` calls `odb_free()`.

  5. `odb_free()` calls `odb_free_sources()` followed by `odb_close()`.

The issue here is the 5th step: we call `odb_free_sources()` _before_ we
call `odb_close()`. But `odb_free_sources()` already frees all sources,
so the logic that closes them in `odb_close()` now becomes a no-op. As a
consequence, we never explicitly close sources at all.

Fix the leak by closing the store before we free the sources.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agobuiltin/gc: fix condition for whether to write commit graphs
Patrick Steinhardt [Tue, 6 Jan 2026 12:58:49 +0000 (13:58 +0100)] 
builtin/gc: fix condition for whether to write commit graphs

When performing auto-maintenance we check whether commit graphs need to
be generated by counting the number of commits that are reachable by any
reference, but not covered by a commit graph. This search is performed
by iterating through all references and then doing a depth-first search
until we have found enough commits that are not present in the commit
graph.

This logic has a memory leak though:

  Direct leak of 16 byte(s) in 1 object(s) allocated from:
      #0 0x55555562e433 in malloc (git+0xda433)
      #1 0x555555964322 in do_xmalloc ../wrapper.c:55:8
      #2 0x5555559642e6 in xmalloc ../wrapper.c:76:9
      #3 0x55555579bf29 in commit_list_append ../commit.c:1872:35
      #4 0x55555569f160 in dfs_on_ref ../builtin/gc.c:1165:4
      #5 0x5555558c33fd in do_for_each_ref_iterator ../refs/iterator.c:431:12
      #6 0x5555558af520 in do_for_each_ref ../refs.c:1828:9
      #7 0x5555558ac317 in refs_for_each_ref ../refs.c:1833:9
      #8 0x55555569e207 in should_write_commit_graph ../builtin/gc.c:1188:11
      #9 0x55555569c915 in maintenance_is_needed ../builtin/gc.c:3492:8
      #10 0x55555569b76a in cmd_maintenance ../builtin/gc.c:3542:9
      #11 0x55555575166a in run_builtin ../git.c:506:11
      #12 0x5555557502f0 in handle_builtin ../git.c:779:9
      #13 0x555555751127 in run_argv ../git.c:862:4
      #14 0x55555575007b in cmd_main ../git.c:984:19
      #15 0x5555557523aa in main ../common-main.c:9:11
      #16 0x7ffff7a2a4d7 in __libc_start_call_main (/nix/store/xx7cm72qy2c0643cm1ipngd87aqwkcdp-glibc-2.40-66/lib/libc.so.6+0x2a4d7) (BuildId: cddea92d6cba8333be952b5a02fd47d61054c5ab)
      #17 0x7ffff7a2a59a in __libc_start_main@GLIBC_2.2.5 (/nix/store/xx7cm72qy2c0643cm1ipngd87aqwkcdp-glibc-2.40-66/lib/libc.so.6+0x2a59a) (BuildId: cddea92d6cba8333be952b5a02fd47d61054c5ab)
      #18 0x5555555f0934 in _start (git+0x9c934)

The root cause of this memory leak is our use of `commit_list_append()`.
This function expects as parameters the item to append and the _tail_ of
the list to append. This tail will then be overwritten with the new tail
of the list so that it can be used in subsequent calls. But we call it
with `commit_list_append(parent->item, &stack)`, so we end up losing
everything but the new item.

This issue only surfaces when counting merge commits. Next to being a
memory leak, it also shows that we're in fact miscounting as we only
respect children of the last parent. All previous parents are discarded,
so their children will be disregarded unless they are hit via another
reference.

While crafting a test case for the issue I was puzzled that I couldn't
establish the proper border at which the auto-condition would be
fulfilled. As it turns out, there's another bug: if an object is at the
tip of any reference we don't mark it as seen. Consequently, if it is
the tip of or reachable via another ref, we'd count that object multiple
times.

Fix both of these bugs so that we properly count objects without leaking
any memory.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 weeks agocat-file: only use bitmaps when filtering
Jeff King [Tue, 6 Jan 2026 10:25:58 +0000 (05:25 -0500)] 
cat-file: only use bitmaps when filtering

Commit 8002e8ee18 (builtin/cat-file: use bitmaps to efficiently filter
by object type, 2025-04-02) introduced a performance regression when we
are not filtering objects: it uses bitmaps even when they won't help,
incurring extra costs. For example, running the new perf tests from this
commit, which check the performance of listing objects by oid:

  $ export GIT_PERF_LARGE_REPO=/path/to/linux.git
  $ git -C "$GIT_PERF_LARGE_REPO" repack -adb
  $ GIT_SKIP_TESTS=p1006.1 ./run 8002e8ee188002e8ee18 p1006-cat-file.sh
  [...]
  Test                                  8002e8ee18^       8002e8ee18
  -------------------------------------------------------------------------------
  1006.2: list all objects (sorted)     1.48(1.44+0.04)   6.39(6.35+0.04) +331.8%
  1006.3: list all objects (unsorted)   3.01(2.97+0.04)   3.40(3.29+0.10) +13.0%
  1006.4: list blobs                    4.85(4.67+0.17)   1.68(1.58+0.10) -65.4%

An invocation that filters, like listing all blobs (1006.4), does
benefit from using the bitmaps; it now doesn't have to check the type of
each object from the pack data, so the tradeoff is worth it.

But for listing all objects in sorted idx order (1006.2), we otherwise
would never open the bitmap nor the revindex file. Worse, our sorting
step gets much worse. Normally we append into an array in pack .idx
order, and the sort step is trivial. But with bitmaps, we get the
objects in pack order, which is apparently random with respect to oid,
and have to sort the whole thing. (Note that this freshly-packed state
represents the best case for .idx sorting; if we had two packs, then
we'd have their objects one after the other and qsort would have to
interleave them).

The unsorted test in 1006.3 is interesting: there we are going in pack
order, so we load the revindex for the pack anyway. And though we don't
sort the result, we do use an oidset to check for duplicates. So we can
see in the 8002e8ee18^ timings that those two things cost ~1.5s over the
sorted case (mostly the oidset hash cost). We also incur the extra cost
to open the bitmap file as of 8002e8ee18, which seems to be ~400ms.
(This would probably be faster with a bitmap lookup table, but writing
that out is not yet the default).

So we know that bitmaps help when there's filtering to be done, but
otherwise make things worse. Let's only use them when there's a filter.

The perf script shows that we've fixed the regressions without hurting
the bitmap case:

  Test                                  8002e8ee18^       8002e8ee18                HEAD
  --------------------------------------------------------------------------------------------------------
  1006.2: list all objects (sorted)     1.56(1.53+0.03)   6.44(6.37+0.06) +312.8%   1.62(1.54+0.06) +3.8%
  1006.3: list all objects (unsorted)   3.04(2.98+0.06)   3.45(3.38+0.07) +13.5%    3.04(2.99+0.04) +0.0%
  1006.4: list blobs                    5.14(4.98+0.15)   1.76(1.68+0.06) -65.8%    1.73(1.64+0.09) -66.3%

Note that there's another related case: we might have a filter that
cannot be used with bitmaps. That check is handled already for us in
for_each_bitmapped_object(), though we'd still load the bitmap and
revindex files pointlessly in that case. I don't think it can happen in
practice for cat-file, though, since it allows only blob:none,
blob:limit, and object:type filters, all of which work with bitmaps.

It would be easy-ish to insert an extra check like:

  can_filter_bitmap(&opt->objects_filter);

into the conditional, but I didn't bother here. It would be redundant
with the call in for_each_bitmapped_object(), and the can_filter helper
function is static local in the bitmap code (so we'd have to make it
public).

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