]> git.ipfire.org Git - thirdparty/git.git/log
thirdparty/git.git
9 hours agoThe 11th batch main master
Junio C Hamano [Tue, 2 Jun 2026 03:48:59 +0000 (12:48 +0900)] 
The 11th batch

Signed-off-by: Junio C Hamano <gitster@pobox.com>
9 hours agoMerge branch 'kh/doc-hook'
Junio C Hamano [Tue, 2 Jun 2026 07:15:29 +0000 (16:15 +0900)] 
Merge branch 'kh/doc-hook'

Doc updates.

* kh/doc-hook:
  doc: hook: don’t self-link via config include
  doc: config: include existing git-hook(1) section
  doc: hook: consistently capitalize Git
  doc: hook: remove stray backtick

9 hours agoMerge branch 'ds/path-walk-filters'
Junio C Hamano [Tue, 2 Jun 2026 07:15:29 +0000 (16:15 +0900)] 
Merge branch 'ds/path-walk-filters'

The "git pack-objects --path-walk" traversal has been integrated
with several object filters, including blobless and sparse filters.

* ds/path-walk-filters:
  path-walk: support `combine` filter
  path-walk: support `object:type` filter
  path-walk: support `tree:0` filter
  t6601: tag otherwise-unreachable trees
  pack-objects: support sparse:oid filter with path-walk
  path-walk: add pl_sparse_trees to control tree pruning
  path-walk: support blob size limit filter
  backfill: die on incompatible filter options
  path-walk: support blobless filter
  path-walk: always emit directly-requested objects
  t/perf: add pack-objects filter and path-walk benchmark
  pack-objects: pass --objects with --path-walk
  t5620: make test work with path-walk var

9 hours agoMerge branch 'ta/approxidate-noon-fix'
Junio C Hamano [Tue, 2 Jun 2026 07:15:29 +0000 (16:15 +0900)] 
Merge branch 'ta/approxidate-noon-fix'

"Friday noon" asked in the morning on Sunday was parsed to be one
day before the specified time, which has been corrected.

* ta/approxidate-noon-fix:
  approxidate: use deferred mday adjustments for "specials"
  approxidate: make "specials" respect fixed day-of-month
  t0006: add support for approxidate test date adjustment
  approxidate: make "today" wrap to midnight

9 hours agoMerge branch 'jk/connect-service-enum'
Junio C Hamano [Tue, 2 Jun 2026 07:15:28 +0000 (16:15 +0900)] 
Merge branch 'jk/connect-service-enum'

The "name" argument in git_connect() and related functions has been
converted to a "service" enum to improve type safety and clarify its
purpose.

* jk/connect-service-enum:
  transport-helper: fix typo in BUG() message
  connect: use "service" enum for "name" argument

2 days agoThe 10th batch
Junio C Hamano [Sun, 31 May 2026 01:00:11 +0000 (10:00 +0900)] 
The 10th batch

Signed-off-by: Junio C Hamano <gitster@pobox.com>
2 days agoMerge branch 'sp/doc-range-diff-takes-notes'
Junio C Hamano [Sun, 31 May 2026 01:00:39 +0000 (10:00 +0900)] 
Merge branch 'sp/doc-range-diff-takes-notes'

Docfix.

* sp/doc-range-diff-takes-notes:
  Documentation/git-range-diff: add missing notes options in synopsis

2 days agoMerge branch 'ps/gitlab-ci-macOS-improvements'
Junio C Hamano [Sun, 31 May 2026 01:00:38 +0000 (10:00 +0900)] 
Merge branch 'ps/gitlab-ci-macOS-improvements'

Update GitLab CI jobs that exercise macOS.

* ps/gitlab-ci-macOS-improvements:
  gitlab-ci: update macOS image
  gitlab-ci: upgrade macOS runners

2 days agoMerge branch 'sa/cat-file-batch-mailmap-switch'
Junio C Hamano [Sun, 31 May 2026 01:00:38 +0000 (10:00 +0900)] 
Merge branch 'sa/cat-file-batch-mailmap-switch'

"git cat-file --batch" learns an in-line command "mailmap"
that lets the user toggle use of mailmap.

* sa/cat-file-batch-mailmap-switch:
  cat-file: add mailmap subcommand to --batch-command

2 days agoMerge branch 'jk/commit-graph-lazy-load-fallback'
Junio C Hamano [Sun, 31 May 2026 01:00:38 +0000 (10:00 +0900)] 
Merge branch 'jk/commit-graph-lazy-load-fallback'

The logic to lazy-load trees from the commit-graph has been made
more robust by falling back to reading the commit object when
the commit-graph is no longer available.

* jk/commit-graph-lazy-load-fallback:
  commit: fall back to full read when maybe_tree is NULL

2 days agoMerge branch 'pt/fsmonitor-linux'
Junio C Hamano [Sun, 31 May 2026 01:00:38 +0000 (10:00 +0900)] 
Merge branch 'pt/fsmonitor-linux'

The fsmonitor daemon has been implemented for Linux.

* pt/fsmonitor-linux:
  fsmonitor: convert shown khash to strset in do_handle_client
  fsmonitor: add tests for Linux
  fsmonitor: add timeout to daemon stop command
  fsmonitor: close inherited file descriptors and detach in daemon
  run-command: add close_fd_above_stderr option
  fsmonitor: implement filesystem change listener for Linux
  fsmonitor: rename fsm-settings-darwin.c to fsm-settings-unix.c
  fsmonitor: rename fsm-ipc-darwin.c to fsm-ipc-unix.c
  fsmonitor: use pthread_cond_timedwait for cookie wait
  compat/win32: add pthread_cond_timedwait
  fsmonitor: fix hashmap memory leak in fsmonitor_run_daemon
  fsmonitor: fix khash memory leak in do_handle_client
  t9210, t9211: disable GIT_TEST_SPLIT_INDEX for scalar clone tests

2 days agoMerge branch 'ps/graph-lane-limit'
Junio C Hamano [Sun, 31 May 2026 01:00:37 +0000 (10:00 +0900)] 
Merge branch 'ps/graph-lane-limit'

The graph output from commands like "git log --graph" can now be
limited to a specified number of lanes, preventing overly wide output
in repositories with many branches.

* ps/graph-lane-limit:
  graph: add truncation mark to capped lanes
  graph: add --graph-lane-limit option
  graph: limit the graph width to a hard-coded max

2 days agoMerge branch 'jr/bisect-custom-terms-in-output'
Junio C Hamano [Sun, 31 May 2026 01:00:37 +0000 (10:00 +0900)] 
Merge branch 'jr/bisect-custom-terms-in-output'

"git bisect" now uses the selected terms (e.g., old/new) more
consistently in its output.

* jr/bisect-custom-terms-in-output:
  rev-parse: use selected alternate terms to look up refs
  bisect: print bisect terms in single quotes
  bisect: use selected alternate terms in status output

2 days agoMerge branch 'tc/generate-configlist-fix-for-older-ninja'
Junio C Hamano [Sun, 31 May 2026 01:00:37 +0000 (10:00 +0900)] 
Merge branch 'tc/generate-configlist-fix-for-older-ninja'

Build update.

* tc/generate-configlist-fix-for-older-ninja:
  generate-configlist: collapse depfile for older Ninja

2 days agoMerge branch 'kk/tips-reachable-from-bases-optim'
Junio C Hamano [Sun, 31 May 2026 01:00:37 +0000 (10:00 +0900)] 
Merge branch 'kk/tips-reachable-from-bases-optim'

Revision traversal optimization.

* kk/tips-reachable-from-bases-optim:
  t6600: add tests for duplicate tips in tips_reachable_from_bases()
  commit-reach: use object flags for tips_reachable_from_bases()

2 days agoMerge branch 'ed/check-connected-close-err-fd'
Junio C Hamano [Sun, 31 May 2026 01:00:36 +0000 (10:00 +0900)] 
Merge branch 'ed/check-connected-close-err-fd'

File descriptor leak fix.

* ed/check-connected-close-err-fd:

2 days agoMerge branch 'ed/check-connected-close-err-fd-2.53'
Junio C Hamano [Sun, 31 May 2026 01:00:36 +0000 (10:00 +0900)] 
Merge branch 'ed/check-connected-close-err-fd-2.53'

File descriptor leak fix (for 2.54 maintenance track).

* ed/check-connected-close-err-fd-2.53:
  connected: close err_fd in promisor fast-path

6 days agoThe 9th batch
Junio C Hamano [Wed, 27 May 2026 05:15:25 +0000 (14:15 +0900)] 
The 9th batch

Signed-off-by: Junio C Hamano <gitster@pobox.com>
6 days agoMerge branch 'ps/setup-wo-the-repository'
Junio C Hamano [Wed, 27 May 2026 05:15:46 +0000 (14:15 +0900)] 
Merge branch 'ps/setup-wo-the-repository'

Many uses of the_repository has been updated to use a more
appropriate struct repository instance in setup.c codepath.

* ps/setup-wo-the-repository:
  setup: stop using `the_repository` in `init_db()`
  setup: stop using `the_repository` in `create_reference_database()`
  setup: stop using `the_repository` in `initialize_repository_version()`
  setup: stop using `the_repository` in `check_repository_format()`
  setup: stop using `the_repository` in `upgrade_repository_format()`
  setup: stop using `the_repository` in `setup_git_directory()`
  setup: stop using `the_repository` in `setup_git_directory_gently()`
  setup: stop using `the_repository` in `setup_git_env()`
  setup: stop using `the_repository` in `set_git_work_tree()`
  setup: stop using `the_repository` in `setup_work_tree()`
  setup: stop using `the_repository` in `enter_repo()`
  setup: stop using `the_repository` in `verify_non_filename()`
  setup: stop using `the_repository` in `verify_filename()`
  setup: stop using `the_repository` in `path_inside_repo()`
  setup: stop using `the_repository` in `prefix_path()`
  setup: stop using `the_repository` in `is_inside_work_tree()`
  setup: stop using `the_repository` in `is_inside_git_dir()`
  setup: replace use of `the_repository` in static functions

