]> git.ipfire.org Git - thirdparty/git.git/log
thirdparty/git.git
24 hours agoMerge branch 'jc/exclude-with-gitignore' into seen
Junio C Hamano [Thu, 6 Nov 2025 23:17:30 +0000 (15:17 -0800)] 
Merge branch 'jc/exclude-with-gitignore' into seen

"git add ':(exclude)foo.o'" is clearly a request not to add 'foo.o',
but the command complained about listing an ignored path foo.o on
the command line, which has been corrected.

Comments?

* jc/exclude-with-gitignore:
  dir.c: do not be fooled by :(exclude) pathspec elements

24 hours agoMerge branch 'jc/whitespace-incomplete-line' into jch
Junio C Hamano [Thu, 6 Nov 2025 23:17:15 +0000 (15:17 -0800)] 
Merge branch 'jc/whitespace-incomplete-line' into jch

Both "git apply" and "git diff" learn a new whitespace error class,
"incomplete-line".

Comments?

* jc/whitespace-incomplete-line:
  attr: enable incomplete-line whitespace error for this project
  diff: highlight and error out on incomplete lines
  apply: check and fix incomplete lines
  whitespace: allocate a few more bits and define WS_INCOMPLETE_LINE
  apply: revamp the parsing of incomplete lines
  diff: update the way rewrite diff handles incomplete lines
  diff: call emit_callback ecbdata everywhere
  diff: refactor output of incomplete line
  diff: fix incorrect counting of line numbers
  diff: correct suppress_blank_empty hack
  diff: emit_line_ws_markup() if/else style fix
  whitespace: correct bit assignment comments

24 hours agoMerge branch 'qj/doc-http-bad-want-response' into jch
Junio C Hamano [Thu, 6 Nov 2025 23:17:15 +0000 (15:17 -0800)] 
Merge branch 'qj/doc-http-bad-want-response' into jch

Doc update.

* qj/doc-http-bad-want-response:
  doc: clarify server behavior for invalid 'want' lines in HTTP protocol

24 hours agoMerge branch 'kn/maintenance-is-needed' into jch
Junio C Hamano [Thu, 6 Nov 2025 23:17:13 +0000 (15:17 -0800)] 
Merge branch 'kn/maintenance-is-needed' into jch

"git maintenance" command learned "is-needed" subcommand to tell if
it is necessary to perform various maintenance tasks.

* kn/maintenance-is-needed:
  maintenance: add 'is-needed' subcommand
  maintenance: add checking logic in `pack_refs_condition()`
  refs: add a `optimize_required` field to `struct ref_storage_be`
  reftable/stack: add function to check if optimization is required
  reftable/stack: return stack segments directly

24 hours agoMerge branch 'dk/make-git-contacts-executable' into jch
Junio C Hamano [Thu, 6 Nov 2025 23:17:13 +0000 (15:17 -0800)] 
Merge branch 'dk/make-git-contacts-executable' into jch

Building "git contacts" script (in contrib/) leaves the resulting
file unexecutable, which has been corrected.

* dk/make-git-contacts-executable:
  perl: also mark git-contacts executable

24 hours agoMerge branch 'dk/meson-html-dir' into jch
Junio C Hamano [Thu, 6 Nov 2025 23:17:13 +0000 (15:17 -0800)] 
Merge branch 'dk/meson-html-dir' into jch

The build procedure based on meson learned to allow builders to
specify the directory to install HTML documents.

* dk/meson-html-dir:
  meson: make GIT_HTML_PATH configurable

24 hours agoMerge branch 'en/ort-rename-another-fix' into jch
Junio C Hamano [Thu, 6 Nov 2025 23:17:12 +0000 (15:17 -0800)] 
Merge branch 'en/ort-rename-another-fix' into jch

Yet another corner case fix around renames in the "ort" merge
strategy.

* en/ort-rename-another-fix:
  merge-ort: fix failing merges in special corner case
  merge-ort: remove debugging crud
  t6429: update comment to mention correct tool

24 hours agoMerge branch 'sa/replay-atomic-ref-updates' into jch
Junio C Hamano [Thu, 6 Nov 2025 23:17:12 +0000 (15:17 -0800)] 
Merge branch 'sa/replay-atomic-ref-updates' into jch

"git replay" (experimental) learned to perform ref updates itself
in a transaction by default, instead of emitting where each refs
should point at and leaving the actual update to another command.

* sa/replay-atomic-ref-updates:
  replay: add replay.refAction config option
  replay: make atomic ref updates the default behavior
  replay: use die_for_incompatible_opt2() for option validation

24 hours agoMerge branch 'tu/credential-wincred-makefile-update' into jch
Junio C Hamano [Thu, 6 Nov 2025 23:17:12 +0000 (15:17 -0800)] 
Merge branch 'tu/credential-wincred-makefile-update' into jch

Build procedure for Wincred credential helper has been updated.

* tu/credential-wincred-makefile-update:
  wincred: align Makefile with other Makefiles in contrib

24 hours ago### match next
Junio C Hamano [Thu, 6 Nov 2025 23:17:12 +0000 (15:17 -0800)] 
### match next

24 hours agoMerge branch 'kn/refs-optim-cleanup' into jch
Junio C Hamano [Thu, 6 Nov 2025 23:17:12 +0000 (15:17 -0800)] 
Merge branch 'kn/refs-optim-cleanup' into jch

