Commit Graph

13625 Commits

Author SHA1 Message Date
Derrick Stolee
cf60a92f8c survey: add report of "largest" paths
Since we are already walking our reachable objects using the path-walk API,
let's now collect lists of the paths that contribute most to different
metrics. Specifically, we care about

 * Number of versions.
 * Total size on disk.
 * Total inflated size (no delta or zlib compression).

This information can be critical to discovering which parts of the
repository are causing the most growth, especially on-disk size. Different
packing strategies might help compress data more efficiently, but the toal
inflated size is a representation of the raw size of all snapshots of those
paths. Even when stored efficiently on disk, that size represents how much
information must be processed to complete a command such as 'git blame'.

The exact disk size seems to be not quite robust enough for testing, as
could be seen by the `linux-musl-meson` job consistently failing, possibly
because of zlib-ng deflates differently: t8100.4(git survey
(default)) was failing with a symptom like this:

   TOTAL OBJECT SIZES BY TYPE
   ===============================================
   Object Type | Count | Disk Size | Inflated Size
   ------------+-------+-----------+--------------
  -    Commits |    10 |      1523 |          2153
  +    Commits |    10 |      1528 |          2153
         Trees |    10 |       495 |          1706
         Blobs |    10 |       191 |           101
  -       Tags |     4 |       510 |           528
  +       Tags |     4 |       547 |           528

This means: the disk size is unlikely something we can verify robustly.
Since zlib-ng seems to increase the disk size of the tags from 528 to
547, we cannot even assume that the disk size is always smaller than the
inflated size. We will most likely want to either skip verifying the
disk size altogether, or go for some kind of fuzzy matching, say, by
replacing `s/ 1[45][0-9][0-9] / ~1.5k /` and `s/ [45][0-9][0-9] / ~½k /`
or something like that.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2026-04-09 02:03:54 +00:00
Derrick Stolee
61a029b144 survey: add ability to track prioritized lists
In future changes, we will make use of these methods. The intention is to
keep track of the top contributors according to some metric. We don't want
to store all of the entries and do a sort at the end, so track a
constant-size table and remove rows that get pushed out depending on the
chosen sorting algorithm.

Co-authored-by: Jeff Hostetler <git@jeffhostetler.com>
Signed-off-by; Jeff Hostetler <git@jeffhostetler.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
2026-04-09 02:03:54 +00:00
Derrick Stolee
6fc5d72547 survey: show progress during object walk
Signed-off-by: Derrick Stolee <stolee@gmail.com>
2026-04-09 02:03:54 +00:00
Derrick Stolee
8c9a377692 survey: summarize total sizes by object type
Now that we have explored objects by count, we can expand that a bit more to
summarize the data for the on-disk and inflated size of those objects. This
information is helpful for diagnosing both why disk space (and perhaps
clone or fetch times) is growing but also why certain operations are slow
because the inflated size of the abstract objects that must be processed is
so large.

Note: zlib-ng is slightly more efficient even at those small sizes. Even
between zlib versions, there are slight differences in compression. To
accommodate for that in the tests, not the exact numbers but some rough
approximations are validated (the test should validate `git survey`,
after all, not zlib).

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2026-04-09 02:03:54 +00:00
Derrick Stolee
9dc8a65400 survey: add object count summary
At the moment, nothing is obvious about the reason for the use of the
path-walk API, but this will become more prevelant in future iterations. For
now, use the path-walk API to sum up the counts of each kind of object.

For example, this is the reachable object summary output for my local repo:

REACHABLE OBJECT SUMMARY
========================
Object Type |  Count
------------+-------
       Tags |   1343
    Commits | 179344
      Trees | 314350
      Blobs | 184030

Signed-off-by: Derrick Stolee <stolee@gmail.com>
2026-04-09 02:03:54 +00:00
Derrick Stolee
65bb0a6688 survey: start pretty printing data in table form
When 'git survey' provides information to the user, this will be presented
in one of two formats: plaintext and JSON. The JSON implementation will be
delayed until the functionality is complete for the plaintext format.