6 days agoMerge branch 'ps/odb-in-memory'
Junio C Hamano [Wed, 27 May 2026 05:15:46 +0000 (14:15 +0900)] 
Merge branch 'ps/odb-in-memory'

Add a new odb "in-memory" source that is meant to only hold
tentative objects (like the virtual blob object that represents the
working tree file used by "git blame").

* ps/odb-in-memory:
  t/unit-tests: add tests for the in-memory object source
  odb: generic in-memory source
  odb/source-inmemory: stub out remaining functions
  odb/source-inmemory: implement `freshen_object()` callback
  odb/source-inmemory: implement `count_objects()` callback
  odb/source-inmemory: implement `find_abbrev_len()` callback
  odb/source-inmemory: implement `for_each_object()` callback
  odb/source-inmemory: convert to use oidtree
  oidtree: add ability to store data
  cbtree: allow using arbitrary wrapper structures for nodes
  odb/source-inmemory: implement `write_object_stream()` callback
  odb/source-inmemory: implement `write_object()` callback
  odb/source-inmemory: implement `read_object_stream()` callback
  odb/source-inmemory: implement `read_object_info()` callback
  odb: fix unnecessary call to `find_cached_object()`
  odb/source-inmemory: implement `free()` callback
  odb: introduce "in-memory" source

6 days agoMerge branch 'jt/odb-transaction-write'
Junio C Hamano [Wed, 27 May 2026 05:15:45 +0000 (14:15 +0900)] 
Merge branch 'jt/odb-transaction-write'

ODB transaction interface is being reworked to explicitly handle
object writes.

* jt/odb-transaction-write:
  odb/transaction: make `write_object_stream()` pluggable
  object-file: generalize packfile writes to use odb_write_stream
  object-file: avoid fd seekback by checking object size upfront
  object-file: remove flags from transaction packfile writes
  odb: update `struct odb_write_stream` read() callback
  odb/transaction: use pluggable `begin_transaction()`
  odb: split `struct odb_transaction` into separate header

6 days agoMerge branch 'tb/incremental-midx-part-3.3'
Junio C Hamano [Wed, 27 May 2026 05:15:45 +0000 (14:15 +0900)] 
Merge branch 'tb/incremental-midx-part-3.3'

The repacking code has been refactored and compaction of MIDX layers
have been implemented, and incremental strategy that does not require
all-into-one repacking has been introduced.

* tb/incremental-midx-part-3.3:
  repack: allow `--write-midx=incremental` without `--geometric`
  repack: introduce `--write-midx=incremental`
  repack: implement incremental MIDX repacking
  packfile: ensure `close_pack_revindex()` frees in-memory revindex
  builtin/repack.c: convert `--write-midx` to an `OPT_CALLBACK`
  repack-geometry: prepare for incremental MIDX repacking
  repack-midx: extract `repack_fill_midx_stdin_packs()`
  repack-midx: factor out `repack_prepare_midx_command()`
  midx: expose `midx_layer_contains_pack()`
  repack: track the ODB source via existing_packs
  midx: support custom `--base` for incremental MIDX writes
  midx: introduce `--no-write-chain-file` for incremental MIDX writes
  midx: use `strvec` for `keep_hashes`
  midx: build `keep_hashes` array in order
  midx: use `strset` for retained MIDX files
  midx-write: handle noop writes when converting incremental chains

6 days agoMerge branch 'ds/fetch-negotiation-options'
Junio C Hamano [Wed, 27 May 2026 05:15:45 +0000 (14:15 +0900)] 
Merge branch 'ds/fetch-negotiation-options'

The negotiation tip options in "git fetch" have been reworked to
allow requiring certain refs to be sent as "have" lines, and to
restrict negotiation to a specific set of refs.

* ds/fetch-negotiation-options:
  send-pack: pass negotiation config in push
  remote: add remote.*.negotiationInclude config
  fetch: add --negotiation-include option for negotiation
  negotiator: add have_sent() interface
  remote: add remote.*.negotiationRestrict config
  transport: rename negotiation_tips
  fetch: add --negotiation-restrict option
  t5516: fix test order flakiness

6 days agoMerge branch 'rs/use-builtin-add-overflow-explicitly-on-clang'
Junio C Hamano [Wed, 27 May 2026 05:15:44 +0000 (14:15 +0900)] 
Merge branch 'rs/use-builtin-add-overflow-explicitly-on-clang'

Micro optimization of codepaths that compute allocation sizes carefully.

* rs/use-builtin-add-overflow-explicitly-on-clang:
  use __builtin_add_overflow() in st_add() with Clang
  strbuf: use st_add3() in strbuf_grow()

6 days agoMerge branch 'jk/sq-dequote-cleanup'
Junio C Hamano [Wed, 27 May 2026 05:15:44 +0000 (14:15 +0900)] 
Merge branch 'jk/sq-dequote-cleanup'

Code simplification.

* jk/sq-dequote-cleanup:
  quote: simplify internals of dequoting
  quote: drop sq_dequote_to_argv()
  quote.h: bump strvec forward declaration to the top

6 days agoMerge branch 'kn/refs-fsck-skip-lock-files'
Junio C Hamano [Wed, 27 May 2026 05:15:44 +0000 (14:15 +0900)] 
Merge branch 'kn/refs-fsck-skip-lock-files'

The consistency checks for the files reference backend have been updated
to skip lock files earlier, avoiding unnecessary parsing of
intermediate files.

* kn/refs-fsck-skip-lock-files:
  refs/files: skip lock files during consistency checks

6 days agoMerge branch 'ps/t3903-cover-stash-include-untracked'
Junio C Hamano [Wed, 27 May 2026 05:15:44 +0000 (14:15 +0900)] 
Merge branch 'ps/t3903-cover-stash-include-untracked'

Test coverage has been added to "git stash --include-untracked".

* ps/t3903-cover-stash-include-untracked:
  stash: add coverage for show --include-untracked

6 days agoMerge branch 'kk/merge-octopus-optim'
Junio C Hamano [Wed, 27 May 2026 05:15:44 +0000 (14:15 +0900)] 
Merge branch 'kk/merge-octopus-optim'

The logic to determine that branches in an octopus merge are
independent has been optimized.

* kk/merge-octopus-optim:
  merge: use repo_in_merge_bases for octopus up-to-date check

6 days agoMerge branch 'en/batch-prefetch'
Junio C Hamano [Wed, 27 May 2026 05:15:43 +0000 (14:15 +0900)] 
Merge branch 'en/batch-prefetch'

In a lazy clone, "git cherry" and "git grep" often fetch necessary
blob objects one by one from promisor remotes.  It has been corrected
to collect necessary object names and fetch them in bulk to gain
reasonable performance.

* en/batch-prefetch:
  grep: prefetch necessary blobs
  builtin/log: prefetch necessary blobs for `git cherry`
  patch-ids.h: add missing trailing parenthesis in documentation comment
  promisor-remote: document caller filtering contract

6 days agoMerge branch 'rs/trailer-fold-optim'
Junio C Hamano [Wed, 27 May 2026 05:15:43 +0000 (14:15 +0900)] 
Merge branch 'rs/trailer-fold-optim'

Code simplification.

* rs/trailer-fold-optim:
  trailer: change strbuf in-place in unfold_value()

6 days agoMerge branch 'pb/doc-diff-format-updates'
Junio C Hamano [Wed, 27 May 2026 05:15:43 +0000 (14:15 +0900)] 
Merge branch 'pb/doc-diff-format-updates'

Doc updates.

* pb/doc-diff-format-updates:
  diff-format.adoc: mode and hash are 0* for unmerged paths from index only
  diff-format.adoc: 'git diff-files' prints two lines for unmerged files
  diff-format.adoc: remove mention of diff-tree specific output

6 days agoMerge branch 'kk/limit-list-optim'
Junio C Hamano [Wed, 27 May 2026 05:15:43 +0000 (14:15 +0900)] 
Merge branch 'kk/limit-list-optim'

The limit_list() function that is one of the core part of the
revision traversal infrastructure has been optimized by replacing
its use of linear list with priority queue.

* kk/limit-list-optim:
  revision: use priority queue in limit_list()

6 days agoMerge branch 'tb/pseudo-merge-bugfixes'
Junio C Hamano [Wed, 27 May 2026 05:15:43 +0000 (14:15 +0900)] 
Merge branch 'tb/pseudo-merge-bugfixes'

Fixes many bugs in pseudo-merge code.

* tb/pseudo-merge-bugfixes:
  pack-bitmap: prevent pattern leak on pseudo-merge re-assignment
  Documentation: fix broken `sampleRate` in gitpacking(7)
  pack-bitmap: reject pseudo-merge "sampleRate" of 0
  pack-bitmap: parse commits in `find_pseudo_merge_group_for_ref()`
  pack-bitmap: fix pseudo-merge lookup for shared commits
  pack-bitmap: fix inverted binary search in `pseudo_merge_at()`
  pack-bitmap-write: sort pseudo-merge commit lookup table in pack order
  t5333: demonstrate various pseudo-merge bugs
  t/helper: add 'test-tool bitmap write' subcommand

8 days agoThe 8th batch
Junio C Hamano [Mon, 25 May 2026 00:39:50 +0000 (09:39 +0900)] 
The 8th batch

Signed-off-by: Junio C Hamano <gitster@pobox.com>
8 days agoMerge branch 'jk/dumb-http-alternate-fix'
Junio C Hamano [Mon, 25 May 2026 00:40:08 +0000 (09:40 +0900)] 
Merge branch 'jk/dumb-http-alternate-fix'

The HTTP walker misinterpreted the alternates file that gives an
absolute path when the server URL does not have the final slash
(i.e., "https://example.com" not "https://example.com/").

