Commit Graph

17576 Commits (main)

Author SHA1 Message Date
Junio C Hamano 1630431f32 The 21st batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-31 08:25:00 -07:00
Junio C Hamano 93f737d51b Merge branch 'ps/odb-geometric-repack-loose-threshold'
The threshold for geometric repacking to trigger based on loose
object count has been adjusted to match that of 'git gc --auto',
preventing over-aggressive repacking during concurrent writes.

* ps/odb-geometric-repack-loose-threshold:
  odb/files: be less aggressive with geometric repacking
2026-08-31 08:24:59 -07:00
Junio C Hamano 1e4d33de9b Merge branch 'kh/trailers-no-urls'
The trailer parsing machinery has been updated to avoid mistaking
lines that begin with a URL (e.g., 'https://...') as trailer lines.
This prevents intended textual URLs from being mangled or mistakenly
treated as metadata keys.

* kh/trailers-no-urls:
  trailers: stop recognizing URLs as trailers
2026-08-31 08:24:59 -07:00
Junio C Hamano c73e85354c The 20th batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-28 11:04:57 -07:00
Junio C Hamano 9c94d206f0 Merge branch 'kh/format-rev-doc-synopsis'
The documentation for 'git format-rev' has been updated to use the
[synopsis] block definition on code blocks to properly highlight
placeholders, and a quoting inconsistency in the running text has
been fixed.

* kh/format-rev-doc-synopsis:
  doc: format-rev: use [synopsis] on code block
  doc: format-rev: quote subject placeholder before and after
2026-08-28 11:04:57 -07:00
Junio C Hamano f78ce2f7b6 The 19th batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-25 10:53:34 -07:00
Junio C Hamano 6d7be5f7fd Merge branch 'ss/submittingpatches-typofix'
Typofix.

* ss/submittingpatches-typofix:
  doc: fix typo in submitting patches
2026-08-25 10:53:32 -07:00
Junio C Hamano 6730f07098 Merge branch 'ss/repack-drop-filtered'
'git repack' has been taught '--drop-filtered' to delete local
promisor blobs exceeding a limit (currently 'blob:limit=') in partial
clones, reclaiming space.  Guards prevent running during other
operations or if referenced by the index.

* ss/repack-drop-filtered:
  builtin/repack: add guards for --drop-filtered
  builtin/repack: actually drop filtered promisor blobs
  builtin/repack: enumerate promisor blobs for --drop-filtered
  repack-promisor: allow excluding objects from the rebuilt promisor pack
  list-objects-filter: add list_objects_filter__filter_oidset()
  builtin/repack: add --drop-filtered and --dry-run options
2026-08-25 10:53:32 -07:00
Junio C Hamano 2c3adbb2c4 The 18th batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-24 13:17:51 -07:00
Junio C Hamano 593c42fe07 The 17th batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-23 18:01:47 -07:00
Junio C Hamano 679a72c6b8 Merge branch 'kk/merge-base-exhaustion'
The merge-base computation has been optimized by stopping the walk
early when one side's exclusive commits in the queue are exhausted,
yielding significant speedups for queries with one-sided histories.

* kk/merge-base-exhaustion:
  commit-reach: remove commit-date ordering fallback
  commit-reach: move min_generation check into paint_queue_get()
  commit-reach: terminate merge-base walk when one paint side is exhausted
  commit-reach: introduce struct paint_state with per-side counters
  t6600: add clock-skew topologies and step counts for edge cases
  commit-reach: add trace2 instrumentation to paint_down_to_common()
  t6099: add side-exhaustion regression test
  t6600: add test cases for side-exhaustion edge cases
  test-lib-functions: improve diagnostic output for trace2 data assertions
  Documentation/technical: add paint-down-to-common doc
2026-08-23 18:01:46 -07:00
Junio C Hamano 10d3ea2469 Merge branch 'cc/fast-import-usage'
The usage string of 'git fast-import' has been updated to use the
parse_options() API for displaying help, and its SYNOPSIS in the
documentation has been standardized to match.

* cc/fast-import-usage:
  fast-import: remove useless from_stream argument
  fast-import: use parse_options() for command line options
  fast-import: use callbacks to parse some options
  fast-import: use struct option for usage string
  fast-import: move command state globals into 'struct fast_import_state'
  fast-import: introduce 'struct fast_import_state'
  fast-import: factor out option_*() functions
  fast-import: use int for some bool flags
  fast-import: localize 'i' into the 'for' loops using it
  api-parse-options.adoc: document hidden and OPT_*_F option macros
  api-parse-options.adoc: document per-option flags
  parse-options: introduce OPT_HIDDEN_GROUP
2026-08-23 18:01:42 -07:00
Junio C Hamano 4b27b7c707 Merge branch 'ps/cat-file-remote-object-info-type'
The 'remote-object-info' command for 'git cat-file --batch-command'
has been extended to support the '%(objecttype)' placeholder.