The most important parts of the plaintext format are headers specifying the
different sections of the report and tables providing concreted data.

Create a custom table data structure that allows specifying a list of
strings for the row values. When printing the table, check each column for
the maximum width so we can create a table of the correct size from the
start.

The table structure is designed to be flexible to the different kinds of
output that will be implemented in future changes.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
2026-04-09 02:03:54 +00:00
Jeff Hostetler
4bb31c794f survey: add command line opts to select references
By default we will scan all references in "refs/heads/", "refs/tags/"
and "refs/remotes/".

Add command line opts let the use ask for all refs or a subset of them
and to include a detached HEAD.

Signed-off-by: Jeff Hostetler <git@jeffhostetler.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
2026-04-09 02:03:54 +00:00
Jeff Hostetler
73fd10debc survey: stub in new experimental 'git-survey' command
Start work on a new 'git survey' command to scan the repository
for monorepo performance and scaling problems.  The goal is to
measure the various known "dimensions of scale" and serve as a
foundation for adding additional measurements as we learn more
about Git monorepo scaling problems.

The initial goal is to complement the scanning and analysis performed
by the GO-based 'git-sizer' (https://github.com/github/git-sizer) tool.
It is hoped that by creating a builtin command, we may be able to take
advantage of internal Git data structures and code that is not
accessible from GO to gain further insight into potential scaling
problems.

Co-authored-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Jeff Hostetler <git@jeffhostetler.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
2026-04-09 02:03:54 +00:00
Junio C Hamano
37a4780f2c Merge branch 'tc/replay-ref'
The experimental `git replay` command learned the `--ref=<ref>` option
to allow specifying which ref to update, overriding the default behavior.

* tc/replay-ref:
  replay: allow to specify a ref with option --ref
  replay: use stuck form in documentation and help message
  builtin/replay: mark options as not negatable
2026-04-08 10:19:18 -07:00
Junio C Hamano
9797fed6ce Merge branch 'ps/odb-cleanup'
Various code clean-up around odb subsystem.

* ps/odb-cleanup:
  odb: drop unneeded headers and forward decls
  odb: rename `odb_has_object()` flags
  odb: use enum for `odb_write_object` flags
  odb: rename `odb_write_object()` flags
  treewide: use enum for `odb_for_each_object()` flags
  CodingGuidelines: document our style for flags
2026-04-08 10:19:17 -07:00
Junio C Hamano
6c9fbf4fcd Merge branch 'rs/history-short-help-fix'
Glitches in "git history -h" have been corrected.

* rs/history-short-help-fix:
  history: fix short help for argument of --update-refs
2026-04-07 14:59:28 -07:00
Junio C Hamano
f1743ad69a Merge branch 'th/backfill-auto-detect-sparseness-fix'
"git backfill" is capable of auto-detecting a sparsely checked out
working tree, which was broken.

* th/backfill-auto-detect-sparseness-fix:
  backfill: auto-detect sparse-checkout from config
2026-04-07 14:59:28 -07:00
Junio C Hamano
b66c97cc64 Merge branch 'ps/receive-pack-updateinstead-in-worktree'
The check in "receive-pack" to prevent a checked out branch from
getting updated via updateInstead mechanism has been corrected.

* ps/receive-pack-updateinstead-in-worktree:
  receive-pack: use worktree HEAD for updateInstead
  t5516: clean up cloned and new-wt in denyCurrentBranch and worktrees test
  t5516: test updateInstead with worktree and unborn bare HEAD
2026-04-07 14:59:27 -07:00
Junio C Hamano
f1edda9bfb Merge branch 'jt/fast-import-signed-modes'
Handling of signed commits and tags in fast-import has been made more
configurable.

* jt/fast-import-signed-modes:
  fast-import: add 'abort-if-invalid' mode to '--signed-tags=<mode>'
  fast-import: add 'sign-if-invalid' mode to '--signed-tags=<mode>'
  fast-import: add 'strip-if-invalid' mode to '--signed-tags=<mode>'
  fast-import: add 'abort-if-invalid' mode to '--signed-commits=<mode>'
  fast-export: check for unsupported signing modes earlier
2026-04-07 14:59:27 -07:00
Junio C Hamano
7b6d0cd51b Merge branch 'ps/fsck-wo-the-repository'
Internals of "git fsck" have been refactored to not depend on the
global `the_repository` variable.

* ps/fsck-wo-the-repository:
  builtin/fsck: stop using `the_repository` in error reporting
  builtin/fsck: stop using `the_repository` when marking objects
  builtin/fsck: stop using `the_repository` when checking packed objects
  builtin/fsck: stop using `the_repository` with loose objects
  builtin/fsck: stop using `the_repository` when checking reflogs
  builtin/fsck: stop using `the_repository` when checking refs
  builtin/fsck: stop using `the_repository` when snapshotting refs
  builtin/fsck: fix trivial dependence on `the_repository`
  fsck: drop USE_THE_REPOSITORY
  fsck: store repository in fsck options
  fsck: initialize fsck options via a function
  fetch-pack: move fsck options into function scope
2026-04-07 14:59:26 -07:00
Junio C Hamano
fbd0428cc3 Merge branch 'jk/c23-const-preserving-fixes'
Adjust the codebase for C23 that changes functions like strchr()
that discarded constness when they return a pointer into a const
string to preserve constness.

* jk/c23-const-preserving-fixes:
  config: store allocated string in non-const pointer
  rev-parse: avoid writing to const string for parent marks
  revision: avoid writing to const string for parent marks
  rev-parse: simplify dotdot parsing
  revision: make handle_dotdot() interface less confusing
2026-04-06 15:42:51 -07:00
Junio C Hamano
a2dc765251 Merge branch 'qb/doc-git-stash-push-optionality'
Doc update.

* qb/doc-git-stash-push-optionality:
  docs: fix "git stash [push]" documentation
2026-04-06 15:42:50 -07:00
Junio C Hamano
03311dca7f Merge branch 'tb/stdin-packs-excluded-but-open'
pack-objects's --stdin-packs=follow mode learns to handle
excluded-but-open packs.

* tb/stdin-packs-excluded-but-open:
  repack: mark non-MIDX packs above the split as excluded-open
  pack-objects: support excluded-open packs with --stdin-packs
  t7704: demonstrate failure with once-cruft objects above the geometric split
  pack-objects: refactor `read_packs_list_from_stdin()` to use `strmap`
  pack-objects: plug leak in `read_stdin_packs()`
2026-04-06 15:42:49 -07:00
Junio C Hamano
d75badf83b Merge branch 'ps/odb-generic-object-name-handling'
Object name handling (disambiguation and abbreviation) has been
refactored to be backend-generic, moving logic into the respective
object database backends.

* ps/odb-generic-object-name-handling:
  odb: introduce generic `odb_find_abbrev_len()`
  object-file: move logic to compute packed abbreviation length
  object-name: move logic to compute loose abbreviation length
  object-name: simplify computing common prefixes
  object-name: abbreviate loose object names without `disambiguate_state`
  object-name: merge `update_candidates()` and `match_prefix()`
  object-name: backend-generic `get_short_oid()`
  object-name: backend-generic `repo_collect_ambiguous()`
  object-name: extract function to parse object ID prefixes
  object-name: move logic to iterate through packed prefixed objects
  object-name: move logic to iterate through loose prefixed objects
  odb: introduce `struct odb_for_each_object_options`
  oidtree: extend iteration to allow for arbitrary return codes
  oidtree: modernize the code a bit
  object-file: fix sparse 'plain integer as NULL pointer' error
2026-04-06 15:42:49 -07:00
René Scharfe
26b9946dd7 history: fix short help for argument of --update-refs
"print" is not a valid argument for --update-refs.  List both valid
alternatives literally in the argh string, consistent with documentation
and usage string.

Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-06 10:17:36 -07:00
Trieu Huynh
339eba65a7 backfill: auto-detect sparse-checkout from config
Commit 85127bcdea ("backfill: assume --sparse when sparse-checkout is
enabled") intended for 'git backfill' to consult the repository
configuration when the user does not pass '--sparse' or
'--no-sparse' on the command line. It added the sentinel check:

    if (ctx->sparse < 0)
        ctx->sparse = cfg->apply_sparse_checkout;

However, the ctx->sparse field is initialized to 0 instead of -1,
so this guard never triggers. Consequently, the repository config
(core.sparseCheckout) is never checked, and the command always
performs a full backfill even when sparse-checkout is enabled.

Fix this by initializing ctx->sparse to -1, ensuring the existing
fallback logic correctly reads the repository configuration when
no explicit flags are provided.

Add a test to verify that 'git backfill' automatically respects
sparse-checkout settings when no flags are passed.

Signed-off-by: Trieu Huynh <vikingtc4@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-06 09:26:08 -07:00
Junio C Hamano
e0613d24f9 Merge branch 'sa/replay-revert'
"git replay" (experimental) learns, in addition to "pick" and
"replay", a new operating mode "revert".

* sa/replay-revert:
  replay: add --revert mode to reverse commit changes
  sequencer: extract revert message formatting into shared function
2026-04-03 13:01:09 -07:00
Junio C Hamano
05ddb9ee8a Merge branch 'pw/worktree-reduce-the-repository'
Reduce the reference to the_repository in the worktree subsystem.

* pw/worktree-reduce-the-repository:
  worktree: reject NULL worktree in get_worktree_git_dir()
  worktree add: stop reading ".git/HEAD"
  worktree: remove "the_repository" from is_current_worktree()
2026-04-03 13:01:09 -07:00
Junio C Hamano
0cd4fb9f46 Merge branch 'ar/config-hook-cleanups'
Code clean-up around the recent "hooks defined in config" topic.

* ar/config-hook-cleanups:
  hook: reject unknown hook names in git-hook(1)
  hook: show disabled hooks in "git hook list"
  hook: show config scope in git hook list
  hook: introduce hook_config_cache_entry for per-hook data
  t1800: add test to verify hook execution ordering
  hook: make consistent use of friendly-name in docs
  hook: replace hook_list_clear() -> string_list_clear_func()
  hook: detect & emit two more bugs
  hook: rename cb_data_free/alloc -> hook_data_free/alloc
  hook: fix minor style issues
  builtin/receive-pack: properly init receive_hook strbuf
  hook: move unsorted_string_list_remove() to string-list.[ch]
2026-04-03 13:01:09 -07:00
Junio C Hamano
4e5821732e Merge branch 'ds/backfill-revs'
`git backfill` learned to accept revision and pathspec arguments.

* ds/backfill-revs:
  t5620: test backfill's unknown argument handling
  path-walk: support wildcard pathspecs for blob filtering
  backfill: work with prefix pathspecs
  backfill: accept revision arguments
  t5620: prepare branched repo for revision tests
  revision: include object-name.h
2026-04-03 13:01:08 -07:00
Junio C Hamano
cd79c76a51 Merge branch 'mf/format-patch-commit-list-format-doc'
Doc updates.

* mf/format-patch-commit-list-format-doc:
  format-patch: removing unconditional wrapping
  docs: fix --commit-list-format related entries
2026-04-03 13:01:08 -07:00
Junio C Hamano
aafabe2fc4 Merge branch 'mf/format-patch-commit-list-format'
Improve the recently introduced `git format-patch
--commit-list-format` (formerly `--cover-letter-format`) option,
including a new "modern" preset and better CLI ergonomics.

* mf/format-patch-commit-list-format:
  format-patch: --commit-list-format without prefix
  format-patch: add preset for --commit-list-format
  format-patch: wrap generate_commit_list_cover()
  format.commitListFormat: strip meaning from empty
  docs/pretty-formats: add %(count) and %(total)
  format-patch: rename --cover-letter-format option
  format-patch: refactor generate_commit_list_cover
  pretty.c: better die message %(count) and %(total)
2026-04-03 13:01:08 -07:00
Junio C Hamano
63901789bc Merge branch 'mf/format-patch-cover-letter-format'
"git format-patch --cover-letter" learns to use a simpler format
instead of the traditional shortlog format to list its commits with
a new --cover-letter-format option and format.commitListFormat
configuration variable.

* mf/format-patch-cover-letter-format:
  docs: add usage for the cover-letter fmt feature
  format-patch: add commitListFormat config
  format-patch: add ability to use alt cover format
  format-patch: move cover letter summary generation
  pretty.c: add %(count) and %(total) placeholders
2026-04-03 13:01:08 -07:00
Toon Claes
23d83f8ddb replay: allow to specify a ref with option --ref
When option '--onto' is passed to git-replay(1), the command will update
refs from the <revision-range> passed to the command. When using option
'--advance' or '--revert', the argument of that option is a ref that
will be updated.

To enable users to specify which ref to update, add option '--ref'. When
using option '--ref', the refs described above are left untouched and
instead the argument of this option is updated instead.

Because this introduces code paths in replay.c that jump to `out` before
init_basic_merge_options() is called on `merge_opt`, zero-initialize the
struct.

Signed-off-by: Toon Claes <toon@iotcl.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-01 21:34:25 -07:00
Toon Claes
6542cacbb3 replay: use stuck form in documentation and help message
gitcli(7) suggests to use stuck form. Change the documentation strings
to use this form.

While at it, reorder them to match the order in the docs.

Signed-off-by: Toon Claes <toon@iotcl.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-01 21:34:25 -07:00
Toon Claes
e5ae639f1a builtin/replay: mark options as not negatable
The options '--onto', '--advance', '--revert', and '--ref-action' of
git-replay(1) are not negatable. Mark them as such using
PARSE_OPT_NONEG.

Signed-off-by: Toon Claes <toon@iotcl.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-01 21:34:25 -07:00
Junio C Hamano
9d498801a7 Merge branch 'mk/repo-help-strings'
"git repo info -h" and "git repo structure -h" limit their help output
to the part that is specific to the subcommand.

* mk/repo-help-strings:
  repo: show subcommand-specific help text
  repo: factor repo usage strings into shared macros
2026-04-01 10:28:19 -07:00
Junio C Hamano
51a74900aa Merge branch 'rs/use-strvec-pushv'
Code paths that loop over another array to push each element into a
strvec have been rewritten to use strvec_pushv() instead.

* rs/use-strvec-pushv:
  use strvec_pushv() to add another strvec
2026-04-01 10:28:19 -07:00
Junio C Hamano
0a39ec283c Merge branch 'vp/http-rate-limit-retries'
The HTTP transport learned to react to "429 Too Many Requests".

* vp/http-rate-limit-retries:
  http: add support for HTTP 429 rate limit retries
  strbuf_attach: fix call sites to pass correct alloc
  strbuf: pass correct alloc to strbuf_attach() in strbuf_reencode()
2026-04-01 10:28:18 -07:00
Patrick Steinhardt
c63911b052 odb: rename odb_has_object() flags
Rename `odb_has_object()` flags to be properly prefixed with the
function name.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-03-31 20:43:14 -07:00
Junio C Hamano
e104e63a81 Merge branch 'ps/odb-generic-object-name-handling' into ps/odb-cleanup
* ps/odb-generic-object-name-handling:
  odb: introduce generic `odb_find_abbrev_len()`
  object-file: move logic to compute packed abbreviation length
  object-name: move logic to compute loose abbreviation length
  object-name: simplify computing common prefixes
  object-name: abbreviate loose object names without `disambiguate_state`
  object-name: merge `update_candidates()` and `match_prefix()`
  object-name: backend-generic `get_short_oid()`
  object-name: backend-generic `repo_collect_ambiguous()`
  object-name: extract function to parse object ID prefixes
  object-name: move logic to iterate through packed prefixed objects
  object-name: move logic to iterate through loose prefixed objects
  odb: introduce `struct odb_for_each_object_options`
  oidtree: extend iteration to allow for arbitrary return codes
  oidtree: modernize the code a bit
  object-file: fix sparse 'plain integer as NULL pointer' error
2026-03-31 20:43:06 -07:00
Junio C Hamano
a1d7a8fef1 Merge branch 'jw/object-name-bitset-to-enum'
The unsigned integer that is used as an bitset to specify the kind
of branches interpret_branch_name() function has been changed to
use a dedicated enum type.

* jw/object-name-bitset-to-enum:
  object-name: turn INTERPRET_BRANCH_* constants into enum values
2026-03-30 13:57:02 -07:00
Pablo Sabater
8151f4fe7e receive-pack: use worktree HEAD for updateInstead
When a bare repo has linked worktrees, and its HEAD points to an unborn branch,
pushing to a wt branch with updateInstead fails and rejects the push, even if
the wt is clean. This happens because HEAD is checked only for the bare repo
context, instead of the wt.

Remove head_has_history and check for worktree->head_oid which does
have the correct HEAD of the wt.

Update the test added by Runxi's patch to expect success.

Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-03-30 12:52:41 -07:00
Quentin Bernet
3402850ee1 docs: fix "git stash [push]" documentation
Both the synopsis and explanation are incorrect and contradict each
other.
The synopsis claims "push" can only be omitted when you do not give any
options and arguments.
The explanation correctly claims that non-option arguments are not
allowed, except pathspec elements preceded by double hyphens.
But it also adds "-p" to the list of exceptions, even though it is an
option argument.

Signed-off-by: Quentin Bernet <quentin.bernet@bluewin.ch>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-03-30 08:19:40 -07:00
Taylor Blau
9ad29df36d repack: mark non-MIDX packs above the split as excluded-open
In 5ee86c273b (repack: exclude cruft pack(s) from the MIDX where
possible, 2025-06-23), geometric repacking learned to exclude cruft
packs from the MIDX when 'repack.midxMustContainCruft' is set to
'false'.

This works because packs generated with '--stdin-packs=follow' rescue
any once-unreachable objects that later become reachable, making the
resulting packs closed under reachability without needing the cruft pack
in the MIDX.

However, packs above the geometric split that were not part of the
previous MIDX may not have full object closure.  When such packs are
marked as excluded-closed ('^'), pack-objects treats them as a
reachability boundary and does not traverse through them during the
follow pass, potentially leaving the resulting pack without full
closure.

Fix this by marking packs above the geometric split that were not in the
previous MIDX as excluded-open ('!') instead of excluded-closed ('^').
This causes pack-objects to walk through their commits during the follow
pass, rescuing any reachable objects not present in the closed-excluded
packs.

Note that MIDXs which were generated prior to this change and are
unlucky enough to not be closed under reachability may still exhibit
this bug, as we treat all MIDX'd packs as closed. That is true in an
overwhelming number of cases, since in order to have a non-closed MIDX
you would have to:

 - Generate a pack via an earlier geometric repack that is not closed
   under reachability.

 - Store that pack in the MIDX.

 - Avoid picking any commits to receive reachability bitmaps which
   happen to reach objects from which the missing objects are reachable.

In the extremely rare chance that all of the above should happen, an
all-into-one repack will resolve the issue.

Unfortunately, there is no perfect way to determine whether a MIDX'd
pack is closed outside of ensuring that there is a '1' bit in at least
one bitmap for every bit position corresponding to objects in that pack.
While this is possible to do, this approach would treat MIDX'd packs as
open in cases where there is at least one object that is not reachable
from the subset of commits selected for bitmapping.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-03-27 13:40:40 -07:00
Taylor Blau
3f7c0e722e pack-objects: support excluded-open packs with --stdin-packs
In cd846bacc7 (pack-objects: introduce '--stdin-packs=follow',
2025-06-23), pack-objects learned to traverse through commits in
included packs when using '--stdin-packs=follow', rescuing reachable
objects from unlisted packs into the output.

When we encounter a commit in an excluded pack during this rescuing
phase we will traverse through its parents. But because we set
`revs.no_kept_objects = 1`, commit simplification will prevent us from
showing it via `get_revision()`. (In practice, `--stdin-packs=follow`
walks commits down to the roots, but only opens up trees for ones that
do not appear in an excluded pack.)

But there are certain cases where we *do* need to see the parents of an
object in an excluded pack. Namely, if an object is rescue-able, but
only reachable from object(s) which appear in excluded packs, then
commit simplification will exclude those commits from the object
traversal, and we will never see a copy of that object, and thus not
rescue it.

This is what causes the failure in the previous commit during repacking.
When performing a geometric repack, packs above the geometric split that
weren't part of the previous MIDX (e.g., packs pushed directly into
`$GIT_DIR/objects/pack`) may not have full object closure.  When those
packs are listed as excluded via the '^' marker, the reachability
traversal encounters the sequence described above, and may miss objects
which we expect to rescue with `--stdin-packs=follow`.

Introduce a new "excluded-open" pack prefix, '!'. Like '^'-prefixed
packs, objects from '!'-prefixed packs are excluded from the resulting
pack. But unlike '^', commits in '!'-prefixed packs *are* used as
starting points for the follow traversal, and the traversal does not
treat them as a closure boundary.

In order to distinguish excluded-closed from excluded-open packs during
the traversal, introduce a new `pack_keep_in_core_open` bit on
`struct packed_git`, along with a corresponding `KEPT_PACK_IN_CORE_OPEN`
flag for the kept-pack cache.

In `add_object_entry_from_pack()`, move the `want_object_in_pack()`
check to *after* `add_pending_oid()`. This is necessary so that commits
from excluded-open packs are added as traversal tips even though their
objects won't appear in the output. As a consequence, the caller
`for_each_object_in_pack()` will always provide a non-NULL 'p', hence we
are able to drop the "if (p)" conditional.

The `include_check` and `include_check_obj` callbacks on `rev_info` are
used to halt the walk at closed-excluded packs, since objects behind a
'^' boundary are guaranteed to have closure and need not be rescued.

The following commit will make use of this new functionality within the
repack layer to resolve the test failure demonstrated in the previous
commit.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-03-27 13:40:40 -07:00
Taylor Blau
d31d1f2e06 pack-objects: refactor read_packs_list_from_stdin() to use strmap
The '--stdin-packs' mode of pack-objects maintains two separate
string_lists: one for included packs, and one for excluded packs. Each
list stores the pack basename as a string and the corresponding
`packed_git` pointer in its `->util` field.

This works, but makes it awkward to extend the set of pack "kinds" that
pack-objects can accept via stdin, since each new kind would need its
own string_list and duplicated handling. A future commit will want to do
just this, so prepare for that change by handling the various "kinds" of
packs specified over stdin in a more generic fashion.

Namely, replace the two `string_list`s with a single `strmap` keyed on
the pack basename, with values pointing to a new `struct
stdin_pack_info`. This struct tracks both the `packed_git` pointer and a
`kind` bitfield indicating whether the pack was specified as included or
excluded.

Extract the logic for sorting packs by mtime and adding their objects
into a separate `stdin_packs_add_pack_entries()` helper.

While we could have used a `string_list`, we must handle the case where
the same pack is specified more than once. With a `string_list` only, we
would have to pay a quadratic cost to either (a) insert elements into
their sorted positions, or (b) a repeated linear search, which is
accidentally quadratic. For that reason, use a strmap instead.

This patch does not include any functional changes.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-03-27 13:40:39 -07:00
Taylor Blau
81e2906437 pack-objects: plug leak in read_stdin_packs()
The `read_stdin_packs()` function added originally via 339bce27f4
(builtin/pack-objects.c: add '--stdin-packs' option, 2021-02-22)
declares a `rev_info` struct but neglects to call `release_revisions()`
on it before returning, creating the potential for a leak.

The related change in 97ec43247c (pack-objects: declare 'rev_info' for
'--stdin-packs' earlier, 2025-06-23) carried forward this oversight and
did not address it.

Ensure that we call `release_revisions()` appropriately to prevent a
potential leak from this function. Note that in practice our `rev_info`
here does not have a present leak, hence t5331 passes cleanly before
this commit, even when built with SANITIZE=leak.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-03-27 13:40:39 -07:00
Mirko Faina
0284046ad0 format-patch: removing unconditional wrapping
Using format-patch with --commit-list-format different than shortlog,
causes the commit entry lines to wrap if they get longer than
MAIL_DEFAULT_WRAP (72 characters).

While this might be sensible for many when sending changes through
email, it forces this decision of wrapping on the user, reducing the
control granularity of --commit-list-format.

Teach generate_commit_list_cover() to respect commit entry line lengths
and place this wrapping rule on the "modern" preset format instead.

Signed-off-by: Mirko Faina <mroik@delayed.space>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-03-27 13:10:12 -07:00
Junio C Hamano
18396dc97d Merge branch 'kh/doc-interpret-trailers-1'
Doc updates.

* kh/doc-interpret-trailers-1:
  interpret-trailers: use placeholder instead of *
  doc: config: convert trailers section to synopsis style
  doc: interpret-trailers: normalize and fill out options
  doc: interpret-trailers: convert to synopsis style
2026-03-27 11:00:02 -07:00
Junio C Hamano
828988bef3 Merge branch 'mr/merge-file-object-id-worktree-fix'
merge-file --object-id used to trigger a BUG when run in a linked
worktree, which has been fixed.

* mr/merge-file-object-id-worktree-fix:
  merge-file: fix BUG when --object-id is used in a worktree
2026-03-27 11:00:01 -07:00
Junio C Hamano
968e62c187 Merge branch 'rs/prio-queue-to-commit-stack'
Uses of prio_queue as a LIFO stack of commits have been written
with commit_stack.

* rs/prio-queue-to-commit-stack:
  use commit_stack instead of prio_queue in LIFO mode
2026-03-27 11:00:01 -07:00
Jeff King
d385845d55 config: store allocated string in non-const pointer
When git-config matches a url, we copy the variable section name and
store it in the "section" member of a urlmatch_config struct. That
member is const, since the url-matcher will not touch it (and other
callers really will have a const string).

But that means that we have only a const pointer to our allocated
string. We have to cast away the constness when we free it, and likewise
when we assign NUL to tie off the "." separating the subsection and key.
This latter happens implicitly via a strchr() call, but recent versions
of glibc have added annotations that let the compiler detect that and
complain.

Let's keep our own "section" pointer for the non-const string, and then
just point config.section at it. That avoids all of the casting, both
explicit and implicit.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-03-26 12:47:17 -07:00
Jeff King
213b213877 rev-parse: avoid writing to const string for parent marks
The previous commit cleared up some const confusion in handling parent
marks in revision.c, but we have roughly the same code duplicated in
rev-parse. This one is much easier to fix, because the handling of the
shortened string is all done in one place, after detecting any marks
(but without shortening the string between marks).

  As a side note, I suspect this means that it behaves differently than
  the revision.c parser for weird stuff like "foo^!^@^-", but that is
  outside the scope of this patch.

While we are here, let's also rename the variable "dotdot", which is
totally misleading (and which we already fixed in revision.c long ago
via f632dedd8d (handle_revision_arg: stop using "dotdot" as a generic
pointer, 2017-05-19)).

Doing that here makes the diff a little messier, but it also lets the
compiler help us make sure we did not miss any stray mentions of the
variable while we are changing its semantics.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-03-26 12:47:17 -07:00
Jeff King
268a9caaf2 rev-parse: simplify dotdot parsing
The previous commit simplified the way that revision.c parses ".." and
"..." range operators. But there's roughly similar code in rev-parse.
This is less likely to trigger a segfault, as there is no library
function which we'd pass a string literal to, but it still causes the
compiler to complain about laundering away constness via strstr().

Let's give it the same treatment, copying the left-hand side of the
range operator into its own string.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-03-26 12:47:17 -07:00