* jk/dumb-http-alternate-fix:
  http: handle absolute-path alternates from server root

8 days agoMerge branch 'jk/pretty-no-strbuf-presizing'
Junio C Hamano [Mon, 25 May 2026 00:40:08 +0000 (09:40 +0900)] 
Merge branch 'jk/pretty-no-strbuf-presizing'

Remove ineffective strbuf presizing that would have computed an
allocation that would not have fit in the available memory anyway,
or too small due to integer wraparound to cause immediate automatic
growing.

* jk/pretty-no-strbuf-presizing:
  pretty: drop strbuf pre-sizing from add_rfc2047()

8 days agoMerge branch 'ag/sequencer-remove-unused-struct-member'
Junio C Hamano [Mon, 25 May 2026 00:40:07 +0000 (09:40 +0900)] 
Merge branch 'ag/sequencer-remove-unused-struct-member'

Code clean-up.

* ag/sequencer-remove-unused-struct-member:
  sequencer: remove todo_add_branch_context.commit

8 days agoMerge branch 'mm/diff-U-takes-no-negative-values'
Junio C Hamano [Mon, 25 May 2026 00:40:07 +0000 (09:40 +0900)] 
Merge branch 'mm/diff-U-takes-no-negative-values'

The command line parser for "git diff" learned a few options take
only non-negative integers.

* mm/diff-U-takes-no-negative-values:
  parse-options: clarify what "negated" means for PARSE_OPT_NONEG
  xdiff: guard against negative context lengths
  diff: reject negative values for -U/--unified
  diff: reject negative values for --inter-hunk-context

8 days agoMerge branch 'dk/doc-exclude-is-shared-per-repo'
Junio C Hamano [Mon, 25 May 2026 00:40:07 +0000 (09:40 +0900)] 
Merge branch 'dk/doc-exclude-is-shared-per-repo'

Document the fact that .git/info/exclude is shared across worktrees
linked to the same repository.

* dk/doc-exclude-is-shared-per-repo:
  ignore: note info/exclude lives in GIT_COMMON_DIR, not GIT_DIR

8 days agoMerge branch 'kk/paint-down-to-common-optim'
Junio C Hamano [Mon, 25 May 2026 00:40:07 +0000 (09:40 +0900)] 
Merge branch 'kk/paint-down-to-common-optim'

"git merge-base" optimization.

* kk/paint-down-to-common-optim:
  commit-reach: early exit paint_down_to_common for single merge-base
  commit-reach: introduce merge_base_flags enum

9 days agopath-walk: support `combine` filter
Taylor Blau [Fri, 22 May 2026 18:24:37 +0000 (18:24 +0000)] 
path-walk: support `combine` filter

The `combine` filter takes the intersection of its children, that is:
objects are shown only when all child filters would admit the object.

The preceding patches added support for many individual filter types.
Enable users to compose these filters by implementing support for the
`combine` filter type.

Mapping intersection onto path_walk_info works because every supported
child filter is a monotonic restriction:

 - `blob:none`, `tree:0` unconditionally clear `info->blobs` and (for
   `tree:0`) `info->trees`; clearing an already-cleared flag is a
   no-op.

 - `object:type=X` is now expressed as an AND of each type flag with the
   filtered type, so applying multiple such filters only refines the
   existing set rather than overwrites it.

 - `blob:limit=N` has to compose too: the intersection of "size < L1"
   and "size < L2" is "size < min(L1, L2)".

   Update the `LOFC_BLOB_LIMIT` handler to take the running minimum when
   `info->blob_limit` is already set, so a combined filter with, e.g.,
   both "blob:limit=10" and "blob:limit=5" produces a limit of 5
   regardless of ordering.

 - `sparse:oid` is left unchanged. A `combine` filter that includes a
   `sparse:oid` is allowed at most once, since the existing handler
   refuses to overwrite `info->pl`. Two `sparse:oid` filters in a single
   `combine` would be unusual and are rejected with a warning, matching
   the standalone `sparse:oid` behavior.

Implementation-wise, the existing `prepare_filters()` called
`list_objects_filter_release()` inside each case branch. That works fine for
top-level filters, but `combine` filters need to recurse over its child
filters without releasing each one in turn (since the parent's release
iterates the sub array). Split `prepare_filters()` into a recursive helper
that performs only the mutation, plus a thin wrapper that calls the helper
and then releases the top-level filter once.

The `LOFC_COMBINE` case in the helper just walks `sub_nr` and recurses;
child filters are released by the wrapper's single
`list_objects_filter_release()` call on the parent (which itself recursively
releases each sub-filter, the same way it always has).

If any sub-filter is unsupported (e.g. "tree:1", "sparse:<path>", or a
not-yet-supported choice), the recursion bubbles a failure up and the
existing pack-objects/backfill fallback paths kick in.

Add coverage in t6601:

  - "combine:blob:none+tree:0" collapses to "tree:0"

  - "combine:object:type=blob+blob:limit=3" yields only the blobs
    smaller than three bytes

  - "combine:object:type=blob+object:type=tree" intersects to empty

  - "combine:tree:1+blob:none" reports the "tree:1" error.

Update Documentation/git-pack-objects.adoc to add combine to the
list of supported --filter forms.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
9 days agopath-walk: support `object:type` filter
Taylor Blau [Fri, 22 May 2026 18:24:36 +0000 (18:24 +0000)] 
path-walk: support `object:type` filter

The `object:type` filter accepts only objects of a single type; it is
the second member of the object-info-only filter family that bitmap
traversal already supports.

Like `blob:none` and `tree:0`, it can be evaluated with nothing more
than the object's type, which is exactly the granularity path-walk's
existing info->{commits,trees,blobs,tags} flags already control.

Map `LOFC_OBJECT_TYPE` in `prepare_filters()` by AND-ing each flag
against the filtered type. A single `object:type=X` filter
applied to the default info (all flags = 1) leaves `info->X = 1` and
all the others 0, which is what we want.

Using an AND rather than straight assignment prepares us for a
subsequent change to implement combined object filters.

The path-walk machinery is mostly already wired for the per-type
distinction:

 - `walk_path()` calls `path_fn` for a batch only when the corresponding
   `info->X` flag is set, so unwanted types are silently not reported.

 - `add_tree_entries()` skips tree entries of type `OBJ_BLOB` when
   `info->blobs` is unset, so we don't even allocate paths for them.

 - The commit-walk loop short-circuits the root-tree fetch when
   `!info->trees && !info->blobs`, so commit-only filters don't descend
   into trees at all.

But there are a couple of side effects of the "trees off, blobs on" case
that need fixing:

 1. 'setup_pending_objects()' previously skipped pending trees as soon
    as `info->trees` was zero. For 'object:type=blob' the call site
    needs those pending trees: a lightweight tag pointing to a tree, or
    an annotated tag whose peeled target is a tree, can both reach
    blobs that are otherwise unreachable from any commit's root tree.
    Loosen the gate to "if (!info->trees && !info->blobs) continue" and
    similarly retrieve the root_tree_list whenever either trees or
    blobs are wanted.

 2. The revision machinery's `handle_commit()` drops pending trees when
    `revs->tree_objects` is zero (see the 'OBJ_TREE' handler in
    revision.c), so by the time path-walk sees the pending list
    after `prepare_revision_walk()` the tree-bearing pendings would
    already be gone. Fix this by setting

        revs->tree_objects = info->trees || info->blobs

    so pending trees survive `prepare_revision_walk()` whenever we
    need to walk into them. Path-walk still resets tree_objects to
    zero immediately after `prepare_revision_walk()` returns, so the
    rev-walk itself never enumerates trees redundantly with
    path-walk's own descent.

Add coverage in t6601 for each of the four `object:type` values. The
'object:type=blob' test in particular asserts that file2 and child/file
(both reachable only through tag-pointed trees) show up in the output,
exercising the pending-tree fix.

Update Documentation/git-pack-objects.adoc to add object:type to
the list of supported --filter forms.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
9 days agopath-walk: support `tree:0` filter
Taylor Blau [Fri, 22 May 2026 18:24:35 +0000 (18:24 +0000)] 
path-walk: support `tree:0` filter

The `tree:0` object filter omits all trees and blobs from the result,
keeping only commits and tags. Consequently, this filter type should
has a fairly straightforward integration with path-walk, as the decision
to include an object depends only on its type and does not depend on any
path-sensitive state.

Mapping it onto `path_walk_info` is direct: set `info->trees = 0` and
`info->blobs = 0` in `prepare_filters()` when the `LOFC_TREE_DEPTH`
choice is requested with depth zero. The existing code already plumbs
those flags through the rest of the walk:

 - 'walk_objects_by_path()' sets `revs->blob_objects = info->blobs` and
   `revs->tree_objects = info->trees` before `prepare_revision_walk()`,
   so the revision walk doesn't try to enumerate trees or blobs itself.

 - The commit-walk loop short-circuits the root-tree fetch with
   "if (!info->trees && !info->blobs) continue;", so we never even
   look up the root tree, let alone descend into it.

 - `setup_pending_objects()` skips pending trees and blobs based on
   the same flags.

This means the path-walk doesn't allocate or expand any tree structures
at all under `tree:0`, which matches the intended behavior of the
filter.

However, this requires first fixing some issues with how the path-walk
API handles directly-requested trees _and_ trees requested through
lightweight tags. These changes create substantial updates to
t6601-path-walk.sh, which the previous change highlighted as a problem
by tagging otherwise-unreachable trees and having them not appear in the
output.

Non-zero tree-depth filters are not supported. Those depend on the depth
at which a tree is visited, which is a path-walk concept the filter
machinery doesn't currently share with the path-walk API. Reject them in
`prepare_filters()` with a helpful error and let pack-objects fall back
to the regular traversal, the same way it already does for unsupported
filters.