* ps/cat-file-remote-object-info-type:
  cat-file: unify default format
  serve: advertise type capability
  fetch-object-info: parse type from server response
  protocol-caps: add type support to object-info
  transport: drop remote object-info fields from transport struct
  fetch-object-info: die() on the remaining error path
  fetch-object-info: use dedicated struct for the results
  fetch-object-info: pass arguments directly instead of a struct
  fetch-object-info: detect malformed server responses
  t5701: use test_file_size() to get the size of a file
2026-08-23 18:01:42 -07:00
Patrick Steinhardt 4e00f13e7e odb/files: be less aggressive with geometric repacking
When performing auto-maintenance with geometric repacking we have two
conditions that may trigger a repack:

  - Either the geometric sequence of packfiles is invalidated.

  - Or we have too many loose objects.

The first condition shouldn't trigger all that often: it may be hit when
we fetch a new packfile, but users tend to not do that all the time. The
second condition is what typically triggers more regularly though, as
every command that ends up writing new objects may cause us to cross the
threshold of loose objects. It is thus preferable to not be too
aggressive here, as otherwise we may end up repacking objects quite
often.

For the geometric-repacking strategy though we have a default of 100
objects, only. As we're approximating the count of objects by only
reading the "objects/17/" shared, we'd only need 2 objects in there
before we perform a repack by default, which is quite aggressive.
git-gc(1) on the other hand has a default of 6700, so it is quite a bit
more conservative here.

Being this aggressive is also causing problems as reported by our users.
When running lots of concurrent writers, those writes will constantly
end up spawning maintenance jobs that end up repacking objects. As we
also prune objects, a concurrently running process that tries to write
an object may see that the sharding directories get removed under their
feet. While we try re-creating such leading directories, we only do so a
single time, and it may happen that the directory vanishes again before
we had the chance to create the loose object. This is not a new problem,
but it is exacerbated by us running maintenance this aggressively.

Improve the status quo by reducing the frequency at which we pack loose
objects to the same frequency that git-gc(1) uses.

Reported-by: Stefan Haller <lists@haller-berlin.de>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-21 10:19:14 -07:00
Kristoffer Haugsbakk d122e37976 trailers: stop recognizing URLs as trailers
An HTTPS URL starts with an alphanumeric scheme followed by a colon.
That means that they will be recognized as trailers in a trailer block.
That turns out to be a problem in practice. Let’s stop recognizing these
as trailers by failing the trailer parsing when we:

1. find the separator;
2. the separator and the next two characters form `://`; and
3. we haven’t parsed any whitespace yet.

The simplest example of how this can be a problem is for people who do
not use trailers but may leave URLs at the end of the commit message.
Now, while these authors might not use trailers themselves, other
authors may have used trailers and this metadata confusion can become a
problem once someone tries to extract that metadata (and non-metadata).

Let’s now look at some examples in the Linux Kernel[1] to see how this
is a problem in practice.