Code clean-up.

* 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

24 hours agoMerge branch 'ps/ref-peeled-tags' into jch
Junio C Hamano [Thu, 6 Nov 2025 23:17:11 +0000 (15:17 -0800)] 
Merge branch 'ps/ref-peeled-tags' into jch

Some ref backend storage can hold not just the object name of an
annotated tag, but the object name of the object the tag points at.
The code to handle this information has been streamlined.

* ps/ref-peeled-tags:
  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`

24 hours agoMerge branch 'tc/last-modified-active-paths-optimization' into jch
Junio C Hamano [Thu, 6 Nov 2025 23:17:10 +0000 (15:17 -0800)] 
Merge branch 'tc/last-modified-active-paths-optimization' into jch

"git last-modified" was optimized by narrowing the set of paths to
follow as it dug deeper in the history.

* tc/last-modified-active-paths-optimization:
  last-modified: implement faster algorithm

24 hours agoMerge branch 'ps/packed-git-in-object-store' into jch
Junio C Hamano [Thu, 6 Nov 2025 23:17:10 +0000 (15:17 -0800)] 
Merge branch 'ps/packed-git-in-object-store' into jch

The list of packfiles used in a running Git process is moved from
the packed_git structure into the packfile store.

* ps/packed-git-in-object-store:
  packfile: track packs via the MRU list exclusively
  packfile: always add packfiles to MRU when adding a pack
  packfile: move list of packs into the packfile store
  builtin/pack-objects: simplify logic to find kept or nonlocal objects
  packfile: fix approximation of object counts
  http: refactor subsystem to use `packfile_list`s
  packfile: move the MRU list into the packfile store
  packfile: use a `strmap` to store packs by name

24 hours agoMerge branch 'dk/parseopt-optional-filename-fixes' main master
Junio C Hamano [Thu, 6 Nov 2025 23:17:01 +0000 (15:17 -0800)] 
Merge branch 'dk/parseopt-optional-filename-fixes'

A recently added configuration variable and command line option
syntax ":(optional)" for values that are of filename type
inconsistently behaved on an empty file (configuration took it
happily, while the command line option pretended as if it did not
exist), which has been corrected.

* dk/parseopt-optional-filename-fixes:
  parseopt: remove unreachable code
  parseopt: restore const qualifier to parsed filename
  config: use boolean type for a simple flag
  parseopt: use boolean type for a simple flag
  doc: clarify command equivalence comment
  parseopt: fix :(optional) at command line to only ignore missing files

24 hours agoMerge branch 'cc/fast-import-export-i18n-cleanup'
Junio C Hamano [Thu, 6 Nov 2025 23:17:01 +0000 (15:17 -0800)] 
Merge branch 'cc/fast-import-export-i18n-cleanup'

Messages from fast-import/export are now marked for i18n.

* cc/fast-import-export-i18n-cleanup:
  gpg-interface: mark a string for translation
  fast-import: mark strings for translation
  fast-export: mark strings for translation
  gpg-interface: use left shift to define GPG_VERIFY_*
  gpg-interface: simplify ssh fingerprint parsing

24 hours agoMerge branch 'js/ci-github-actions-update'
Junio C Hamano [Thu, 6 Nov 2025 22:52:57 +0000 (14:52 -0800)] 
Merge branch 'js/ci-github-actions-update'

CI updates.

* js/ci-github-actions-update:
  ci: update {download,upload}-artifact Action versions

24 hours agoMerge branch 'pk/reflog-migrate-message-fix'
Junio C Hamano [Thu, 6 Nov 2025 22:52:56 +0000 (14:52 -0800)] 
Merge branch 'pk/reflog-migrate-message-fix'

Message fix.

* pk/reflog-migrate-message-fix:
  refs: add missing space in messages

28 hours agoci: update {download,upload}-artifact Action versions
Johannes Schindelin [Thu, 6 Nov 2025 13:59:36 +0000 (13:59 +0000)] 
ci: update {download,upload}-artifact Action versions

Bumps `actions/upload-artifact` from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

Bumps `actions/download-artifact` from 5 to 6.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v5...v6)

Originally-authored-by: dependabot[bot] <support@github.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
29 hours agomaintenance: add 'is-needed' subcommand
Karthik Nayak [Thu, 6 Nov 2025 08:22:34 +0000 (09:22 +0100)] 
maintenance: add 'is-needed' subcommand

The 'git-maintenance(1)' command provides tooling to run maintenance
tasks over Git repositories. The 'run' subcommand, as the name suggests,
runs the maintenance tasks. When used with the '--auto' flag, it uses
heuristics to determine if the required thresholds are met for running
said maintenance tasks.

There is however a lack of insight into these heuristics. Meaning, the
checks are linked to the execution.

Add a new 'is-needed' subcommand to 'git-maintenance(1)' which allows
users to simply check if it is needed to run maintenance without
performing it.

This subcommand can check if it is needed to run maintenance without
actually running it. Ideally it should be used with the '--auto' flag,
which would allow users to check if the thresholds required are met. The
subcommand also supports the '--task' flag which can be used to check
specific maintenance tasks.

While adding the respective tests in 't/t7900-maintenance.sh', remove a
duplicate of the test: 'worktree-prune task with --auto honors
maintenance.worktree-prune.auto'.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
29 hours agomaintenance: add checking logic in `pack_refs_condition()`
Karthik Nayak [Thu, 6 Nov 2025 08:22:33 +0000 (09:22 +0100)] 
maintenance: add checking logic in `pack_refs_condition()`

The 'git-maintenance(1)' command supports an '--auto' flag. Usage of the
flag ensures to run maintenance tasks only if certain thresholds are
met. The heuristic is defined on a task level, wherein each task defines
an 'auto_condition', which states if the task should be run.

The 'pack-refs' task is hard-coded to return 1 as:
1. There was never a way to check if the reference backend needs to be
optimized without actually performing the optimization.
2. We can pass in the '--auto' flag to 'git-pack-refs(1)' which would
optimize based on heuristics.

The previous commit added a `refs_optimize_required()` function, which
can be used to check if a reference backend required optimization. Use
this within `pack_refs_condition()`.

This allows us to add a 'git maintenance is-needed' subcommand which can
notify the user if maintenance is needed without actually performing the
optimization. Without this change, the reference backend would always
state that optimization is needed.

Since we import 'revision.h', we need to remove the definition for
'SEEN' which is duplicated in the included header.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
29 hours agorefs: add a `optimize_required` field to `struct ref_storage_be`
Karthik Nayak [Thu, 6 Nov 2025 08:22:32 +0000 (09:22 +0100)] 
refs: add a `optimize_required` field to `struct ref_storage_be`

To allow users of the refs namespace to check if the reference backend
requires optimization, add a new field `optimize_required` field to
`struct ref_storage_be`. This field is of type `optimize_required_fn`
which is also introduced in this commit.

Modify the debug, files, packed and reftable backend to implement this
field. A following commit will expose this via 'git pack-refs' and 'git
refs optimize'.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
29 hours agoreftable/stack: add function to check if optimization is required
Karthik Nayak [Thu, 6 Nov 2025 08:22:31 +0000 (09:22 +0100)] 
reftable/stack: add function to check if optimization is required

The reftable backend performs auto-compaction as part of its regular
flow, which is required to keep the number of tables part of a stack at
bay. This allows it to stay optimized.

Compaction can also be triggered voluntarily by the user via the 'git
pack-refs' or the 'git refs optimize' command. However, currently there
is no way for the user to check if optimization is required without
actually performing it.

Extract out the heuristics logic from 'reftable_stack_auto_compact()'
into an internal function 'update_segment_if_compaction_required()'.
Then use this to add and expose `reftable_stack_compaction_required()`
which will allow users to check if the reftable backend can be
optimized.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
29 hours agoreftable/stack: return stack segments directly
Karthik Nayak [Thu, 6 Nov 2025 08:22:30 +0000 (09:22 +0100)] 
reftable/stack: return stack segments directly

The `stack_table_sizes_for_compaction()` function returns individual
sizes of each reftable table. This function is only called by
`reftable_stack_auto_compact()` to decide which tables need to be
compacted, if any.

Modify the function to directly return the segments, which avoids the
extra step of receiving the sizes only to pass it to
`suggest_compaction_segment()`.

A future commit will also add functionality for checking whether
auto-compaction is necessary without performing it. This change allows
code re-usability in that context.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
29 hours agomeson: make GIT_HTML_PATH configurable
D. Ben Knoble [Tue, 4 Nov 2025 13:58:29 +0000 (08:58 -0500)] 
meson: make GIT_HTML_PATH configurable

Makefile-based builds can configure Git's internal HTML_PATH by defining
htmldir, which is useful for packagers that put documentation in
different locations. Gentoo, for example, uses version-suffixed
directories like ${prefix}/share/doc/git-2.51 and puts the HTML
documentation in an 'html' subdirectory of the same.

Propagate the same configuration knob to Meson-based builds so that
"git --html-path" on such systems can be configured to output the
correct directory.

Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
29 hours agoperl: also mark git-contacts executable
D. Ben Knoble [Tue, 4 Nov 2025 18:14:57 +0000 (13:14 -0500)] 
perl: also mark git-contacts executable

When installing git-contacts with Meson via -Dcontrib=contacts, the default
Perl generation fails to mark it executable. As a result, "git contacts"
reports "'contacts' is not a git command."

Unlike generate-script.sh, we aren't testing the basename here; so, glob
the script name in the case arm to match wherever the input comes from.

Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
29 hours agowincred: align Makefile with other Makefiles in contrib
Thomas Uhle [Wed, 5 Nov 2025 19:55:19 +0000 (20:55 +0100)] 
wincred: align Makefile with other Makefiles in contrib

* Replace $(LOADLIBES) because it is deprecated since long and it is
  used nowhere else in the git project.
* Use $(gitexecdir) instead of $(libexecdir) because config.mak defines
  $(libexecdir) as $(prefix)/libexec, not as $(prefix)/libexec/git-core.
* Similar to other Makefiles, let install target rule create
  $(gitexecdir) to make sure the directory exists before copying the
  executable and also let it respect $(DESTDIR).
* Shuffle the lines for the default settings to align them with the
  other Makefiles in contrib/credential.
* Define .PHONY for all special targets (all, install, clean).

Signed-off-by: Thomas Uhle <thomas.uhle@mailbox.tu-dresden.de>
Acked-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
29 hours agodoc: clarify server behavior for invalid 'want' lines in HTTP protocol
Queen Ediri Jessa [Wed, 5 Nov 2025 14:38:49 +0000 (15:38 +0100)] 
doc: clarify server behavior for invalid 'want' lines in HTTP protocol

Update the documentation to clearly describe how the server responds when a
client sends an invalid or malformed `want` line during the HTTP protocol
exchange. The server includes the offending object name in its error message.

Signed-off-by: Queen Ediri Jessa <qjessa662@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agorefs: add missing space in messages
Peter Krefting [Wed, 5 Nov 2025 21:47:17 +0000 (22:47 +0100)] 
refs: add missing space in messages

Signed-off-by: Peter Krefting <peter@softwolves.pp.se>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agoGit 2.52-rc1 v2.52.0-rc1
Junio C Hamano [Wed, 5 Nov 2025 21:41:41 +0000 (13:41 -0800)] 
Git 2.52-rc1

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agoMerge branch 'jc/ci-use-macos-14'
Junio C Hamano [Wed, 5 Nov 2025 21:41:51 +0000 (13:41 -0800)] 
Merge branch 'jc/ci-use-macos-14'

The version of macos image used in GitHub CI has been updated to
macos-14, as the macos-13 that we have been using got deprecated.

* jc/ci-use-macos-14:
  GitHub CI: macos-13 images are no more

2 days agoMerge branch 'rz/t0450-bisect-doc-update'
Junio C Hamano [Wed, 5 Nov 2025 21:41:51 +0000 (13:41 -0800)] 
Merge branch 'rz/t0450-bisect-doc-update'

The help text and manual page of "git bisect" command have been
made consistent with each other.

* rz/t0450-bisect-doc-update:
  bisect: update usage and docs to match each other

2 days agoattr: enable incomplete-line whitespace error for this project
Junio C Hamano [Wed, 5 Nov 2025 21:30:52 +0000 (13:30 -0800)] 
attr: enable incomplete-line whitespace error for this project

Now "git diff --check" and "git apply --whitespace=warn/fix" learned
incomplete line is a whitespace error, enable them for this project
to prevent patches to add new incomplete lines to our sources.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agodiff: highlight and error out on incomplete lines
Junio C Hamano [Wed, 5 Nov 2025 21:30:51 +0000 (13:30 -0800)] 
diff: highlight and error out on incomplete lines

Teach "git diff" to highlight "\ No newline at end of file" message
as a whitespace error when incomplete-line whitespace error class is
in effect.  Thanks to the previous refactoring of complete rewrite
code path, we can do this at a single place.

Unlike whitespace errors in the payload where we need to annotate in
line, possibly using colors, the line that has whitespace problems,
we have a dedicated line already that can serve as the error
message, so paint it as a whitespace error message.

Also teach "git diff --check" to notice incomplete lines as
whitespace errors and report when incomplete-line whitespace error
class is in effect.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agoapply: check and fix incomplete lines
Junio C Hamano [Wed, 5 Nov 2025 21:30:50 +0000 (13:30 -0800)] 
apply: check and fix incomplete lines

The final line of a file that lacks the terminating newline at its
end is called an incomplete line.  In general they are frowned upon
for many reasons (imagine concatenating two files with "cat A B" and
what happens when A ends in an incomplete line, for example), and
text-oriented tools often mishandle such a line.

Implement checks in "git apply" for incomplete lines, which is off
by default for backward compatibility's sake, so that "git apply
--whitespace={fix,warn,error}" can notice, warn against, and fix
them.

As one of the new test shows, if you modify contents on an
incomplete line in the original and leave the resulting line
incomplete, it is still considered a whitespace error, the reasoning
being that "you'd better fix it while at it if you are making a
change on an incomplete line anyway", which may controversial.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agowhitespace: allocate a few more bits and define WS_INCOMPLETE_LINE
Junio C Hamano [Wed, 5 Nov 2025 21:30:49 +0000 (13:30 -0800)] 
whitespace: allocate a few more bits and define WS_INCOMPLETE_LINE

Reserve a few more bits in the diff flags word to be used for future
whitespace rules.  Add WS_INCOMPLETE_LINE without implementing the
behaviour (yet).

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agoapply: revamp the parsing of incomplete lines
Junio C Hamano [Wed, 5 Nov 2025 21:30:48 +0000 (13:30 -0800)] 
apply: revamp the parsing of incomplete lines

A patch file represents the incomplete line at the end of the file
with two lines, one that is the usual "context" with " " as the
first letter, "added" with "+" as the first letter, or "removed"
with "-" as the first letter that shows the content of the line,
plus an extra "\ No newline at the end of file" line that comes
immediately after it.

Ever since the apply machinery was written, the "git apply"
machinery parses "\ No newline at the end of file" line
independently, without even knowing what line the incomplete-ness
applies to, simply because it does not even remember what the
previous line was.

This poses a problem if we want to check and warn on an incomplete
line.  Revamp the code that parses a fragment, to actually drop the
'\n' at the end of the incoming patch file that terminates a line,
so that check_whitespace() calls made from the code path actually
sees an incomplete as incomplete.

Note that the result of this parsing is not directly used by the
code path that applies the patch.  apply_one_fragment() function
already checks if each of the patch text it handles is followed by a
line that begins with a backslash to drop the newline at the end of
the current line it is looking at.  In a sense, this patch harmonizes
the behaviour of the parsing side to what is already done in the
application side.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agodiff: update the way rewrite diff handles incomplete lines
Junio C Hamano [Wed, 5 Nov 2025 21:30:47 +0000 (13:30 -0800)] 
diff: update the way rewrite diff handles incomplete lines

The diff_symbol based output framework uses one DIFF_SYMBOL_* enum
value per the kind of output lines of "git diff", which corresponds
to one output line from the xdiff machinery used internally.  Most
notably, DIFF_SYMBOL_PLUS and DIFF_SYMBOL_MINUS that correspond to
"+" and "-" lines are designed to always take a complete line, even
if the output from xdiff machinery may produce "\ No newline at the
end of file" immediately after them.

But this is not true in the rewrite-diff codepath, which completely
bypasses the xdiff machinery.  Since the code path feeds the bytes
directly from the payload to the output routines, the output layer
has to deal with an incomplete line with DIFF_SYMBOL_PLUS and
DIFF_SYMBOL_MINUS, which never would see an incomplete line in the
normal code paths.  This lack of final newline is compensated by an
ugly hack for a fabricated DIFF_SYMBOL_NO_LF_EOF token to inject an
extra newline to the output to simulate output coming from the xdiff
machinery.

Revamp the way the complete-rewrite code path feeds the lines to the
output layer by treating the last line of the pre/post image when it
is an incomplete line specially.

This lets us remove the DIFF_SYMBOL_NO_LF_EOF hack and use the usual
DIFF_SYMBOL_CONTEXT_INCOMPLETE code path, which will later learn how
to handle whitespace errors.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agodiff: call emit_callback ecbdata everywhere
Junio C Hamano [Wed, 5 Nov 2025 21:30:46 +0000 (13:30 -0800)] 
diff: call emit_callback ecbdata everywhere

Everybody else, except for emit_rewrite_lines(), calls the
emit_callback data ecbdata.  Make sure we call the same thing by
the same name for consistency.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agodiff: refactor output of incomplete line
Junio C Hamano [Wed, 5 Nov 2025 21:30:45 +0000 (13:30 -0800)] 
diff: refactor output of incomplete line

Create a helper function that reacts to "\ No newline at the end of
file" in preparation for unifying the incomplete line handling in
the code path that handles xdiff output and the code path that
bypasses xdiff and produces complete rewrite patch.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agodiff: fix incorrect counting of line numbers
Junio C Hamano [Wed, 5 Nov 2025 21:30:44 +0000 (13:30 -0800)] 
diff: fix incorrect counting of line numbers

The "\ No newline at the end of the file" can come after any of the
"-" (deleted preimage line), " " (unchanged line), or "+" (added
postimage line).  Incrementing only the preimage line number upon
seeing it does not make any sense.

We can keep track of what the previous line was, and increment
lno_in_{pre,post}image variables properly, like this patch does.  I
do not think it matters, as these numbers are used only to compare
them with blank_at_eof_in_{pre,post}image to issue the warning every
time we see an added line, but by definition, after we see "\ No
newline at the end of the file" for an added line, we will not see
an added line for the file.

Keeping track of what the last line was (in other words, "is it that
the file used to end in an incomplete line?  The file ends in an
incomplete line after the change?  Both the file before and after
the change ends in an incomplete line that did not change?") will be
independently useful.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agodiff: correct suppress_blank_empty hack
Junio C Hamano [Wed, 5 Nov 2025 21:30:43 +0000 (13:30 -0800)] 
diff: correct suppress_blank_empty hack

The suppress-blank-empty feature abused the CONTEXT_INCOMPLETE
symbol that was meant to be used only for "\ No newline at the end
of file" code path.

The intent of the feature was to turn a context line we receive from
xdiff machinery (which always uses ' ' for context lines, even an
empty one) and spit it out as a truly empty line.

Perform such a conversion very locally at where a line from xdiff
that begins with ' ' is handled for output; there are many checks
before the control reaches such place that checks the first letter
of the diff output line to see if it is a context line, and having
to check for '\n' and treat it as a special case is error prone.

In order to catch similar hacks in the future, make sure the code
path that is meant for "\ No newline" case checks the first byte is
indeed a backslash.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agodiff: emit_line_ws_markup() if/else style fix
Junio C Hamano [Wed, 5 Nov 2025 21:30:42 +0000 (13:30 -0800)] 
diff: emit_line_ws_markup() if/else style fix

Apply the simple rule: if you need {} in one arm of the if/else
if/else... cascade, have {} in all of them.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agowhitespace: correct bit assignment comments
Junio C Hamano [Wed, 5 Nov 2025 21:30:41 +0000 (13:30 -0800)] 
whitespace: correct bit assignment comments

A comment in diff.c claimed that bits up to 12th (counting from 0th)
are whitespace rules, and 13th thru 15th are for new/old/context,
but it turns out it was miscounting.  Correct them, and clarify
where the whitespace rule bits come from in the comment.  Extend bit
assignment comments to cover bits used for color-moved, which
weren't described.

Also update the way these bit constants are defined to use (1 << N)
notation, instead of octal constants, as it tends to make it easier
to notice a breakage like this.

Sprinkle a few blank lines between logically distinct groups of CPP
macro definitions to make them easier to read.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agoreplay: add replay.refAction config option
Siddharth Asthana [Wed, 5 Nov 2025 19:16:01 +0000 (00:46 +0530)] 
replay: add replay.refAction config option

Add a configuration variable to control the default behavior of git replay
for updating references. This allows users who prefer the traditional
pipeline output to set it once in their config instead of passing
--ref-action=print with every command.

The config variable uses string values that mirror the behavior modes:
  * replay.refAction = update (default): atomic ref updates
  * replay.refAction = print: output commands for pipeline

Helped-by: Junio C Hamano <gitster@pobox.com>
Helped-by: Elijah Newren <newren@gmail.com>
Helped-by: Christian Couder <christian.couder@gmail.com>
Helped-by: Phillip Wood <phillip.wood123@gmail.com>
Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agoreplay: make atomic ref updates the default behavior
Siddharth Asthana [Wed, 5 Nov 2025 19:16:00 +0000 (00:46 +0530)] 
replay: make atomic ref updates the default behavior

The git replay command currently outputs update commands that can be
piped to update-ref to achieve a rebase, e.g.

  git replay --onto main topic1..topic2 | git update-ref --stdin

This separation had advantages for three special cases:
  * it made testing easy (when state isn't modified from one step to
    the next, you don't need to make temporary branches or have undo
    commands, or try to track the changes)
  * it provided a natural can-it-rebase-cleanly (and what would it
    rebase to) capability without automatically updating refs, similar
    to a --dry-run
  * it provided a natural low-level tool for the suite of hash-object,
    mktree, commit-tree, mktag, merge-tree, and update-ref, allowing
    users to have another building block for experimentation and making
    new tools

However, it should be noted that all three of these are somewhat
special cases; users, whether on the client or server side, would
almost certainly find it more ergonomic to simply have the updating
of refs be the default.

For server-side operations in particular, the pipeline architecture
creates process coordination overhead. Server implementations that need
to perform rebases atomically must maintain additional code to:

  1. Spawn and manage a pipeline between git-replay and git-update-ref
  2. Coordinate stdout/stderr streams across the pipe boundary
  3. Handle partial failure states if the pipeline breaks mid-execution
  4. Parse and validate the update-ref command output

Change the default behavior to update refs directly, and atomically (at
least to the extent supported by the refs backend in use). This
eliminates the process coordination overhead for the common case.

For users needing the traditional pipeline workflow, add a new
--ref-action=<mode> option that preserves the original behavior:

  git replay --ref-action=print --onto main topic1..topic2 | git update-ref --stdin

The mode can be:
  * update (default): Update refs directly using an atomic transaction
  * print: Output update-ref commands for pipeline use

Test suite changes:

All existing tests that expected command output now use
--ref-action=print to preserve their original behavior. This keeps
the tests valid while allowing them to verify that the pipeline workflow
still works correctly.

New tests were added to verify:
  - Default atomic behavior (no output, refs updated directly)
  - Bare repository support (server-side use case)
  - Equivalence between traditional pipeline and atomic updates
  - Real atomicity using a lock file to verify all-or-nothing guarantee
  - Test isolation using test_when_finished to clean up state
  - Reflog messages include replay mode and target

A following commit will add a replay.refAction configuration
option for users who prefer the traditional pipeline output as their
default behavior.

Helped-by: Elijah Newren <newren@gmail.com>
Helped-by: Patrick Steinhardt <ps@pks.im>
Helped-by: Christian Couder <christian.couder@gmail.com>
Helped-by: Phillip Wood <phillip.wood123@gmail.com>
Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agoreplay: use die_for_incompatible_opt2() for option validation
Siddharth Asthana [Wed, 5 Nov 2025 19:15:59 +0000 (00:45 +0530)] 
replay: use die_for_incompatible_opt2() for option validation

In preparation for adding the --ref-action option, convert option
validation to use die_for_incompatible_opt2(). This helper provides
standardized error messages for mutually exclusive options.

The following commit introduces --ref-action which will be incompatible
with certain other options. Using die_for_incompatible_opt2() now means
that commit can cleanly add its validation using the same pattern,
keeping the validation logic consistent and maintainable.

This also aligns git-replay's option handling with how other Git commands
manage option conflicts, using the established die_for_incompatible_opt*()
helper family.

Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agoGitHub CI: macos-13 images are no more
Junio C Hamano [Tue, 4 Nov 2025 23:13:20 +0000 (15:13 -0800)] 
GitHub CI: macos-13 images are no more

As this image was deprecated on Sep 22nd, and will be dropped on Dec
4th, replace these jobs to use macos-14 images instead.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 days agodir.c: do not be fooled by :(exclude) pathspec elements
Junio C Hamano [Tue, 4 Nov 2025 22:11:20 +0000 (14:11 -0800)] 
dir.c: do not be fooled by :(exclude) pathspec elements

When exclude_matches_pathspec() tries to determine if an otherwise
excluded item matches the pathspec given, it goes through each
pathspec element and declares a hit, without checking if the element
is a negative ":(exclude)" element.  Fix it be applying the usual "a
path matches if it matches any one of positive pathspec element, and
if it matches none of negative pathspec elements" rule in the
function.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 days agoparseopt: remove unreachable code
Junio C Hamano [Tue, 4 Nov 2025 17:34:20 +0000 (09:34 -0800)] 
parseopt: remove unreachable code

At this point in the code after running skip_prefix() on the
variable and receiving the result in the same variable, the contents
of the variable can never be NULL.  The function either (1) updates
the variable to point at a later part of the string it originally
pointed at, or (2) leaves it intact if the string does not have the
prefix.  (1) will never make the variable NULL, and (2) cannot be
the source of NULL, because the variable cannot be NULL before
calling skip_prefix(), which would die immediately by dereferencing
the NULL pointer in that case.

Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 days agoparseopt: restore const qualifier to parsed filename
D. Ben Knoble [Sun, 2 Nov 2025 16:17:48 +0000 (11:17 -0500)] 
parseopt: restore const qualifier to parsed filename

This was unintentionally dropped in ccfcaf399f (parseopt: values of
pathname type can be prefixed with :(optional), 2025-09-28). Notably,
continue dropping the const qualifier when free'ing value; see
4049b9cfc0 (fix const issues with some functions, 2007-10-16) or
83838d5c1b (cast variable in call to free() in builtin/diff.c and
submodule.c, 2011-11-06) for more details on why.

Suggested-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 days agoconfig: use boolean type for a simple flag
D. Ben Knoble [Sun, 2 Nov 2025 16:17:47 +0000 (11:17 -0500)] 
config: use boolean type for a simple flag

Suggested-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 days agoparseopt: use boolean type for a simple flag
D. Ben Knoble [Sun, 2 Nov 2025 16:17:46 +0000 (11:17 -0500)] 
parseopt: use boolean type for a simple flag

Suggested-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 days agodoc: clarify command equivalence comment
D. Ben Knoble [Sun, 2 Nov 2025 16:17:45 +0000 (11:17 -0500)] 
doc: clarify command equivalence comment

Documentation of command parsing for :(optional) includes a terse
comment; expand it to be clearer to readers.

Suggested-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 days agoparseopt: fix :(optional) at command line to only ignore missing files
D. Ben Knoble [Sun, 2 Nov 2025 16:17:44 +0000 (11:17 -0500)] 
parseopt: fix :(optional) at command line to only ignore missing files

Unlike the configuration option magic, the parseopt code also ignores
empty files: compare implementations from ccfcaf399f (parseopt: values
of pathname type can be prefixed with :(optional), 2025-09-28) and
749d6d166d (config: values of pathname type can be prefixed with
:(optional), 2025-09-28).

Unify the 2 by not ignoring empty files, which is less surprising and
the intended semantics from the first patch for config.

Suggested-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 days agoA bit more before rc1
Junio C Hamano [Tue, 4 Nov 2025 15:47:51 +0000 (07:47 -0800)] 
A bit more before rc1

Signed-off-by: Junio C Hamano <gitster@pobox.com>
3 days agoMerge branch 'jk/doc-backslash-in-exclude'
Junio C Hamano [Tue, 4 Nov 2025 15:48:10 +0000 (07:48 -0800)] 
Merge branch 'jk/doc-backslash-in-exclude'

The patterns used in the .gitignore files use backslash in the way
documented for fnmatch(3); document as such to reduce confusion.

* jk/doc-backslash-in-exclude:
  doc: document backslash in gitignore patterns

3 days agoMerge branch 'jk/test-delete-gpgsig-leakfix'
Junio C Hamano [Tue, 4 Nov 2025 15:48:09 +0000 (07:48 -0800)] 
Merge branch 'jk/test-delete-gpgsig-leakfix'

Leakfix.

* jk/test-delete-gpgsig-leakfix:
  test-tool: fix leak in delete-gpgsig command

3 days agoMerge branch 'eb/t1016-hash-transition-fix'
Junio C Hamano [Tue, 4 Nov 2025 15:48:09 +0000 (07:48 -0800)] 
Merge branch 'eb/t1016-hash-transition-fix'

Test fix.

* eb/t1016-hash-transition-fix:
  t1016-compatObjectFormat: really freeze time for reproduciblity

3 days agoMerge branch 'kh/doc-checkout-markup-fix'
Junio C Hamano [Tue, 4 Nov 2025 15:48:08 +0000 (07:48 -0800)] 
Merge branch 'kh/doc-checkout-markup-fix'

Doc mark-up fix.

* kh/doc-checkout-markup-fix:
  doc: git-checkout: fix placeholder markup

3 days agoMerge branch 'xr/ref-debug-remove-on-disk'
Junio C Hamano [Tue, 4 Nov 2025 15:48:08 +0000 (07:48 -0800)] 
Merge branch 'xr/ref-debug-remove-on-disk'

The "debug" ref-backend was missing a method implementation, which
has been corrected.

* xr/ref-debug-remove-on-disk:
  refs: add missing remove_on_disk implementation for debug backend

3 days 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

3 days 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

3 days 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()

3 days 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

3 days 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

3 days 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

3 days 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
  ...

3 days 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>
3 days 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>
3 days 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>
3 days 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
  ...

3 days 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>
3 days 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>
3 days 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>
3 days 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>
3 days 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>
3 days 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>
3 days 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>
3 days 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>
3 days 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>
3 days 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>
3 days 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>
3 days 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>
3 days 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>
3 days 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>
3 days 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>
3 days 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>
4 days agomerge-ort: fix failing merges in special corner case
Elijah Newren [Mon, 3 Nov 2025 18:01:48 +0000 (18:01 +0000)] 
merge-ort: fix failing merges in special corner case

At GitHub, we had a repository that was triggering
  git: merge-ort.c:3032: process_renames: Assertion `newinfo && !newinfo->merged.clean` failed.
during git replay.

This sounds similar to the somewhat recent f6ecb603ff8a (merge-ort: fix
directory rename on top of source of other rename/delete, 2025-08-06),
but the cause is different.  Unlike that case, there are no
rename-to-self situations arising in this case, and new to this case it
can only be triggered during a replay operation on the 2nd or later
commit being replayed, never on the first merge in the sequence.

To trigger, the repository needs:
  * an upstream which:
    * renames a file to a different directory, e.g.
        old/file -> new/file
    * leaves other files remaining in the original directory (so that
      e.g. "old/" still exists upstream even though file has been
      removed from it and placed elsewhere)
  * a topic branch being rebased where:
    * a commit in the sequence:
      * modifies old/file
    * a subsequent commit in the sequence being replayed:
      * does NOT touch *anything* under new/
      * does NOT touch old/file
      * DOES modify other paths under old/
      * does NOT have any relevant renames that we need to detect
        _anywhere_ elsewhere in the tree (meaning this interacts
        interestingly with both directory renames and cached renames)

In such a case, the assertion will trigger.  The fix turns out to be
surprisingly simple.  I have a very vague recollection that I actually
considered whether to add such an if-check years ago when I added the
very similar one for oldinfo in 1b6b902d95a5 (merge-ort:
process_renames() now needs more defensiveness, 2021-01-19), but I think
I couldn't figure out a possible way to trigger it and was worried at
the time that if I didn't know how to trigger it then I wasn't so sure
that simply skipping it was correct.  Waiting did give me a chance to
put more thorough tests and checks into place for the rename-to-self
cases a few months back, which I might not have found as easily
otherwise.  Anyway, put the check in place now and add a test that
demonstrates the fix.

Note that this bug, as demonstrated by the conditions listed above,
runs at the intersection of relevant renames, trivial directory
resolutions, and cached renames.  All three of those optimizations are
ones that unfortunately make the code (and testcases!) a bit more
complex, and threading all three makes it a bit more so.  However, the
testcase isn't crazy enough that I'd expect no one to ever hit it in
practice, and was confused why we didn't see it before.  After some
digging, I discovered that merge.directoryRenames=false is a workaround
to this bug, and GitHub used that setting until recently (it was a
"temporary" match-what-libgit2-does piece of code that lasted years
longer than intended).  Since the conditions I gave above for triggering
this bug rule out the possibility of there being directory renames, one
might assume that it shouldn't matter whether you try to detect such
renames if there aren't any.  However, due to commit a16e8efe5c2b
(merge-ort: fix merge.directoryRenames=false, 2025-03-13), the heavy
hammer used there means that merge.directoryRenames=false ALSO turns off
rename caching, which is critical to triggering the bug.  This becomes
a bit more than an aside since...

Re-reading that old commit, a16e8efe5c2b (merge-ort: fix
merge.directoryRenames=false, 2025-03-13), it appears that the solution
to this latest bug might have been at least a partial alternative
solution to that old commit.  And it may have been an improved
alternative (or at least help implement one), since it may be able to
avoid the heavy-handed disabling of rename cache.  That might be an
interesting future thing to investigate, but is not critical for the
current fix.  However, since I spent time digging it all up, at least
leave a small comment tweak breadcrumb to help some future reader
(myself or others) who wants to dig further to connect the dots a little
quicker.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
4 days agomerge-ort: remove debugging crud
Elijah Newren [Mon, 3 Nov 2025 18:01:47 +0000 (18:01 +0000)] 
merge-ort: remove debugging crud

While developing commit a16e8efe5c2b (merge-ort: fix
merge.directoryRenames=false, 2025-03-13), I was testing things out and
had an extra condition on one of the if-blocks that I occasionally
swapped between '&& 0' and '&& 1' to see the effects of the changes.  I
forgot to remove it before submitting and it wasn't caught in review.
Remove it now.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
4 days agot6429: update comment to mention correct tool
Elijah Newren [Mon, 3 Nov 2025 18:01:46 +0000 (18:01 +0000)] 
t6429: update comment to mention correct tool

A comment at the top of t6429 mentions why the test doesn't exercise git
rebase or git cherry-pick.  However, it claims that it uses `test-tool
fast-rebase`.  That was true when the comment was written, but commit
f920b0289ba3 (replay: introduce new builtin, 2023-11-24) changed it to
use git replay without updating this comment.

We could potentially just strike this second comment, since git replay
is a bonified built-in, but perhaps the explanation about why it focuses
on git replay is still useful.  Update the comment to make it accurate
again.

Signed-off-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
4 days 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>
4 days 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>
4 days 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()

4 days 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

4 days 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

4 days 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

4 days 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

4 days 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

8 days 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>