Add coverage in t6601 for both `--all` and a single-branch case to
confirm that no trees or blobs are emitted, and a separate test that
`tree:1` is rejected with the expected error message. Place the new
tests before "setup sparse filter blob" so they run on the original set
of refs, before the orphan branch that the sparse-tree tests create.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
9 days agot6601: tag otherwise-unreachable trees
Derrick Stolee [Fri, 22 May 2026 18:24:34 +0000 (18:24 +0000)] 
t6601: tag otherwise-unreachable trees

The tests in t6601-path-walk.sh demonstrate the behavior of the
path-walk API under different conditions. One thing that I noticed while
updating the behavior of directly-requested objects is that we don't
actually emit tagged trees. This was previously not noticed due to those
tagged trees actually being reachable from commits that we are including
in the path-walk.

Update the test setup to have tree-tag and tree-tag2 point to trees that
are otherwise unreachable.

It is worth noting that this does not meaningfully change any of the
other test cases, demontrating the bug.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
9 days agopack-objects: support sparse:oid filter with path-walk
Derrick Stolee [Fri, 22 May 2026 18:24:33 +0000 (18:24 +0000)] 
pack-objects: support sparse:oid filter with path-walk

The --filter=sparse:<oid> option to 'git pack-objects' allows focusing
an object set to a sparse-checkout definition. This reduces the set of
matching blobs while retaining all reachable trees. No server currently
supports fetching with this filter because it is expensive to compute
and reachability bitmaps do not help without a significant effort to
extend the bitmap feature to store bitmaps for each supported sparse-
checkout definition.

Without focusing on serving fetches and clones with these filters, there
are still benefits that could be realized by making this faster. With
the sparse index, it's more realistic now than ever to be able to
operate a local clone that was bootstrapped by a packfile created with
a sparse filter, because the missing trees are not needed to move a
sparse-checkout from one commit to another or to view the history of any
path in scope. Such clones could perhaps be bootstrapped by partial
bundles.

Previously, constructing these sparse packs has been incredibly
computationally inefficient. The revision walk that explores which
objects are in scope spends a lot of time checking each object to see if
it matches the sparse-checkout patterns, causing quadratic behavior
(number of objects times number of sparse-checkout patterns). This
improves somewhat when using cone-mode sparse-checkout patterns that can
use hashtables and prefix matches to determine containment. However, the
check per object is still too expensive for most cases.

This is where the path-walk feature comes in. We can proceed as normal
by placing objects in bins by path and _then_ check a group of objects
all at once. Since sparse:<oid> only restricts blobs, the path-walk must
include all reachable trees while using the cone-mode patterns to skip
blobs at paths outside the sparse scope. This establishes a baseline for
a potential future "treesparse:<oid>" filter that would also restrict
trees, but introducing such a new filter is deferred to a later change.

The implementation here is focused around loading the sparse-checkout
patterns from the provided object ID and checking that the patterns are
indeed cone-mode patterns. We can then load the correct pattern list
into the path walk context and use the logic that already exists from
bff45557675 (backfill: add --sparse option, 2025-02-03), though that
feature loads sparse-checkout patterns from the worktree's local
settings and also restricts tree objects. We use a combination of errors
and warnings to signal problems during this load. The difference is that
errors are likely fatal for the non-path-walk version while the warnings
are probably just implementation details for the path-walk version and
the 'git pack-objects' command can fall back to the revision walk
version.

Now that the SEEN flag is deferred until after pattern checks (from the
previous commit), handle the case where a tree with a shared OID appears
at both an out-of-cone and in-cone path. When trees are not being pruned
(pl_sparse_trees == 0), the path-walk re-walks the tree at the in-cone
path so that in-cone blobs within it are discovered. The new tests in
t5317 and t6601 demonstrate this behavior and would fail without these
changes.

The performance test p5315 shows the impact of this change when using
sparse filters:

Test                                              HEAD~1     HEAD
----------------------------------------------------------------------
5315.10: repack (sparse:oid)                      77.98    77.47  -0.7%
5315.11: repack size (sparse:oid)                187.5M   187.4M  -0.0%
5315.12: repack (sparse:oid, --path-walk)         77.91    31.41 -59.7%
5315.13: repack size (sparse:oid, --path-walk)   187.5M   161.1M -14.1%

These performance tests were run on the Git repository. The --path-walk
feature shows meaningful space savings (14% smaller for sparse packs)
and dramatic time savings (60% faster) by leveraging the path-walk's
ability to skip blobs outside the sparse scope.

Co-authored-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Taylor Blaue <me@ttaylorr.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
9 days agopath-walk: add pl_sparse_trees to control tree pruning
Derrick Stolee [Fri, 22 May 2026 18:24:32 +0000 (18:24 +0000)] 
path-walk: add pl_sparse_trees to control tree pruning

The path-walk API prunes trees and blobs when a sparse-checkout pattern
list is provided, which is the correct behavior for 'git backfill
--sparse' since it only needs to fill in objects at paths within the
sparse cone.

However, a future change will use the path-walk API with a sparse:<oid>
filter that restricts only blobs while retaining all reachable trees.
To support both behaviors, add a 'pl_sparse_trees' flag to
path_walk_info. When set (as in 'git backfill --sparse' and the
--stdin-pl test helper mode), the sparse patterns prune both trees and
blobs. When unset, only blobs are filtered and all trees are walked and
reported.

Additionally, move the SEEN flag assignment in add_tree_entries() to
after the sparse pattern and pathspec checks. Previously, SEEN was set
immediately upon discovering an object, before checking whether its path
matched the sparse patterns. When the same object ID appeared at
multiple paths (e.g. sibling directories with identical contents), the
first path to be visited would mark the object as SEEN. If that path was
outside the sparse cone, the object would be skipped there but also
never discovered at its in-cone path.

By deferring the SEEN flag until after the checks pass, objects that are
skipped due to sparse filtering remain discoverable at other paths where
they may be in scope.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
9 days agopath-walk: support blob size limit filter
Derrick Stolee [Fri, 22 May 2026 18:24:31 +0000 (18:24 +0000)] 
path-walk: support blob size limit filter

Extend the path-walk API to handle the 'blob:limit=<size>' object
filter natively. This filter omits blobs whose size is equal to or
greater than the given limit, matching the semantics used by the
list-objects-filter machinery.

When revs->filter.choice is LOFC_BLOB_LIMIT, the prepare_filters()
method stores the limit value in info->blob_limit and clears the filter
from revs. If the limit is zero, this degenerates to blob:none (all
blobs excluded), so info->blobs is set to 0 instead.

During walk_path(), blob batches are filtered before being delivered to
the callback: each blob's size is checked via odb_read_object_info(),
and only blobs strictly smaller than the limit are included. Blobs whose
size cannot be determined (e.g. missing in a partial clone) are
conservatively included, matching the existing filter behavior. Empty
batches after filtering are skipped entirely.

The check for inclusion in the path batch looks a little strange at
first glance. We use odb_read_object_info() to read the object's size.
Based on all of the assumptions to this point, this _should_ return
OBJ_BLOB. Since we are focused on the size filter, we use a
short-circuited OR (||) to skip the size check if that method returns a
different object type.

Notice that this inspection of object sizes requires the content to be
present in the repository. The odb_read_object_info() call will download
a missing blob on-demand. This means that the use of the path-walk API
within 'git backfill' would not operate nicely with this filter type.
The intention of that command is to download missing blobs in batches.
Downloading objects one-by-one would go against the point. Update the
validation in 'git backfill' to add its own compatibility check on top
of path_walk_filter_compatible().

Add tests for blob:limit=0 (equivalent to blob:none) and blob:limit=3
(which exercises partial filtering within a batch where some blobs are
kept and others are excluded).

Co-authored-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
9 days agobackfill: die on incompatible filter options
Derrick Stolee [Fri, 22 May 2026 18:24:30 +0000 (18:24 +0000)] 
backfill: die on incompatible filter options

The 'git backfill' command uses the path-walk API in a critical way: it
uses the objects output from the command to find the batches of missing
objects that should be requested from the server. Unlike 'git
pack-objects', we cannot fall back to another mechanism.

The previous change added the path_walk_filter_compatible() method that
we can reuse here. Use it during argument validation in cmd_backfill().

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
9 days agopath-walk: support blobless filter
Derrick Stolee [Fri, 22 May 2026 18:24:29 +0000 (18:24 +0000)] 
path-walk: support blobless filter

The 'git pack-objects' command can opt-in to using the path-walk API for
scanning the objects. Currently, this option is dynamically disabled if
combined with '--filter=<X>', even when using a simple filter such as
'blob:none' to signal a blobless packfile. This is a common scenario for
repos at scale, so is worth integrating.

Also, users can opt-in to the '--path-walk' option by default through
the pack.usePathWalk=true config option. When using that in a blobless
partial clone, the following warning can appear even though the user did
not specify either option directly:

  warning: cannot use --filter with --path-walk

Teach the path-walk API to handle the 'blob:none' object filter
natively. When revs->filter.choice is LOFC_BLOB_NONE, the path-walk
sets info->blobs to 0 (skipping all blob objects) and clears the
filter from revs so that prepare_revision_walk() does not reject the
configuration.

This check is implemented in the static prepare_filters() method, which
will simultaneously check if the input filters are compatible and will
make the appropriate mutations to the path_walk_info and filters if the
path_walk_info is non-NULL. This allows us to use this logic both in the
API method path_walk_filter_compatible() for use in
builtin/pack-objects.c and as a prep step in walk_objects_by_path().

Update the test helper (test-path-walk) to accept --filter=<spec>
as a test-tool option (before '--'), applying it to revs after
setup_revisions() to avoid the --objects requirement check. We can also
revert recent GIT_TEST_PACK_PATH_WALK overrides in t5620.

Also switch test-path-walk from REV_INFO_INIT with manual repo
assignment to repo_init_revisions(), which properly initializes
the filter_spec strbuf needed for filter parsing.

Add tests for blob:none with --all and with a single branch.