There are commits which contain intended non-trailer lines which start
with URLs. These are comments. Example with just the trailers:[2]

    Signed-off-by: Shuai Xue <xueshuai@linux.alibaba.com>
    [bhelgaas: squash fixes:
    https://lore.kernel.org/r/20260108013956.14351-2-bagasdotme@gmail.com
    https://lore.kernel.org/r/20260108013956.14351-3-bagasdotme@gmail.com]
    Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
    Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
    Link: https://patch.msgid.link/20251210132907.58799-4-xueshuai@linux.alibaba.com

Those `[]` pairs delimit the “squash fixes” comment.

Now, any of these two commands:

     git log --format='%(trailers:only)' -1 <commit>
     git log -1 --format=%B <commit> |
         git interpret-trailers --only-trailers

Will both wrongly (according to the surmised user intent) include these
two URL lines as trailers and also mangle the URLs, e.g.:

    https: //lore.kernel.org/r/20260108013956.14351-2-bagasdotme@gmail.com

Because the `--only-trailers` mode (or `only` for the git-log(1) format)
normalizes the output to a colon and a space.

Another example is linewrapping mistakes; a `Link` trailer with a
URL where the URL ended up on the next line, presumably because the
user’s editor linewrapped the “too long” line. Example with just the
trailers:[3]

    Link: https://patch.msgid.link/20260216-work-xattr-socket-v1-4-c2efa4f74cb7@kernel.org
    Link:
    https://lore.kernel.org/3cnmtqmakpbb2uwhenrj7kdqu3uefykiykjllgfbtpkiwhaa4s@sghkevv7jned [1]
    Acked-by: Darrick J. Wong <djwong@kernel.org>
    Reviewed-by: Jan Kara <jack@suse.cz>
    Signed-off-by: Christian Brauner <brauner@kernel.org>

Now, this intended trailer is already ruined, but interpreting the URL
as a standalone trailer only compounds the mistake.

Yet another example is the trailer machinery normalizing the trailer
block before application, resulting in a `https` trailer key in the
commit message itself. Example with just the trailers:[4]

    https: //sashiko.dev/#/patchset/20260429114208.941011-1-holger.brunck%40hitachienergy.com
    Fixes: c19b6d246a35 ("drivers/net: support hdlc function for QE-UCC")
    Signed-off-by: Holger Brunck <holger.brunck@hitachienergy.com>
    Link: https://patch.msgid.link/20260507155332.3452319-1-holger.brunck@hitachienergy.com
    Signed-off-by: Jakub Kicinski <kuba@kernel.org>

We have a helpful `Link` that points to the original patch.[5] Following
it we can see that that `https` trailer was indeed a URL
originally (again just the trailer block here):

    https://sashiko.dev/#/patchset/20260429114208.941011-1-holger.brunck%40hitachienergy.com
    Fixes: c19b6d246a35 ("drivers/net: support hdlc function for QE-UCC")
    Signed-off-by: Holger Brunck <holger.brunck@hitachienergy.com>

So how did it end up as a `https` trailer? My theory is that the trailer
block was normalized on patch application, causing a URL comment to be
wrongly normalized and cemented in the commit message as a trailer.[6]

† 1: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/
† 2: commit 8236fc613d44e59f6736d6c3e9efffaf26ab7f00
† 3: commit 5bd97f5c5f241a5610c4412d1b93995a26241f81
† 4: commit 496c0c4c53bbe1bad97e82cd12103df61a6e459d
† 5: https://patch.msgid.link/20260507155332.3452319-1-holger.brunck@hitachienergy.com
† 6: There are only four commits in the Linux Kernel of this kind, and
     three of them have the same recurring person in the signoff chain.

***

Note that this check has some benign false positives. A trailer key
can start with a digit, but a URL scheme can not start with a digit.
That means that a line that starts with `1://` will be rejected even
though it cannot be a URL. I don’t think this will reject any real
trailers, so I think the implementation simplicity is worth it.

And these false positives are just for a limited start fragment check;
a mere heuristic, not a URL parser.

Helped-by: Jeff King <peff@peff.net>
Acked-by: Jeff King <peff@peff.net>
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-21 08:53:27 -07:00
Junio C Hamano 1a3e64c6c4 The 16th batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-20 07:30:52 -07:00
Junio C Hamano 3f664917c2 Merge branch 'kh/doc-trailers'
Documentation for 'git interpret-trailers' has been updated to explain
the format of trailer keys (alphanumeric characters and hyphens),
replace outdated terminology, define key terms upfront, and document
how comment lines in the input are treated.

* kh/doc-trailers:
  doc: interpret-trailers: document comment line treatment
  doc: interpret-trailers: rewrite new-trailers paragraphs
  doc: interpret-trailers: commit to “trailer block” term
  doc: interpret-trailers: join new-trailers again
  doc: interpret-trailers: add key format example
  doc: interpret-trailers: explain key format
  doc: interpret-trailers: explain the format after the intro
  doc: interpret-trailers: not just for commit messages
  doc: interpret-trailers: use “metadata” in Name as well
  doc: interpret-trailers: replace “lines” with “metadata”
  doc: interpret-trailers: stop fixating on RFC 822
2026-08-20 07:30:52 -07:00
Junio C Hamano 006933a32c Merge branch 'hn/branch-delete-merged'
The 'git branch' command has been taught the '--delete-merged' option
to remove local branches that are already merged into their tracked
remote-tracking branches.

* hn/branch-delete-merged:
  branch: add --dry-run for --delete-merged
  branch: add branch.<name>.deleteMerged opt-out
  branch: add --delete-merged <pattern>
  branch: prepare delete_branches for a bulk caller
  branch: let delete_branches skip unmerged branches on bulk refusal
  branch: convert delete_branches() to a flags argument
  branch: add --forked filter for --list mode
2026-08-20 07:30:51 -07:00
Junio C Hamano dea0ea3582 The 15th batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-18 09:31:36 -07:00
Junio C Hamano e23356ae1a Merge branch 'hn/bisect-reset-when-found'
The 'git bisect' command has been taught a
'--reset-when-found[=<where>]' option that tells the command to
automatically run 'git bisect reset' to jump back to the original
state or to the found culprit.

* hn/bisect-reset-when-found:
  bisect: add --reset-when-found to leave when done
  bisect: let bisect_reset() optionally check out quietly
2026-08-18 09:31:36 -07:00
Junio C Hamano 1428b15baf Merge branch 'kh/doc-refs-migrate-limitations'
The known limitations of the ref format migration in 'git refs' have
been moved to be displayed as a warning admonition directly under the
description of the 'migrate' subcommand, improving visibility.  A
reference to 'git-maintenance' has also been corrected to use the
'linkgit' macro.

* kh/doc-refs-migrate-limitations:
  doc: refs: linkgit to git-maintenance(1)
  doc: refs: put ref migration warning under the command
2026-08-18 09:31:36 -07:00
Kristoffer Haugsbakk 634257a89b doc: format-rev: use [synopsis] on code block
This code block uses the placeholder `<subject>`. Let’s highlight this
placeholder properly by using the `synopsis` open block definition which
was introduced in a34d1d53 (doc: convert git-show to synopsis style,
2026-02-06). This renders the block like a code block but with emphasis
styling on placeholders, just like inline-verbatim (`) in running text.

Yes, note that open blocks since commit a34d1d53 can, on synopsis-style
docs like this one, be immediately preceded by `[synopsis]`, just like
the command synopsis is:

    [synopsis]
    (EXPERIMENTAL!) git format-rev - [...]

Cf. verse-style:

    [verse]
    'git name-rev' [...]

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-17 13:33:06 -07:00
Kristoffer Haugsbakk ddd7de1341 doc: format-rev: quote subject placeholder before and after
We first talk about just `%s`, but then show the result with
quotes. That is inconsistent. Let’s use quotes both in the format
as well as in the result.

The implied input here, which is not spelled out for brevity, is:

    Did we not fix this in <commit object name>?

Which is then supposed to be formatted to `"<subject>"`.

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-17 13:33:06 -07:00
Junio C Hamano 18e66859d8 The 14th batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-15 09:20:27 -07:00
Junio C Hamano 230296d560 Merge branch 'jc/add-resolved'
'git add' has been taught a new '--resolved' option to stage
conflict-resolved paths, while leaving unrelated local changes
unstaged.  It scans the unmerged paths for leftover conflict
markers and aborts if any are found.

* jc/add-resolved:
  add: introduce '--resolved' option
  read-cache: add remove_file_from_index_with_flags()
  merge-ll: consolidate conflict marker scanning logic
  read-cache: reindent
2026-08-15 09:20:27 -07:00
Junio C Hamano 8b34c1f352 Merge branch 'tn/packfile-uri-concurrency'
Concurrent downloads of packfiles via packfile URIs and dumb HTTP are
safer by avoiding concurrent appends to the staging file.  Opening in
read-write mode with separate file offsets prevents corruption and
preserves resumability.  'fetch-pack' now tolerates pre-existing
'.keep' files.

* tn/packfile-uri-concurrency:
  fetch-pack: accept "pack" output for packfile URIs
  http: permit unlinking partial packs on Windows
  http: avoid concurrent appends to partial packs
  http: accept HTTP 416 for complete partial packs
  http: avoid closing index-pack input twice
  http-fetch: correct --index-pack-arg documentation
2026-08-15 09:20:27 -07:00
Swapnil Saste | INDIA 026636128f doc: fix typo in submitting patches
Remove the article "an" before "incremental updates".

Signed-off-by: Swapnil Saste | INDIA <theswapnilsaste@gmail.Com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-14 12:21:29 -07:00
Siddharth Shrimali c6fed8b7a6 builtin/repack: add guards for --drop-filtered
--drop-filtered removes local promisor blobs. That is only safe when the
repository is not mid-operation and when the blobs are not actively in
use, so add two guards, both skipped for bare repositories which have
neither a worktree nor an index.

First, refuse to run while a merge, rebase, am, cherry-pick, revert, or
bisect is in progress. During these operations the working tree and
index are in an intermediate state, and rewriting packs and deleting
objects underneath a half-finished operation is unsafe.

Second, refuse to drop a blob that the current index references. Such a
blob is needed by the working tree, so dropping it would only cause the
next command that touches the worktree to lazy-fetch it straight back,
reclaiming nothing. The offending path is reported so the user can see
why the drop was refused.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Siddharth Asthana <siddharthasthana31@gmail.com>
Signed-off-by: Siddharth Shrimali <r.siddharth.shrimali@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-13 13:34:50 -07:00
Siddharth Shrimali 0c4142a25b builtin/repack: actually drop filtered promisor blobs
Make --drop-filtered remove the enumerated promisor blobs instead of
only listing them.

The drop set is computed before repack_promisor_objects() runs, and on
a real run it is passed in so the rebuilt promisor pack omits those
blobs. --drop-filtered implies -d so the old promisor packs, which
still contain the dropped blobs, are removed. Without this the blobs
would survive in the redundant packs. The existing repack machinery
performs the write-before-delete and fsync, so the drop is crash-safe.

The dropped blobs become absent locally but remain recoverable from the
promisor remote, so a later access lazy-fetches them back
transparently. --dry-run keeps its previous behavior, i.e. it lists the
candidates and changes nothing.

Mentored-by: Christian Couder <christian.couder@gmail.com>
Mentored-by: Siddharth Asthana <siddharthasthana31@gmail.com>
Signed-off-by: Siddharth Shrimali <r.siddharth.shrimali@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-13 13:34:49 -07:00
Junio C Hamano 11c6700f10 The 13th batch
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-11 10:07:00 -07:00
Junio C Hamano 461ed7e1b3 Merge branch 'kh/doc-replay-config'
Documentation for 'git replay' has been updated to refer to its
configuration variables.

* kh/doc-replay-config:
  doc: replay: move “default” to the right-hand side
  doc: replay: use a nested description list
  doc: replay: improve config description
  doc: link to config for git-replay(1)
2026-08-11 10:07:00 -07:00
Junio C Hamano bf6bc2ae42 Merge branch 'ja/doc-synopsis-style-yet-more'
Synopsis and options in the documentation for 'git format-patch',
'git imap-send', 'git send-email', and 'git request-pull' have been
updated to the modern style.

* ja/doc-synopsis-style-yet-more:
  doc: convert git-request-pull synopsis and options to new style
  doc: convert git-send-email synopsis and options to new style
  doc: convert git-format-patch synopsis and options to new style
  doc: convert git-imap-send synopsis and options to new style
2026-08-11 10:06:59 -07:00
Kristofer Karlsson 56c9056e30 commit-reach: remove commit-date ordering fallback
Remove the fallback that switched paint_down_to_common() from
generation ordering to commit-date ordering when the commit-graph
lacks corrected commit dates (v1 graph with topo levels only).

The fallback was added in 091f4cf3 (commit: don't use generation
numbers if not needed, 2018-08-30) to avoid a performance
regression on the Linux kernel repo where v1 topo levels caused
"git merge-base v4.8 v4.9" to walk 636k commits instead of 167k.
A side branch with a low topo level stayed in the queue behind a
long chain, preventing early STALE propagation.

Side-exhaustion (added in the previous commits) solves this
differently by terminating the walk as soon as one paint side
empties from the queue, preventing the deep walk regardless of
queue ordering. Benchmarks of "git merge-base --all v4.8 v4.9"
on the Linux kernel repo show that side-exhaustion reduces the
step count far below what the date-ordering fallback achieved:

                         steps      time
  no graph, baseline:   167,413    3.25 s
  v1 graph, baseline:   167,413    0.25 s
  v2 graph, baseline:   167,441    0.29 s
  v1 graph, this series:  5,725    0.02 s
  v2 graph, this series:  3,887    0.01 s

With generation ordering always active, the existing min_generation
check in paint_queue_get() can safely terminate once the walk
crosses below the caller's generation floor. The date ordering
fallback broke this invariant: a commit could have a finite topo
level while the queue was date-ordered, causing the early exit to
fire before all merge bases were found.

With the fallback removed, gen_ordered is always true and can be
dropped. The topo_ceiling field (introduced earlier) already
handles V1_MAX saturation, so the early exit gates need no further
changes.

Signed-off-by: Kristofer Karlsson <krka@spotify.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-11 07:34:32 -07:00
Kristofer Karlsson 02d7ba092d commit-reach: terminate merge-base walk when one paint side is exhausted
Add an early termination check to paint_down_to_common() using the
per-side counters introduced earlier. Once the walk enters the
ordered region, terminate early when one side's exclusive count
drops to zero -- no new merge-base can form without both paint
sides meeting.

The check also waits for pending_merge_bases to reach zero, ensuring
all merge-base candidates have been dequeued and recorded before
exiting.

The optimization is gated by gen_ordered (which excludes v1
commit-graphs that use the date-ordering fallback) and by a
generation check against topo_ceiling. topo_ceiling is
GENERATION_NUMBER_INFINITY for v2 graphs and
GENERATION_NUMBER_V1_MAX for v1 graphs, so that saturated commits
are treated as unordered. Together these ensure the check only
fires in the ordered region where topological ordering holds.

The same topo_ceiling boundary is applied to the existing
single-result early exit so that all generation-dependent gates
express the same saturation-aware boundary consistently.

Step counts measured with trace2 on git.git with commit-graph:

  merge-base --all v2.0.0 v2.55.0-rc1:
    before: 72264 steps    after: 44589 steps

  merge-base --all v2.55.0-rc1 v2.55.0-rc1~5:
    before:   110 steps    after:     7 steps

Helped-by: Derrick Stolee <stolee@gmail.com>
Helped-by: Elijah Newren <newren@gmail.com>
Signed-off-by: Kristofer Karlsson <krka@spotify.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-11 07:34:32 -07:00
Kristofer Karlsson a3e5bad734 commit-reach: introduce struct paint_state with per-side counters
Add a paint_state struct for use by paint_down_to_common() that
wraps a prio_queue with per-side commit counters. Each non-stale
queued commit occupies exactly one counter bucket based on its
paint flags: PARENT1-only, PARENT2-only, or both sides (a pending
merge-base candidate).

The counters are maintained by paint_count_update() which adjusts
the appropriate bucket by a signed delta. An exhaustive switch on
the paint+stale bits documents all valid flag combinations in one
place.

Convert paint_down_to_common() to use paint_state. The loop now
drains the queue via paint_queue_get() which returns NULL when all
counters reach zero, replacing the old pointer-based termination
(max_nonstale). This is equivalent behavior -- both conditions
detect that no non-stale entries remain.

paint_queue_get() uses a "pop first" form: it dequeues a commit,
then checks the counters. This means the loop exits one iteration
earlier than the old code in some topologies (the popped stale
commit is never processed), so a few step counts drop by one.

The existing nonstale_queue is left in place for ahead_behind(),
though nonstale_queue_put_dedup() and nonstale_queue_get_dedup()
become unused and are removed.

Signed-off-by: Kristofer Karlsson <krka@spotify.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-11 07:34:32 -07:00
Kristofer Karlsson cd2ab0e128 Documentation/technical: add paint-down-to-common doc
Add a technical document describing the paint_down_to_common()
algorithm used for merge-base computation, covering the paint
walk, generation number regions, and termination conditions.

Signed-off-by: Kristofer Karlsson <krka@spotify.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-11 07:34:31 -07:00
Christian Couder 863937696e fast-import: use parse_options() for command line options
Previous commits have started to use the parse-options API to display
output from `git fast-import -h` and `git fast-import --help-all` and
to prepare for parsing the command line options using this API.

Let's now actually use the API to parse command line options.

This brings a number of changes that are mostly beneficial:

  - The `--alias`, `--get-mark`, `--cat-blob`, `--ls` and `--notes`
    options are no longer accepted on the command line. They were
    previously accepted as no-ops because parse_argv() fell through to
    parse_one_feature(). They are not documented in the OPTIONS section
    and are only meaningful as in-stream feature assertions, so
    accepting them on the command line was an accident of code sharing
    dating back to 9c8398f0c9 (fast-import: add option command,
    2009-12-04).

  - Abbreviated options like `--dep=5` now work since parse_options()
    allows unambiguous prefixes.

  - As `--cat-blob` is an abbreviation of `--cat-blob-fd`, using the
    former on the command line will fail with "option `cat-blob-fd'
    requires a value" unlike the other four options that are not
    accepted anymore on the command line (see above).

  - Value-taking options now also accept the space-separated
    `--opt value` form, like `--depth 5`, in addition to the
    `--opt=value` form.

  - A bare or trailing `--` is now accepted and the stream is read
    normally, while it used to be a usage error.

  - The error messages for some options might differ a bit.

  - The code is shorter and more standard.

Note that parse_one_feature() is now always called with its
`from_stream` argument set to 1, but the code simplifications that
can be made are left for a following clean-up commit.

Signed-off-by: Christian Couder <christian.couder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-11 07:33:17 -07:00
Christian Couder 27ab5815f7 fast-import: use struct option for usage string
Currently `git fast-import -h` shows the following on a single line:

  usage : git fast-import [--date-format=<f>] [--max-pack-size=<n>] \
                          [--big-file-threshold=<n>] [--depth=<n>] \
                          [--active-branches=<n>] \
                          [--export-marks=<marks.file>]

This output has a number of issues like:

  - It's missing a lot of options.
  - It's not consistent with the SYNOPSIS section of the doc.
  - With `--help-all` instead of `-h` additional hidden options should
    be shown, but that's not the case.
  - It's not standard style anymore.
  - Most other Git commands show additional lines for most of the
    options they support.

Also while most commands use the parse-options API to handle their
options, "builtin/fast-import.c" still doesn't use it.

Let's improve on that by using the parse-options API to display the
options when `-h` and `--help-all` are used.

While at it, let's make the SYNOPSIS section of
"Documentation/git-fast-import.adoc" consistent with the new usage
string.

This deliberately leaves it to future work to also use the
parse-options API to actually parse the options.

Signed-off-by: Christian Couder <christian.couder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-11 07:33:17 -07:00
Christian Couder 08b7e358e3 api-parse-options.adoc: document hidden and OPT_*_F option macros
In "Documentation/technical/api-parse-options.adoc", the list of option
macros does not mention the `OPT_*_F()` macro variants that take a
trailing `flags` argument, nor the `OPT_HIDDEN_GROUP()` and
`OPT_HIDDEN_BOOL()` convenience macros.

Now that a previous commit documents the per-option flags, let's
document these macros too:

  - Add a paragraph explaining the `OPT_*_F` convention and how it
    relates to the per-option flags.

  - Document `OPT_HIDDEN_GROUP()`, introduced in a previous commit,
    right after `OPT_GROUP()`.

  - Document `OPT_HIDDEN_BOOL()` right after `OPT_BOOL()`.

Signed-off-by: Christian Couder <christian.couder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-11 07:33:16 -07:00
Christian Couder e455bade3a api-parse-options.adoc: document per-option flags
The "Flags" section in "Documentation/technical/api-parse-options.adoc"
documents the flags that can be passed to parse_options() itself. It
does not, however, document the flags that can be set on individual
options through the `flags` member of `struct option` (and through the
`OPT_*_F()` macro variants).

These per-option flags are used throughout the codebase (for example
`PARSE_OPT_HIDDEN` is used to hide an option from `-h` while still
showing it with `--help-all`), but a reader currently has to dig into
"parse-options.h" to find them.

To remediate that, let's add an "Option flags" subsection to the
"Data Structure" section, just before the list of option macros.

Let's also make it explicit that these are distinct from the
parse_options() flags described earlier, and let's describe the `-h`
versus `--help-all` behavior for `PARSE_OPT_HIDDEN`.

Signed-off-by: Christian Couder <christian.couder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-11 07:33:16 -07:00
Junio C Hamano 78d1e468ea Merge branch 'kh/doc-trailers' into kh/trailers-no-urls
* kh/doc-trailers:
  doc: interpret-trailers: document comment line treatment
  doc: interpret-trailers: rewrite new-trailers paragraphs
  doc: interpret-trailers: commit to “trailer block” term
  doc: interpret-trailers: join new-trailers again
  doc: interpret-trailers: add key format example
  doc: interpret-trailers: explain key format
  doc: interpret-trailers: explain the format after the intro
  doc: interpret-trailers: not just for commit messages
  doc: interpret-trailers: use “metadata” in Name as well
  doc: interpret-trailers: replace “lines” with “metadata”
  doc: interpret-trailers: stop fixating on RFC 822
2026-08-10 11:26:27 -07:00
Kristoffer Haugsbakk 4515c86fd9 doc: interpret-trailers: document comment line treatment
Comment lines have always been ignored but this is not documented.

The primary motivation here is to be reasonably complete in the
documentation of how trailers are parsed; this is after all the only
documentation page that documents this format. However, and going beyond
that point, we could imagine that someone would want to use this format
outside a commit (or tag) message context, like say in Git notes.

On the other hand, it seems far-fetched that someone would be caught
off guard by this considering that comment characters/strings are not
likely to be alphanumeric,[1] which would mean that these comment lines
would be treated as non-trailer lines if they were *not* detected and
removed as comment lines.

† 1: A notable exception is that Jujutsu VCS uses `JJ:` as
     the comment string

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-10 11:05:52 -07:00
Kristoffer Haugsbakk cb657364d5 doc: interpret-trailers: rewrite new-trailers paragraphs
Two commits ago we moved new-trailers paragraph next to each other.
But there is something curious about two of them:

    By default the new trailer will appear at the end of the trailer
    block. [...]

Then a source block and a paragraph later:

    By default, a `<key>=<value>` or `<key>:<value>` argument given
    using `--trailer` will be appended after the existing trailers only
    if [...]

Why are there two paragraphs that talk about how “By default” a trailer
will be appended?

We can make these paragraphs flow better, and with a more distinct
character each, by dividing the flow like this:

1. Declare that we are about to talk about `--trailer` appending
2. Explain the default behavior
3. Explain how this affects the trailer block
4. Then discuss what each trailer line will look like

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-10 11:05:52 -07:00
Kristoffer Haugsbakk 4d45e571ae doc: interpret-trailers: commit to “trailer block” term
We chose to introduce the term “trailer block” into the documentation a
few commits ago.[1] It is used in the code though, so it is not a newly
invented term.

That term was useful to explain where the trailers are found (they
*trail* the message). But it is also useful here, where we explain
how trailers are added to existing messages, how trailer blocks are
found (beyond the simple case in the introduction), and how the end
of the message is found.

Also note that we simplify the “blank line” point. The text says:

    A blank line will be added before the new trailer if there isn't one
    already.

But this isn’t quite coherent. The previous sentence says “If there is
no existing trailer”, so we are in one of these modes:

1. discussing trailer blocks in general; or
2. discussing creating a new trailer block in particular.

If (1), then we shouldn’t add a blank line before the new trailer if
there exists a trailer block already. And if (2), then the “if there
isn’t one already” is redundant.[2] So just talking about the higher-
level “trailer block” simplifies the text, since we don’t have to worry
about the different contexts that *trailers* can find themselves in.

† 1: in commit “explain the format after the intro”
† 2: Note that non-trailer lines don’t matter here; if you have a
     trailer block consisting of `(cherry picked from commit <commit>)`,
     then you still shouldn’t insert a blank line before the new trailer
     since that would create a new trailer block

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-10 11:05:52 -07:00
Kristoffer Haugsbakk 1e4200ede5 doc: interpret-trailers: join new-trailers again
There are three paragraphs that talk about how a new trailer is added.
But the first one is separated from the other two by two paragraphs
about how `key-alias` can make using `--trailer` more convenient. This
short how-to does not follow thematically from the previous paragraph,
and can wait until we have fully described how a new trailer is
added. So let’s move the three paragraphs about the new-trailer topic
together and move the how-to paragraphs after that.

***

Let’s now review the history of the document. Even if the document
is not quite correct in its current state, just doing the apparently
obvious edit without considering the history does not respect the
effort that went into changing the document in the past.

These three paragraphs were originally next to each other, in the first
version of the doc.[1] But extra sentences about this how-to topic was
added to the first paragraph nine years later:[2]

    [...]
    `': '` (one colon followed by one space). For convenience, the
    <token> can be a shortened string key (e.g., "sign") instead of the
    full string which should [...]

And then it was split into it’s own paragraph a little later.[3]

This evolution shows, in my opinion, that this how-to never followed
thematically from the existing topic. Which means that there is nothing
that was potentially lost to time that we need to restore or respect.

† 1: dfd66ddf (Documentation: add documentation for 'git
     interpret-trailers', 2014-10-13)
† 2: eda2c44c (doc: trailer: mention 'key' in DESCRIPTION, 2023-06-15)
† 3: 6ccbc667 (trailer doc: <token> is a <key> or <keyAlias>, not both,
     2023-09-07)

Suggested-by: D. Ben Knoble <ben.knoble+github@gmail.com>
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-10 11:05:52 -07:00
Kristoffer Haugsbakk fddec1fe11 doc: interpret-trailers: add key format example
All of the examples speak of the Happy Path where everything works
as intended. But failure examples can also be instructive. Especially
for explaining again, by example, the key format (see previous commit).

This also allows us to demonstrate trailer block detection with a
concrete example.

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-10 11:05:52 -07:00
Kristoffer Haugsbakk fd39e5a481 doc: interpret-trailers: explain key format
A trailer key must consist of ASCII alphanumeric characters and
hyphens *only*. Let’s document it explicitly instead of relying on
readers being conservative and only basing their trailer keys on the
documentation examples.[1]

The previous commit provided us with an appropriate paragraph to
describe the key format.

† 1: Technically they would then miss out on using digits in them since
     all of the example keys just use letters and hyphens

Reported-by: Brendan Jackman <jackmanb@google.com>
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-10 11:05:52 -07:00
Kristoffer Haugsbakk c88d60db44 doc: interpret-trailers: explain the format after the intro
You need to read the entire “Description” section in order to understand
the full trailer format. But there are many nuances, so that’s fine.
As a starter though we have an introductory example.[1] That turns out
to be crucial; the rest of this section talks about the mechanics of the
command and only incidentally the format itself.

Now, although the example might arguably be self-explanatory, we can
add a little preamble which defines the format in its simplest form as
well as define the most important terms.

Note that we name the “blank line” rule since I want to use that term
every time it comes up. It gets very mildly obfuscated if you call it
a “blank line” in one place[2] and “empty (or whitespace-only) ...” in
another one.[3]

We will define the format of the *key* in the next commit.

† 1: from d57fa7fc (doc: trailer: add more examples in DESCRIPTION,
     2023-06-15)
† 2: `Documentation/git-interpret-trailers.adoc:86` in
     5361983c (The 22nd batch, 2026-03-27)
† 3: `Documentation/git-interpret-trailers.adoc:93` in
     5361983c (The 22nd batch, 2026-03-27)

Suggested-by: D. Ben Knoble <ben.knoble+github@gmail.com>
Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-10 11:05:51 -07:00
Kristoffer Haugsbakk 33691bc9d7 doc: interpret-trailers: not just for commit messages
This command doesn’t interface with commits directly. You can
interpret or modify any kind of text, even though commit messages
are the most relevant.

The git(1) suite also isn’t restricted to only direct commit support
since git-tag(1) learned `--trailer` in 066cef77 (builtin/tag: add
--trailer option, 2024-05-05)

Now, we already introduce the command in the “Name” section as dealing
with commit messages as well. That is fine since that intro line needs
to remain pretty short.

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-10 11:05:51 -07:00
Kristoffer Haugsbakk 500257fd2b doc: interpret-trailers: use “metadata” in Name as well
We now since the previous commit introduce the format as “trailer
metadata”. We can replace “structured information” with “metadata”
in the “Name” section to be consistent.

While “structured information” does emphasize that the data is not
loosely structured, we also say that this command adds to or parses
this format. I don’t think that we need to emphasize that it is
structured since clearly there is some structure there.

Both “metadata” and “structured information” can convey the same
information. But “metadata” is shorter and easier to deploy since
it’s just one word.

Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-08-10 11:05:51 -07:00