The performance test p5315 shows the impact of this change when using
blobless filters:

Test                                           HEAD~1     HEAD
---------------------------------------------------------------------
5315.6: repack (blob:none)                      13.53   13.87  +2.5%
5315.7: repack size (blob:none)                137.7M  137.8M  +0.1%
5315.8: repack (blob:none, --path-walk)         13.51   23.43 +73.4%
5315.9: repack size (blob:none, --path-walk)   137.7M  115.2M -16.3%

These performance tests were run on the Git repository. The --path-walk
feature shows meaningful space savings (16% smaller for blobless packs)
at the cost of increased computation time due to the two compression
passes. This data demonstrates that the feature is engaged and provides
real compression benefits when --no-reuse-delta forces fresh deltas.

Co-Authored-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
9 days agopath-walk: always emit directly-requested objects
Derrick Stolee [Fri, 22 May 2026 18:24:28 +0000 (18:24 +0000)] 
path-walk: always emit directly-requested objects

We are preparing to integrate the path-walk API with some --filter options
in 'git pack-objects', but there is a subtle issue that is revealed when
those are put together and the test suite is run with
GIT_TEST_PACK_PATH_WALK=1.

When a filter reduces the set of requested objects, this results in
filtering out directly-requested objects, such as in the download of needed
blobs in a blobless partial clone.

The root cause is that the scan of pending objects in the path-walk API
respects the filters set in the path_walk_info instead of overriding them
for pending objects.

We can tell that a path is part of the directly-referenced objects if its
path name starts with '/' (other paths, including root trees never have this
starting character). Create a path_is_for_direct_objects() to make this
meaning clear, especially as we add more references in the future as we
integrate the path-walk API with partial clone filter options.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
9 days agot/perf: add pack-objects filter and path-walk benchmark
Derrick Stolee [Fri, 22 May 2026 18:24:27 +0000 (18:24 +0000)] 
t/perf: add pack-objects filter and path-walk benchmark

Add p5315-pack-objects-filter.sh to measure the performance of
'git pack-objects --revs --all' under different filter and traversal
combinations:

 * no filter (baseline)
 * --filter=blob:none (blobless)
 * --filter=sparse:oid=<oid> (cone-mode sparse)

Each filter scenario is tested both with and without --path-walk,
producing paired measurements that show the impact of the path-walk
traversal for each filter type as we integrate the --path-walk feature
with different --filter options. It currently has no integration so
falls back to the standard revision walk. Thus, there are no significant
differences in the current results other than a full repack (and even
then, the --path-walk feature is not incredibly different for the
default Git repository):

Test                                             HEAD
-----------------------------------------------------
5315.2: repack (no filter)                      27.91
5315.3: repack size (no filter)                250.7M
5315.4: repack (no filter, --path-walk)         34.92
5315.5: repack size (no filter, --path-walk)   220.0M
5315.6: repack (blob:none)                      13.63
5315.7: repack size (blob:none)                137.6M
5315.8: repack (blob:none, --path-walk)         13.48
5315.9: repack size (blob:none, --path-walk)   137.7M
5315.10: repack (sparse:oid)                    72.67
5315.11: repack size (sparse:oid)              187.4M
5315.12: repack (sparse:oid, --path-walk)       72.47
5315.13: repack size (sparse:oid, --path-walk) 187.4M

The sparse filter definition is built automatically by sampling
depth-2 directories from the test repository, making the test work
on any repo passed via GIT_PERF_LARGE_REPO. For repos that lack
depth-2 directories, a single top-level directory is used; for flat
repos, the sparse tests are skipped via prerequisite.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
9 days agopack-objects: pass --objects with --path-walk
Derrick Stolee [Fri, 22 May 2026 18:24:26 +0000 (18:24 +0000)] 
pack-objects: pass --objects with --path-walk

When 'git pack-objects' has the --path-walk option enabled, it uses a
different set of revision walk parameters than normal. For one,
--objects was previously assumed by the path-walk API and could be
omitted. We also needed --boundary to allow discovering UNINTERESTING
objects to use as delta bases.

We will be updating the path-walk API soon to work with some filter
options. However, the revision machinery will trigger a fatal error:

  fatal: object filtering requires --objects

The fix is easy: add the --objects option as an argument. This has no
effect on the path-walk API but does simplify the revision option
parsing for the objects filter.

We can remove the comment about "removing" the options because they were
never removed and instead not added. We still need to disable using
bitmaps.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
9 days agot5620: make test work with path-walk var
Derrick Stolee [Fri, 22 May 2026 18:24:25 +0000 (18:24 +0000)] 
t5620: make test work with path-walk var

The GIT_TEST_PACK_PATH_WALK test variable allows enabling the
--path-walk option to 'git pack-objects' by default. This sometimes
engages the warning that --path-walk is incompatible with the --filter
option. These tests in t5620 fail due to this warning over stderr in
this case. Disable this variable for this moment until these options
work together.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
11 days agotransport-helper: fix typo in BUG() message
Jeff King [Fri, 22 May 2026 04:43:52 +0000 (00:43 -0400)] 
transport-helper: fix typo in BUG() message

We mistakenly refer to the git_connect_service enum as "_type" rather
than "_service". Users should never see this message in practice, but it
is slightly confusing when reading the code.

Reported-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
11 days agodoc: hook: don’t self-link via config include
Kristoffer Haugsbakk [Thu, 21 May 2026 16:25:58 +0000 (18:25 +0200)] 
doc: hook: don’t self-link via config include

Do not link to git-hook(1) from the config options when we already are
in that doc.

This implementation is similar to the updates to git-init(1) and
git-commit(1), implemented in [1] and [2], respectively.

† 1: e7b3a768 (doc: git-init: rework config item init.templateDir,
     2024-03-10)
† 2: 819fdd6e (doc: convert git commit config to new format, 2025-01-15)

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
11 days agodoc: config: include existing git-hook(1) section
Kristoffer Haugsbakk [Thu, 21 May 2026 16:25:57 +0000 (18:25 +0200)] 
doc: config: include existing git-hook(1) section

It is already included in git-hook(1) but missing from git-config(1).

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
11 days agodoc: hook: consistently capitalize Git
Kristoffer Haugsbakk [Thu, 21 May 2026 16:25:56 +0000 (18:25 +0200)] 
doc: hook: consistently capitalize Git

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
11 days agodoc: hook: remove stray backtick
Kristoffer Haugsbakk [Thu, 21 May 2026 16:25:55 +0000 (18:25 +0200)] 
doc: hook: remove stray backtick

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
11 days agoThe 7th batch
Junio C Hamano [Thu, 21 May 2026 23:47:06 +0000 (08:47 +0900)] 
The 7th batch

With this batch, we have flushed all the topics that need to
be merged to 'maint' to make its build healthy.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
11 days agoMerge branch 'ps/maintenance-daemonize-lockfix'
Junio C Hamano [Thu, 21 May 2026 23:48:20 +0000 (08:48 +0900)] 
Merge branch 'ps/maintenance-daemonize-lockfix'

"git maintenance" that goes background did not use the lockfile to
prevent multiple maintenance processes from running at the same
time, which has been corrected.

* ps/maintenance-daemonize-lockfix:
  run-command: honor "gc.auto" for auto-maintenance
  builtin/maintenance: fix locking with "--detach"

11 days agoMerge branch 'jk/apply-leakfix'
Junio C Hamano [Thu, 21 May 2026 23:48:20 +0000 (08:48 +0900)] 
Merge branch 'jk/apply-leakfix'

Leakfix.

* jk/apply-leakfix:
  apply: plug leak on "patch too large" error

11 days agoMerge branch 'jk/commit-sign-overflow-fix'
Junio C Hamano [Thu, 21 May 2026 23:48:20 +0000 (08:48 +0900)] 
Merge branch 'jk/commit-sign-overflow-fix'

Leakfix.

* jk/commit-sign-overflow-fix:
  commit: handle large commit messages in utf8 verification

12 days agogitlab-ci: update macOS image
Patrick Steinhardt [Thu, 21 May 2026 08:59:25 +0000 (10:59 +0200)] 
gitlab-ci: update macOS image

The GitLab CI jobs for macOS are all using the macOS 15 images. While
these images are not deprecated yet, there is a new image for macOS 26
generally available by now [1].

Switch two of our jobs to use the new image. The third job still
continues to use the old image. This ensures broader test coverage until
this old image gets deprecated.

[1]: https://docs.gitlab.com/ci/runners/hosted_runners/macos/

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agogitlab-ci: upgrade macOS runners
Patrick Steinhardt [Thu, 21 May 2026 08:59:24 +0000 (10:59 +0200)] 
gitlab-ci: upgrade macOS runners

We're currently using M1-based runners for our macOS jobs. GitLab has
since introduced a new M2 Pro-based runner type that is available for
all GitLab tiers [1], which upgrades from 4 to 6 cores and from 8 to 16
GB RAM.

Upgrade to this new runner type, which results in some nice speedups:

  - osx-clang goes from 26 minutes to 16 minutes.

  - osx-meson goes from 19 minutes to 13 minutes.

  - osx-reftable goes from 23 minutes to 14 mintues.

[1]: https://docs.gitlab.com/ci/runners/hosted_runners/macos/

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agoapproxidate: use deferred mday adjustments for "specials"
Tuomas Ahola [Thu, 21 May 2026 10:54:08 +0000 (13:54 +0300)] 
approxidate: use deferred mday adjustments for "specials"

There are cases where the "wrap-to-yesterday" behavior of "tea" and
"noon" should be reverted later on down the line, so that "today tea"
and "tea today" won't yield different results.  However, the logic of
approxidate doesn't seem to lend itself particularly well to
such cases.

Start tackling the issue by reusing negative values of `tm->tm_mday`
field for deferred date adjustments which can be easily reverted, so
that the default logic of the special formats only applies if we don't
get any explicit date (mday) specification.  In particular, overwrite
the field with -1 in "today" and "yesterday", so that those formats will
be relative to the current date.  That makes specifications like "tea
yesterday" behave more sensibly: instead of going backwards to the
last tea-time and then a day back, Git will now understand that as the
tea-time of yesterday.

Replace the call of `update_tm()` in `date_time()` with the assignment
`tm->tm_mday = -2`.  Add the corresponding code to handle that in
`update_tm()`, wrapping to the previous day if the field still holds
such assignment, meaning that we haven't seen any better specification
for the day-of-month.  On the other hand, `mday=-3` would mean going
two days back and so on.  Even though such functionality isn't
actually needed by this patch, it won't add much complexity in the
code and is rather natural way to handle such values.

As `date_time()` won't no longer need the `now` struct, mark the
associated function parameters as unused.  The parameters themselves
have to stay, however, as those functions are called through pointers
in `approxidate_alpha`.  Add relevant tests to cover the changes.

Signed-off-by: Tuomas Ahola <taahol@utu.fi>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agoapproxidate: make "specials" respect fixed day-of-month
Tuomas Ahola [Thu, 21 May 2026 10:54:07 +0000 (13:54 +0300)] 
approxidate: make "specials" respect fixed day-of-month

The special approxidate time formats, "noon" and "tea" differ from
"12pm" and "5pm" by having the feature of wrapping to the previous day
if the current time is before those hours:

now  -> 2026-05-13 11:00:00 +0000

12pm -> 2026-05-13 12:00:00 +0000
5pm  -> 2026-05-13 17:00:00 +0000

noon -> 2026-05-12 12:00:00 +0000
tea  -> 2026-05-12 17:00:00 +0000

However, that logic carries too far.  Even when the date is specified,
the behavior of the "specials" depends on the current time.  Assuming
the same time as above, we get:

today at noon -> 2026-05-12 12:00:00 +0000 (should be 13 May)
13 May at tea -> 2026-05-12 17:00:00 +0000

or, using an example mentioned in date-formats.adoc:

last Friday at noon -> 2026-05-07 12:00:00 +0000 (should be 8 May)

The quirk seems to be rather old.  Already in 2006, Linus Torvalds
remarked that the date yielded by "one year ago yesterday at tea-time"
was "just silly and not even correct".  Indeed, even today it gives:

One year ago yesterday at tea-time -> 2025-05-11 17:00:00 +0000
  (should be 12 May)

Let's fix all of those with a simple patch.  Check whether we already
have a specified day-of-month in `tm->tm_mday` and make `date_time()`
stick to it.  Ensure the correct behavior with relevant tests.

Links:
  1. https://lore.kernel.org/git/Pine.LNX.4.64.0610101102560.3952@g5.osdl.org/

Signed-off-by: Tuomas Ahola <taahol@utu.fi>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agot0006: add support for approxidate test date adjustment
Tuomas Ahola [Thu, 21 May 2026 10:54:06 +0000 (13:54 +0300)] 
t0006: add support for approxidate test date adjustment

t0006 uses a hard-coded test date and provides no convenient
way to override it temporarily.  Add an optional parameter to
check_approxidate to adjust the time as needed, and demonstrate
the feature with a new test.

Signed-off-by: Tuomas Ahola <taahol@utu.fi>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agoapproxidate: make "today" wrap to midnight
Tuomas Ahola [Thu, 21 May 2026 10:54:05 +0000 (13:54 +0300)] 
approxidate: make "today" wrap to midnight

Although some commands do reject invalid approxidate expressions,
in other cases those are simply evaluated as the current time.
Oftentimes that is a perfectly good compromise to handle silly
requests, but it isn't without rough edges.

Because of the silent acceptance, it is easy to forget that
"today" isn't actually a valid approxidate format.  That is
a bit awkward because while the fallback logic of using the
current time does make some sense, there is no deliberative
decision behind such behavior of "today".  Indeed, whatever
(non-)action "today" currently has, is just an accidental
side effect.

That means "git log --since=today" is currently unlikely to
print anything at all as it tries to list commits dated with
*future* timestamps.  Arguably it would be more useful to
list the commits of the current day---i.e. those made since
midnight.

On the other hand, "git log --until=today" doesn't really
filter commits at all.  Changing the definition of "today"
would make it return the commits made before the current day.
That isn't without problems though---running "git log
--until=today" in the late afternoon could reasonably include
the work done earlier that day (as the command currently
does do).

Still the utility of no-op "--until=today" is debatable and
perhaps outweighed by the pros of having "--since=today" to
mean "--since=midnight".  The thing is that the approxidate
machinery doesn't know about its consumers, so the meaning
of "today" has to be the same for "--since" and "--until".

In fact, "git log --until=" is documented as

`--until=<date>`::
`--before=<date>`::
Show commits older than _<date>_,

so excluding commits made today would actually match the
documentation more closely.

Moreover, a revision parameter "@{today}" is currently outright
rejected.  Making "today" a valid approxidate time format could
make a natural way to specify the state of the ref at the start
of the current day.

Bind "today" to new function `date_today()` as an approxidate
special.  Make it return the last midnight if no specific time
is given; i.e. retain the old behavior of "noon today" and such.

Document the new behavior of "git log --since=today" in
rev-list-options.adoc.

Signed-off-by: Tuomas Ahola <taahol@utu.fi>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agoDocumentation/git-range-diff: add missing notes options in synopsis
Siddh Raman Pant [Thu, 21 May 2026 05:28:41 +0000 (10:58 +0530)] 
Documentation/git-range-diff: add missing notes options in synopsis

git-range-diff supports note options which are also mentioned later in
the help, but they are missing from the synopsis. Let's fix that.

Signed-off-by: Siddh Raman Pant <siddh.raman.pant@oracle.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agoSync with 'maint'
Junio C Hamano [Thu, 21 May 2026 03:45:24 +0000 (12:45 +0900)] 
Sync with 'maint'

12 days agoStart preparing for 2.54.1 maint
Junio C Hamano [Thu, 21 May 2026 03:40:38 +0000 (12:40 +0900)] 
Start preparing for 2.54.1

Mostly build and CI related updates taken from the 'master' front
are included in here.

We still need to grab a couple more topics once they graduate to
'master', namely

    jk/apply-leakfix
    jk/commit-sign-overflow-fix

Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agoMerge branch 'jc/t5551-fix-expensive' into maint-2.54
Junio C Hamano [Thu, 21 May 2026 03:30:40 +0000 (12:30 +0900)] 
Merge branch 'jc/t5551-fix-expensive' into maint-2.54

Test fix.

* jc/t5551-fix-expensive:
  t5551: "GIT_TEST_LONG=Yes make test" is broken

12 days agoMerge branch 'jh/alias-i18n-fixes' into maint-2.54
Junio C Hamano [Thu, 21 May 2026 03:30:11 +0000 (12:30 +0900)] 
Merge branch 'jh/alias-i18n-fixes' into maint-2.54

Further update to the i18n alias support to avoid regressions.

* jh/alias-i18n-fixes:
  alias: restore support for simple dotted aliases

12 days agoMerge branch 'js/mingw-no-nedmalloc' into maint-2.54
Junio C Hamano [Thu, 21 May 2026 03:28:55 +0000 (12:28 +0900)] 
Merge branch 'js/mingw-no-nedmalloc' into maint-2.54

Stop using unmaintained custom allocator in Windows build which was
the last user of the code.

* js/mingw-no-nedmalloc:
  mingw: remove the vendored compat/nedmalloc/ subtree
  mingw: drop the build-system plumbing for nedmalloc
  mingw: stop using nedmalloc

12 days agoMerge branch 'js/maintenance-fix-deadlock-on-win10' into maint-2.54
Junio C Hamano [Thu, 21 May 2026 03:27:47 +0000 (12:27 +0900)] 
Merge branch 'js/maintenance-fix-deadlock-on-win10' into maint-2.54

To help Windows 10 installations, avoid removing files whose
contents are still mmap()'ed.

* js/maintenance-fix-deadlock-on-win10:
  maintenance(geometric): do release the `.idx` files before repacking
  mingw: optionally use legacy (non-POSIX) delete semantics

12 days agoMerge branch 'js/t5564-socks-use-short-path' into maint-2.54
Junio C Hamano [Thu, 21 May 2026 03:27:19 +0000 (12:27 +0900)] 
Merge branch 'js/t5564-socks-use-short-path' into maint-2.54

Avoid hitting the pathname limit for socks proxy socket during the
test.

* js/t5564-socks-use-short-path:
  t5564: use a short path for the SOCKS proxy socket

12 days agoMerge branch 'js/ci-github-actions-update' into maint-2.54
Junio C Hamano [Thu, 21 May 2026 03:26:28 +0000 (12:26 +0900)] 
Merge branch 'js/ci-github-actions-update' into maint-2.54

Update various GitHub Actions versions.

* js/ci-github-actions-update:
  l10n: bump mshick/add-pr-comment from v2 to v3
  ci: bump git-for-windows/setup-git-for-windows-sdk from v1 to v2
  ci: bump actions/checkout from v5 to v6
  ci: bump actions/github-script from v8 to v9
  ci: bump actions/{upload,download}-artifact to v7 and v8
  ci: bump microsoft/setup-msbuild from v2 to v3

12 days agoMerge branch 'jk/revert-aa-reap-transport-child-processes' into maint-2.54
Junio C Hamano [Thu, 21 May 2026 03:25:55 +0000 (12:25 +0900)] 
Merge branch 'jk/revert-aa-reap-transport-child-processes' into maint-2.54

Revert a recent change that introduced a regression to help mksh users.

* jk/revert-aa-reap-transport-child-processes:
  Revert "transport-helper, connect: use clean_on_exit to reap children on abnormal exit"

12 days agoMerge branch 'ps/clang-w-glibc-2.43-and-_Generic' into maint-2.54
Junio C Hamano [Thu, 21 May 2026 03:23:50 +0000 (12:23 +0900)] 
Merge branch 'ps/clang-w-glibc-2.43-and-_Generic' into maint-2.54

Headers from glibc 2.43 when used with clang does not allow
disabling C11 language features, causing build failures..

* ps/clang-w-glibc-2.43-and-_Generic:
  build: tolerate use of _Generic from glibc 2.43 with Clang

12 days agoThe 6th batch
Junio C Hamano [Thu, 21 May 2026 03:05:44 +0000 (12:05 +0900)] 
The 6th batch

Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 days agoMerge branch 'sp/shallow-deepen-on-non-shallow-repo-fix'
Junio C Hamano [Thu, 21 May 2026 03:06:49 +0000 (12:06 +0900)] 
Merge branch 'sp/shallow-deepen-on-non-shallow-repo-fix'

"git fetch --deepen=<n>" in a full clone truncated the history to <n>
commits deep, which has been corrected to be a no-op instead.

* sp/shallow-deepen-on-non-shallow-repo-fix:
  shallow: fix relative deepen on non-shallow repositories

12 days agoMerge branch 'jc/ci-enable-expensive'
Junio C Hamano [Thu, 21 May 2026 03:06:48 +0000 (12:06 +0900)] 
Merge branch 'jc/ci-enable-expensive'

Enable expensive tests to catch topics that may cause breakages on
integration branches closer to their origin in the contributor PR
builds.

* jc/ci-enable-expensive:
  ci: enable EXPENSIVE for contributor builds

12 days agoMerge branch 'aw/validate-proxy-url-scheme'
Junio C Hamano [Thu, 21 May 2026 03:06:48 +0000 (12:06 +0900)] 
Merge branch 'aw/validate-proxy-url-scheme'

Misspelt proxy URL (e.g., httt://...) did not trigger any warning
or failure, which has been corrected.

* aw/validate-proxy-url-scheme:
  http: reject unsupported proxy URL schemes

12 days agoMerge branch 'mm/git-url-parse'
Junio C Hamano [Thu, 21 May 2026 03:06:48 +0000 (12:06 +0900)] 
Merge branch 'mm/git-url-parse'

The internal URL parsing logic has been made accessible via a new
subcommand "git url-parse".

* mm/git-url-parse:
  t9904: add tests for the new url-parse builtin
  doc: describe the url-parse builtin
  builtin: create url-parse command
  urlmatch: define url_parse function
  url: return URL_SCHEME_UNKNOWN instead of dying
  url: move scheme detection to URL header/source
  url: move url_is_local_not_ssh to url.h
  connect: rename enum protocol to url_scheme

12 days agoMerge branch 'pw/xdiff-shrink-memory-consumption'
Junio C Hamano [Thu, 21 May 2026 03:06:48 +0000 (12:06 +0900)] 
Merge branch 'pw/xdiff-shrink-memory-consumption'

Shrink wasted memory in Myers diff that does not account for common
prefix and suffix removal.

* pw/xdiff-shrink-memory-consumption:
  xdiff: reduce the size of array
  xprepare: simplify error handling
  xdiff: cleanup xdl_clean_mmatch()
  xdiff: reduce size of action arrays

12 days agoMerge branch 'kh/doc-log-decorate-list'
Junio C Hamano [Thu, 21 May 2026 03:06:47 +0000 (12:06 +0900)] 
Merge branch 'kh/doc-log-decorate-list'

Doc update.

* kh/doc-log-decorate-list:
  doc: log: use the same delimiter in description list
  doc: log: fix --decorate description list

12 days agoMerge branch 'kn/refs-generic-helpers'
Junio C Hamano [Thu, 21 May 2026 03:06:47 +0000 (12:06 +0900)] 
Merge branch 'kn/refs-generic-helpers'

Refactor service routines in the ref subsystem backends.

* kn/refs-generic-helpers:
  refs: use peeled tag values in reference backends
  refs: add peeled object ID to the `ref_update` struct
  refs: move object parsing to the generic layer
  update-ref: handle rejections while adding updates
  update-ref: move `print_rejected_refs()` up
  refs: return `ref_transaction_error` from `ref_transaction_update()`
  refs: extract out reflog config to generic layer
  refs: introduce `ref_store_init_options`
  refs: remove unused typedef 'ref_transaction_commit_fn'

12 days agoMerge branch 'za/t2000-modernise-more'
Junio C Hamano [Thu, 21 May 2026 03:06:47 +0000 (12:06 +0900)] 
Merge branch 'za/t2000-modernise-more'

Test update.

* za/t2000-modernise-more:
  t2000: consolidate second scenario into a single test block

13 days agocommit: fall back to full read when maybe_tree is NULL
Jeff King [Tue, 19 May 2026 06:15:34 +0000 (02:15 -0400)] 
commit: fall back to full read when maybe_tree is NULL

When we load a commit object from the commit graph (rather than reading
the object contents), we don't fill in its "maybe_tree" entry, but
rather wait to lazy-load it. This goes back to 7b8a21dba1 (commit-graph:
lazy-load trees for commits, 2018-04-06), and saves the work of
instantiating tree objects that nobody cares about.

But it creates a data dependency: now the commit struct depends on the
graph file to do that lazy load. This is a problem if we close the graph
file; now we have a commit struct that claims to be parsed but is
missing some of its data.

It's rare for this to be a problem in practice, because we don't tend to
close the graph files at all, and if we do we don't tend to look at
their commits afterward. But there is one case that is easy to trigger:
git-clone's --dissociate option will close the object database before
running the dissociate repack, and then afterwards still try to check
out the working tree. This will yield an error like:

  fatal: unable to parse commit b29edc0babef41810f7b1c9ee1d74058f22e4080
  warning: Clone succeeded, but checkout failed.

What happens is that we expect repo_get_commit_tree() to lazy-load the
tree, but commit_graph_position() returns COMMIT_NOT_FROM_GRAPH because
the position slab has gone away (and even if it hadn't, we don't have
the graph file itself available anymore).

Let's try harder to find the tree in repo_get_commit_tree() by actually
opening the commit object and parsing the tree line. This is extra work,
but no more than we'd have to go to if we hadn't done the initial graph
load in the first place.

It does mean that a corrupt commit (e.g., one that points to a non-tree
object for which we couldn't instantiate a struct) will repeatedly load
the object from disk, once for each call to repo_get_commit_tree(). But
such corruptions should be rare, and we don't tend to perform such calls
repeatedly (usually we'd abort the operation upon seeing corruption).

It also means we have to reimplement a bit of the commit parsing. We
can't just use parse_commit_buffer() here, because it expects an
unparsed struct and wants to load everything, including parent links.
But we don't know if the parent list has been munged during traversal,
so it's not safe for us to touch it. Fortunately, it's quite easy to
load just the tree, as it is always the first line of the commit object.

There is an alternative approach which I considered but rejected:
"complete" each graph-loaded commit struct when we close the graph file
by looking up and instantiating their trees at close time. This is the
most elegant solution in some sense, as it resolves the data dependency
at the moment it goes away. And it avoids ever opening the commit
objects at all, which can be more efficient.

But not always. The resolving effort scales with the number of
graph-loaded commits, even though we may only later access one or a few.
So the tradeoff depends on how many were loaded in total versus how many
will be later accessed.

And in most cases, we will not access any at all! Programs which close
the object database before exiting will then do a bunch of work for no
reason. This could be mitigated by requiring a separate function to
resolve the graph structs before closing the file. But now each close
call has to consider whether to call that resolving function. So we'd
fix this case in git-clone, but we don't know what other cases (if any)
are lurking.

Moreover, this strategy does nothing if we lose access to the graph file
unexpectedly (e.g., due to a system error). I'm not entirely sure this
is possible now (we mmap it, so I'd guess any error would turn into
SIGBUS anyway). But it feels like making the lazy-load more robust
(which this patch does) is the best way to handle a wide variety of
possible failure modes.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 days agosend-pack: pass negotiation config in push
Derrick Stolee [Tue, 19 May 2026 16:24:55 +0000 (16:24 +0000)] 
send-pack: pass negotiation config in push

When push.negotiate is enabled, 'git push' spawns a child 'git fetch
--negotiate-only' process to find common commits.  Pass
--negotiation-include and --negotiation-restrict options from the
'remote.<name>.negotiationInclude' and
'remote.<name>.negotiationRestrict' config keys to this child process.

When negotiationRestrict is configured, it replaces the default
behavior of using all remote refs as negotiation tips. This allows
the user to control which local refs are used for push negotiation.

When negotiationInclude is configured, the specified ref patterns
are passed as --negotiation-include to ensure their tips are always
sent as 'have' lines during push negotiation.

Reviewed-by: Matthew John Cheetham <mjcheetham@outlook.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 days agoremote: add remote.*.negotiationInclude config
Derrick Stolee [Tue, 19 May 2026 16:24:54 +0000 (16:24 +0000)] 
remote: add remote.*.negotiationInclude config

Add a new 'remote.<name>.negotiationInclude' multi-valued config option that
provides default values for --negotiation-include when no
--negotiation-include arguments are specified over the command line.  This
is a mirror of how 'remote.<name>.negotiationRestrict' specifies defaults
for the --negotiation-restrict arguments.

Each value is either an exact ref name or a glob pattern whose tips should
always be sent as 'have' lines during negotiation. The config values are
resolved through the same resolve_negotiation_include() codepath as the CLI
options.

This option is additive with the normal negotiation process: the negotiation
algorithm still runs and advertises its own selected commits, but the refs
matching the config are sent unconditionally on top of those heuristically
selected commits.

Similar to the negotiationRestrict config, an empty value resets the value
list to allow ignoring earlier config values, such as those that might be
set in system or global config.

Reviewed-by: Matthew John Cheetham <mjcheetham@outlook.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 days agofetch: add --negotiation-include option for negotiation
Derrick Stolee [Tue, 19 May 2026 16:24:53 +0000 (16:24 +0000)] 
fetch: add --negotiation-include option for negotiation

Add a new --negotiation-include option to 'git fetch', which ensures
that certain ref tips are always sent as 'have' lines during fetch
negotiation, regardless of what the negotiation algorithm selects.

This is useful when the repository has a large number of references, so
the normal negotiation algorithm truncates the list. This is especially
important in repositories with long parallel commit histories. For
example, a repo could have a 'dev' branch for development and a
'release' branch for released versions. If the 'dev' branch isn't
selected for negotiation, then it's not a big deal because there are
many in-progress development branches with a shared history. However, if
'release' is not selected for negotiation, then the server may think
that this is the first time the client has asked for that reference,
causing a full download of its parallel commit history (and any extra
data that may be unique to that branch). This is based on a real example
where certain fetches would grow to 60+ GB when a release branch
updated.

This option is a complement to --negotiation-restrict, which reduces the
negotiation ref set to a specific list. In the earlier example, using
--negotiation-restrict to focus the negotiation to 'dev' and 'release'
would avoid those problematic downloads, but would still not allow
advertising potentially-relevant user branches. In this way, the
'include' version solves the problem I mention while allowing
negotiation to pick other references opportunistically. The two options
can also be combined to allow the best of both worlds.

The argument may be an exact ref name or a glob pattern. Non-existent
refs are silently ignored. This behavior is also updated in the ref matching
logic for the related --negotiation-restrict option to match.

The implementation outputs the requested objects as haves before the
negotiator performs its own algorithm to choose the next haves. Use the new
have_sent() interface to signal these have commits were sent before engaging
with the negotiator's next() iterator.

Also add --negotiation-include to 'git pull' passthrough options.

Reviewed-by: Matthew John Cheetham <mjcheetham@outlook.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 days agonegotiator: add have_sent() interface
Derrick Stolee [Tue, 19 May 2026 16:24:52 +0000 (16:24 +0000)] 
negotiator: add have_sent() interface

In a future change, we will introduce a capability to choose specific commit
OIDs as 'have's in fetch negotiation, with the ability to have the
negotiator choose more 'have's to increase coverage beyond that required
core set. The negotiator works to avoid emitting 'have's that can reach each
other, but that logic is hidden beneath the negotiator's iterator function
pointer ('next'). We need a way to communicate to the negotiator that we
have picked a 'have' so it could incorporate that into its logic.

Add a have_sent() method to the fetch_negotiator interface. This is the
signal that allows the negotiator to track the commit as already shown and
can perform the proper bookkeeping to avoid emitting those objects or
anything they can reach.

For our non-trivial negotiators, it is sufficient to mark these commits as
common, so the implementation is quite simple. This logic will be exercised
in the next change.

Reviewed-by: Matthew John Cheetham <mjcheetham@outlook.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 days agoremote: add remote.*.negotiationRestrict config
Derrick Stolee [Tue, 19 May 2026 16:24:51 +0000 (16:24 +0000)] 
remote: add remote.*.negotiationRestrict config

In a previous change, the --negotiation-restrict command-line option of 'git
fetch' was added as a synonym of --negotiation-tip. Both of these options
restrict the set of 'haves' the client can send as part of negotiation.

This was previously not available via a configuration option. Add a new
'remote.<name>.negotiationRestrict' multi-valued config option that updates
'git fetch <name>' to use these restrictions by default.

If the user provides even one --negotiation-restrict argument, then the
config is ignored.

An empty value resets the value list to allow ignoring earlier config
values, such as those that might be set in system or global config.

Reviewed-by: Matthew John Cheetham <mjcheetham@outlook.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 days agotransport: rename negotiation_tips
Derrick Stolee [Tue, 19 May 2026 16:24:50 +0000 (16:24 +0000)] 
transport: rename negotiation_tips

The previous change added the --negotiation-restrict synonym for the
--negotiation-tip option for 'git fetch'. In anticipation of adding a new
option that behaves similarly but with distinct changes to its behavior,
rename the internal representation of this data from 'negotiation_tips' to
'negotiation_restrict_tips'.

The 'tips' part is kept because this is an oid_array in the transport layer.
This requires the builtin to handle parsing refs into collections of oids so
the transport layer can handle this cleaner form of the data.

Also update the string_list used to store the inputs from command-line
options.

Reviewed-by: Matthew John Cheetham <mjcheetham@outlook.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 days agofetch: add --negotiation-restrict option
Derrick Stolee [Tue, 19 May 2026 16:24:49 +0000 (16:24 +0000)] 
fetch: add --negotiation-restrict option

The --negotiation-tip option to 'git fetch' and 'git pull' allows users
to specify that they want to focus negotiation on a small set of
references. This is a _restriction_ on the negotiation set, helping to
focus the negotiation when the ref count is high. However, it doesn't
allow for the ability to opportunistically select references beyond that
list.

This subtle detail that this is a 'maximum set' and not a 'minimum set'
is not immediately clear from the option name. This makes it more
complicated to add a new option that provides the complementary behavior
of a minimum set.

For now, create a new synonym option, --negotiation-restrict, that
behaves identically to --negotiation-tip. Update the documentation to
make it clear that this new name is the preferred option, but we keep
the old name for compatibility. Mark --negotiation-tip as an alias of the
new, preferred option.

Update a few warning messages with the new option, but also make them
translatable with the option name inserted by formatting. At least one
of these messages will be reused later for a new option.

Reviewed-by: Matthew John Cheetham <mjcheetham@outlook.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 days agot5516: fix test order flakiness
Derrick Stolee [Tue, 19 May 2026 16:24:48 +0000 (16:24 +0000)] 
t5516: fix test order flakiness

The 'fetch follows tags by default' test sorts using 'sort -k 4', but
for-each-ref output only has 3 columns. This relies on sort treating records
with fewer fields as having an empty fourth field, which may produce
unstable results depending on locale. This appears to be an accident added
in 3f763ddf28 (fetch: set remote/HEAD if it does not exist, 2024-11-22).

Use 'sort -k 3' to match the actual number of columns in the output.

Reviewed-by: Matthew John Cheetham <mjcheetham@outlook.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 days agorepack: allow `--write-midx=incremental` without `--geometric`
Taylor Blau [Tue, 19 May 2026 15:58:25 +0000 (11:58 -0400)] 
repack: allow `--write-midx=incremental` without `--geometric`

Previously, `--write-midx=incremental` required `--geometric` and would
die() without it. Relax this restriction so that incremental MIDX
repacking can be used independently.

Without `--geometric`, the behavior is append-only: a single new MIDX
layer is created containing whatever packs were written by the repack
and appended to the existing chain (or a new chain is started). Existing
layers are preserved as-is with no compaction or merging.

Implement this via a new repack_make_midx_append_plan() that builds a
plan consisting of a WRITE step for the freshly written packs followed
by COPY steps for every existing MIDX layer. The existing compaction
plan (repack_make_midx_compaction_plan) is used only when `--geometric`
is active.

Update the documentation to describe the behavior with and without
`--geometric`, and replace the test that enforced the old restriction
with one exercising append-only incremental MIDX repacking.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 days agorepack: introduce `--write-midx=incremental`
Taylor Blau [Tue, 19 May 2026 15:58:22 +0000 (11:58 -0400)] 
repack: introduce `--write-midx=incremental`

Expose the incremental MIDX repacking mode (implemented in an earlier
commit) via a new --write-midx=incremental option for `git repack`.

Add "incremental" as a recognized argument to the --write-midx
OPT_CALLBACK, mapping it to REPACK_WRITE_MIDX_INCREMENTAL. When this
mode is active and --geometric is in use, set the midx_layer_threshold
on the pack geometry so that only packs in sufficiently large tip layers
are considered for repacking.

Two new configuration options control the compaction behavior:

 - repack.midxSplitFactor (default: 2): the factor used in the
   geometric merging condition for MIDX layers.

 - repack.midxNewLayerThreshold (default: 8): the minimum number of
   packs in the tip MIDX layer before its packs are considered as
   candidates for geometric repacking.

Add tests exercising the new mode across a variety of scenarios
including basic geometric violations, multi-round chain integrity,
branching and merging histories, cross-layer object uniqueness, and
threshold-based compaction.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 days agorepack: implement incremental MIDX repacking
Taylor Blau [Tue, 19 May 2026 15:58:19 +0000 (11:58 -0400)] 
repack: implement incremental MIDX repacking

Implement the `write_midx_incremental()` function, which builds and
maintains an incremental MIDX chain as part of the geometric repacking
process.

Unlike the default mode which writes a single flat MIDX, the incremental
mode constructs a compaction plan that determines which MIDX layers to
write, compact, or copy, and then executes each step using `git
multi-pack-index` subcommands with the --no-write-chain-file flag.

The repacking strategy works as follows:

 * Acquire the lock guarding the multi-pack-index-chain.

 * A new MIDX layer is always written containing the newly created
   pack(s). If the tip MIDX layer was rewritten during geometric
   repacking, any surviving packs from that layer are also included.

 * Starting from the new layer, adjacent MIDX layers are merged together
   as long as the accumulated object count exceeds half the object count
   of the next deeper layer (controlled by 'repack.midxSplitFactor').

 * Remaining layers in the chain are evaluated pairwise and either
   compacted or copied as-is, following the same merging condition.

 * Write the contents of the new multi-pack-index chain, atomically move
   it into place, and then release the lock.

 * Delete any now-unused MIDX layers.

After writing the new layer, the strategy is evaluated among the
existing MIDX layers in order from oldest to newest. Each step that
writes a new MIDX layer uses "--no-write-chain-file" to avoid updating
the multi-pack-index-chain file. After all steps are complete, the new
chain file is written and then atomically moved into place.

At present, this functionality is exposed behind a new enum value,
`REPACK_WRITE_MIDX_INCREMENTAL`, but has no external callers. A
subsequent commit will expose this mode via `git repack
--write-midx=incremental`.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>