Commit Graph

82780 Commits (seen)

Author SHA1 Message Date
Junio C Hamano 9c1d9033c4 Merge branch 'bb/imap-send-openssl-set-verify' into seen
imap-send used to use hand coded peer hostname verification,
which has been replaced with the native API OpenSSL offered since
version 1.1.0.

* bb/imap-send-openssl-set-verify:
  imap-send: let OpenSSL do the hostname verification
  imap-send: use the recommended TLS_method()
2026-10-12 14:25:16 -07:00
Junio C Hamano fe457deda3 Merge branch 'bb/unicode-width-table-18' into seen
Unicode character width table has been updated to match
Unicode 18 announced on 2026-09-16.

* bb/unicode-width-table-18:
  unicode: update the width tables to Unicode 18
2026-10-12 14:24:07 -07:00
Junio C Hamano e2027e145e Merge branch 'dk/stash-completion-updates' into seen
The command-line completion for 'git stash' has been updated to
dynamically discover subcommands and to correct a Zsh-specific
formatting issue where stash references were improperly unquoted.
Additionally, the deprecated 'save' subcommand has been removed from
completions and synopsis documentation.

* dk/stash-completion-updates:
  completion: drop "stash save" completion altogether
  doc: drop usage mentions of "git stash save"
  completion: fix Zsh handling of stash names
  completion: extract common stash listing code
  completion: simplify stash subcommand completion
2026-10-12 14:23:54 -07:00
Junio C Hamano ddd528c137 Merge branch 'ic/includeif-hostname' into seen
The conditional configuration inclusion mechanism via 'includeIf'
has been extended to support matching the machine's hostname, and
the system's hostname as seen by Git can now be queried using 'git
var GIT_HOSTNAME'.

* ic/includeif-hostname:
  config: learn the "hostname:" includeIf condition
  t6500: get hostname from "git var"
  var: add GIT_HOSTNAME
2026-10-12 14:23:54 -07:00
Junio C Hamano c64409ac5b Merge branch 'kn/fetch-tag-backfill-batch-fix' into seen
When 'git fetch' uses batched reference updates, references are not
committed before backfilling tags, causing shallow fetches to report
no local references during negotiation and receive all objects from
the server again.  The batched update is now committed before tag
backfilling begins.

* kn/fetch-tag-backfill-batch-fix:
  fetch: commit references fetched before backfilling tags
2026-10-12 14:23:54 -07:00
Junio C Hamano 824e95128e Merge branch 'kk/connectivity-check-incremental' into seen
The connectivity check in 'git fetch' and 'git receive-pack' has
been optimized with an alternative incremental mode, available via
'transfer.connectivityCheck=incremental'.  Instead of walking the
full object closure of the boundary commits, it compares the trees
of incoming commits against their trusted parent trees, skipping
unchanged subtrees.

* kk/connectivity-check-incremental:
  connected: add incremental connectivity check via rev-list
  connected: add transfer.connectivityCheck config and rev-list flag
  p5413: add perf tests for connectivity check
  Documentation: describe connectivity checking
2026-10-12 14:23:53 -07:00
Junio C Hamano 091dad56d7 Merge branch 'hn/fetch-refmap' into seen
In a shallow repository, adding a new remote and fetching from it
used to eagerly fetch all remote branches.  The default refspec
configured for remotes added in shallow repositories has been
changed to rely on `remote.<name>.refmap` rather than
`remote.<name>.fetch`, pulling only those remote branches tracked
by local branches.

* hn/fetch-refmap:
  remote: default to --limited-fetch in a shallow repository
  remote: add "git remote add --limited-fetch"
  fetch: infer branches to fetch from a refmap-only remote
  fetch: extract collect_upstream_from_remote() helper
  fetch: add remote.<name>.refmap
2026-10-12 14:23:53 -07:00
Junio C Hamano 4e578a56e4 Merge branch 'js/push-refspec-match-speedup' into seen
The client-side refspec matching during 'git push' has been
optimized by replacing linear traversals with string map lookups,
speeding up pushes with lots of delete refspecs against a server
with many advertised refs.

* js/push-refspec-match-speedup:
  remote: use strmap for apply_push_cas()
  remote: restructure apply_push_cas() loops
  t/perf: measure --force-with-lease in p5516
  remote: use strmap for match_explicit_refs()
  remote: reject duplicate destinations on an empty remote
  t5408: expect client-side error for duplicate destinations
  t5408: check refspec order with distinct destinations
  t5408, t5410: test duplicate updates without relying on the client
  t5516: test pushing two refspecs creating the same new branch
  remote: use strmap for check_push_refs()
  refs: stop using mkpath() in refname_match()
  t/perf: add explicit delete refspec matching test
  t5510: document fetch with "./"-prefixed branch.<name>.merge
  t5516: demonstrate push with "./"-prefixed source
  remote: validate --force-with-lease <refname> argument
2026-10-12 14:23:53 -07:00
Beat Bolli 84b5d49790 imap-send: let OpenSSL do the hostname verification
According to the OpenSSL Wiki[1], OpenSSL knows how to verify the peer's
hostname since version 1.0.2. A simpler interface is available since
1.1.0, which is what is implemented here.

As a side-effect, we get all present and future improvements done by
OpenSSL for free. E.g., the old code did not handle IP addresses in the
subject alternative names, while the new code does.

If the verification fails, print the error message as returned by
OpenSSL.

[1]: https://wiki.openssl.org/index.php/Hostname_validation

Suggested-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Beat Bolli <dev+git@drbeat.li>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 14:19:03 -07:00
Beat Bolli 0267ebcfc1 imap-send: use the recommended TLS_method()
SSLv23_method() has been deprecated since OpenSSL 1.1.0, and
TLS_method() is the recommended function.

Signed-off-by: Beat Bolli <dev+git@drbeat.li>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 14:19:03 -07:00
Beat Bolli 01de14365d unicode: update the width tables to Unicode 18
Unicode 18 has been announced on 2026-09-16 [0], so update the character
width tables to the new version.

[0] https://blog.unicode.org/2026/09/announcing-unicode-standard-version-180.html

Signed-off-by: Beat Bolli <dev+git@drbeat.li>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 14:18:13 -07:00
Junio C Hamano ca3ceba753 Merge branch 'rs/archive-zip-omit-out-of-range-mtime' into seen
The ZIP archive creation code has been updated to omit the 'UT'
extended timestamp extra field when the commit time exceeds the
32-bit positive signed integer limit, avoiding integer wraparound
for dates past the year 2038.

* rs/archive-zip-omit-out-of-range-mtime:
  SQUASH??? if time_t is 64 bit timestamp_t aka uintmax_t should also be wide enough, but the converse is not necessarily true
  archive-zip: omit UT extra field if mtime is out of range
2026-10-12 13:00:06 -07:00
Junio C Hamano ba66b805fc Merge branch 'js/doc-test-fix-anti-pattern' into seen
The 'SubmittingPatches' document has been updated to discourage the
anti-pattern of adding a failing test in one commit and fixing it in
a subsequent one, advising contributors to combine the test and fix
into a single commit for easier review

* js/doc-test-fix-anti-pattern:
  SubmittingPatches: avoid add-failing-test-then-fix anti-pattern
2026-10-12 13:00:05 -07:00
Junio C Hamano a47500a8a2 Merge branch 'ps/setup-enforce-repo-passed-to-create-repository-has-no-state' into seen
The repository initialization sequence has been refactored to treat
the repository object passed to create_repository() purely as an
out-parameter.

* ps/setup-enforce-repo-passed-to-create-repository-has-no-state:
  setup: enforce that passed-in repo does not carry relevant state
  repository: adapt `repo_clear()` to fully reset the repository
  builtin/clone: don't apply "core.sharedRepository" to leading dirs
  builtin/init: move handling of "core.sharedRepository" into "setup.c"
  builtin/init: refactor messy creation of leading directories
  path: introduce `safe_create_leading_directories_no_share_const()`
  path: drop useless `safe_create_leading_directories_1()`
2026-10-12 13:00:05 -07:00
Junio C Hamano 6d9ab1893b Merge branch 'je/doc-merge-conflicts' into seen
A new user manual page on how to resolve merge conflicts has been
introduced, and other commands that could encounter conflicts have
been updated to link to it.

* je/doc-merge-conflicts:
  SQUASH???
  doc: git-pull: link to new merge conflicts guide
  doc: git-cherry-pick: link to new merge conflicts guide
  doc: git-revert: link to new merge conflicts guide
  doc: git-rebase: link to new merge conflicts guide
  doc: git-merge: link to new merge conflicts guide
  doc: add new gitmergeconflicts man page
2026-10-12 13:00:05 -07:00
Junio C Hamano 084100f874 Merge branch 'rm/blame-default-ignore-revs' into seen
'git blame' and 'git annotate' have been updated to automatically
use the 'HEAD:.git-blame-ignore-revs' blob as the default ignore
list if it exists, aligning local behavior with major hosting
platforms.  The parser and tag-peeling machinery have been hardened
against missing objects and malformed files.

* rm/blame-default-ignore-revs:
  blame: ignore revs in HEAD:.git-blame-ignore-revs
  blame: harden ignore-revs parser and tag peeling
2026-10-12 13:00:05 -07:00
Ravi Mistry 3507b40dc7 blame: ignore revs in HEAD:.git-blame-ignore-revs
git-blame(1) can ignore a list of commits specified via
--ignore-revs-file or the blame.ignoreRevsFile configuration option.
This is useful for skipping uninteresting revisions such as tree-wide
formatting changes, large-scale refactors, and code modernizations that
would otherwise obscure genuine historical authorship.

When revision-ignoring was introduced in commit ae3f36dea1 ("blame: add
blame.ignoreRevsFile config option", 2019-10-18), it intentionally
avoided adopting a default ignore file. At the time, the capability was
new and unproven, so avoiding unrequested filesystem I/O or unexpected
attribution shifts took priority over a project-wide default.
Requiring explicit opt-in per clone was therefore the prudent design.

Since then, maintaining a .git-blame-ignore-revs file in the repository
root has become the de facto standard across the Git ecosystem, adopted
by major hosting platforms (GitHub, GitLab, Gerrit) and prominent open
source projects (such as Chromium and LLVM). As a consequence,
developers frequently encounter a jarring mismatch: web interfaces
seamlessly ignore formatting commits, but local git-blame(1) and
git-annotate(1) runs do not, unless each user manually configures
blame.ignoreRevsFile for every local checkout.

Teach git-blame(1) and git-annotate(1) to automatically add the
HEAD:.git-blame-ignore-revs blob, if it exists, as the initial element
in the list of ignore-revs files in both bare and non-bare
repositories. Reading the committed blob from HEAD rather than the
working tree ensures that local runs match hosting platforms even when
an untracked .git-blame-ignore-revs file is present or a tracked one
has uncommitted local changes.

To ensure consistent precedence and override semantics:
- The default HEAD:.git-blame-ignore-revs entry is added before reading
  configuration and CLI options, preserving user and repository config
  overrides.
- In git_blame_config(), blame.ignoreRevsFile entries are appended via
  string_list_append() rather than inserted in sorted order via
  string_list_insert() so that configuration entries preserve their
  order relative to the initial default entry.
- The HEAD:.git-blame-ignore-revs tree entry is resolved quietly via
  get_oid_with_context(). Its mode is checked with S_ISREG() before
  reading the object so that non-regular tree entries (such as a
  committed symbolic link whose blob stores a target path rather than
  revision IDs, a subdirectory, or a gitlink) are skipped instead of
  being read and rejected as malformed object names. Its size is checked
  via odb_read_object_info() and capped at IGNORE_REVS_MAX_FILE_SIZE
  (100MB, matching ATTR_MAX_FILE_SIZE from 3c50032ff5 ("attr: ignore
  overly large gitattributes files", 2022-12-01)) so an oversized blob
  is skipped with a warning without being loaded into memory. The blob
  is parsed in memory via a new oidset_parse_buffer_carefully() helper
  in oidset.c that shares line parsing with
  oidset_parse_file_carefully().
- In build_ignorelist(), ignore-revs entries are processed starting
  after the last empty string entry. This ensures setting
  blame.ignoreRevsFile to "" or passing --ignore-revs-file "" or
  --no-ignore-revs-file cleanly discards the default blob without
  attempting to read or parse it, allowing users to bypass a malformed
  default blob.

Update documentation in blame-options.adoc and config/blame.adoc, and
add comprehensive test coverage in t8013 for the default blob lookup,
subdirectory invocations, bare repositories, uncommitted and untracked
working-tree files, CLI and config overrides, committed symlink
entries, overly large blobs, and comments and whitespace handling.

Based-on-patch-by: Abhijeetsingh Meena <abhijeet040403@gmail.com>
Helped-by: Kristoffer Haugsbakk <code@khaugsbakk.name>
Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk>
Helped-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Ravi Mistry <rmistry@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 12:58:54 -07:00
Ravi Mistry f3dfec9283 blame: harden ignore-revs parser and tag peeling
Currently, blame.ignoreRevsFile and --ignore-revs-file only read paths
explicitly configured by the user, which cannot point to an
attacker-controlled file under Git's threat model. An upcoming commit
will teach git-blame(1) and git-annotate(1) to automatically read the
HEAD:.git-blame-ignore-revs blob by default if it exists, exposing the
ignore-revs parser (oidset_parse_file_carefully() in oidset.c) and its
tag-peeling callback (peel_to_commit_oid() in builtin/blame.c) to
upstream-controlled content at a well-known path.

Harden both code paths before enabling the default blob:

- In oidset_parse_file_carefully(), strbuf_getline() reads up to the
  next newline and records the full line length in sb.len, including
  any embedded NUL bytes. However, strchr(sb.buf, '#') and
  parse_oid_hex_algop(sb.buf, &oid, &p, algop) treat sb.buf as a
  NUL-terminated string. If a line contains an embedded NUL byte after
  a valid object name (such as "<oid>\0garbage" or "<oid>\0# comment"),
  *p is '\0' and trailing bytes on the line are silently ignored.
  Reject any line containing an embedded NUL byte via memchr() before
  stripping comments and whitespace.
- In peel_to_commit_oid(), odb_read_object_info() is called without
  OBJECT_INFO_SKIP_FETCH_OBJECT or OBJECT_INFO_QUICK, and deref_tag()
  calls parse_object() on tag targets without checking whether the
  target object exists locally first. In a partial clone, any missing
  commit OID or tag target listed in the ignore-revs file would trigger
  lazy promisor fetches and pack directory rescans during git-blame(1).
  Use odb_read_object_info_extended() with OBJECT_INFO_LOOKUP_REPLACE |
  OBJECT_INFO_SKIP_FETCH_OBJECT | OBJECT_INFO_QUICK and peel OBJ_TAG
  objects one layer per iteration, verifying that each target object
  exists locally and matches the tag's declared type before parsing it.

Signed-off-by: Ravi Mistry <rmistry@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 12:58:54 -07:00
D. Ben Knoble 7a7f8f8d87 completion: drop "stash save" completion altogether
It's been deprecated since fd2ebf14db (stash: mark "git stash save"
deprecated in the man page, 2017-10-22) and the previous commit removed
further documentation suggesting to use it.

Since we recommend push instead, stop completing for "save" and remove a
special case in completion code.

Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 12:55:55 -07:00
D. Ben Knoble f4c8d30a74 doc: drop usage mentions of "git stash save"
Even though we previously deprecated it in fd2ebf14db (stash: mark "git
stash save" deprecated in the man page, 2017-10-22), the save subcommand
clings to life. For example, 951ec747d4 (doc txt & -h consistency: make
"stash" consistent, 2022-10-13) brought back "save" to the git-stash(1)
synopsis, and 41a28eb6c1 (stash: implement '--staged' option for 'push'
and 'save', 2021-10-18) gave it new options. But we really discourage
its use in modern Git, so let's drop mention of it from -h usage and the
synopsis.

It's still described in the manual, since some descriptions talk about
the "save" command. As we haven't gone ahead with a full deprecation and
removal, we can leave these pieces for folks whose fingers still type
"save" and need a reference for its behavior.

Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 12:55:55 -07:00
D. Ben Knoble f4ced7cb0b completion: fix Zsh handling of stash names
When Git completes stashes for Zsh, it eventually invokes something like
this (via our redefinition of __gitcomp_nl):

    compadd -Q -S " " -p "" -- 'stash@{0}' 'stash@{1}' && _ret=0

Because of -Q, the braces are unquoted, and Zsh will leave us at (for
example)

    git stash show stash@{
                   cursor ^

>From here, the list-choices widget (on Ctrl-D by default) will show
stash@{0} and stash@{1}, but the complete-word widget (Tab) will just
add another brace. Zsh things we're trying to do a brace expansion, I
think! Interestingly, using menu-complete (Ctrl-N) does cycle through
matches, since it's taking a slightly different completion path in Zsh.

We might try to fix this by passing surrounding single quotes (using the
-S/-p arguments of compadd, which we can do via __gitcomp_nl's other
parameters), and indeed Zsh will generate

    git stash show 'stash@{
                    cursor ^

but completing here won't find anything, and I'm not totally sure why.

Instead, though, we can let Zsh quote metacharacters (removing -Q) and
everything "just works." It changes the output format a bit (users see
stash@\{0\}, for example), but I find this an improvement over not being
able to complete names at all. menu-complete is unchanged aside from the
extra backslashes.

So, override stash listing completion in Zsh with a working version.

Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 12:55:55 -07:00
D. Ben Knoble 4ee00faa9d completion: extract common stash listing code
With no change in behavior, prepare to adjust how stashes are completed
by centralizing candidate generation.

Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 12:55:55 -07:00
D. Ben Knoble 43f61f9f67 completion: simplify stash subcommand completion
The stash completion helper contains a hard-coded list of commands, but
git-stash provides a mechanism to list such commands
(--git-completion-helper). The pattern for using it is wrapped by
__git_resolve_builtins, so use it, bring _git_stash closer in line with
other completion helpers.

Note that we maintain the "save" special case, since it was removed from
default completion in 0eb5a4f911 (completion: stop showing 'save' for
stash by default, 2018-04-20). We don't have to do anything special with
the exclude (3rd) argument to __git_resolve_builtins, though, because
save is already marked PARSE_OPT_NOCOMPLETE.

Signed-off-by: D. Ben Knoble <ben.knoble@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 12:55:55 -07:00
Isabella Caselli b2f3c53e6c config: learn the "hostname:" includeIf condition
When the same home directory is shared across multiple machines, they
all read the same ~/.gitconfig. Settings that should differ between
machines therefore need a way to make that file behave differently
on each host. The same problem affects people who keep their dotfiles
in a repository and check them out on multiple machines.

Add a "hostname:" keyword to includeIf. The value that follows is a
pattern supporting standard glob wildcards, and the condition is met
when the machine's hostname matches it. If the hostname cannot be
determined, the condition is not met.

Depending on the system configuration, the hostname may be either a
short name or a fully qualified domain name. Making the name fully
qualified ourselves was considered, but it could require a DNS lookup
while reading the configuration. Instead, match the name as the
system reports it, document this, and point to "git var GIT_HOSTNAME"
as a way to check the value being matched.

The tests obtain the hostname with "git var GIT_HOSTNAME" before
writing the configuration, so that a failure to retrieve it makes
the test fail instead of going unnoticed inside the here-document.

Based-on-patch-by: Ignacio Encinas <ignacio@iencinas.com>
Signed-off-by: Isabella Caselli <bellacaselli20@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 12:12:50 -07:00
Isabella Caselli a37cc0bf49 t6500: get hostname from "git var"
The test "background auto gc respects lock for all operations" simulates
a concurrent gc by writing our shell's pid and hostname to "gc.pid".
It gets the hostname from the "hostname" command, falling back to
"unknown" if the command fails.

"git gc" gets its hostname from the system and only checks whether the
pid is alive if the two hostnames match. Otherwise, it assumes the
lock belongs to a gc running on another machine. Since the test passes
in either case, a missing "hostname" command or a mismatch between
its output and the system hostname can cause the test to silently
exercise the wrong case.

Use "git var GIT_HOSTNAME" to get the same hostname as "git gc".
Keep the "unknown" fallback, which is also used by "git gc" when it
cannot determine the hostname.

Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Isabella Caselli <bellacaselli20@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 12:12:50 -07:00
Isabella Caselli a13fc94041 var: add GIT_HOSTNAME
Git asks the system for the name of the machine it runs on in a few
places. For example, "git gc" records it in "gc.pid" to tell whether
the gc holding the lock runs on the same machine. Users have no way
to see which name Git uses, and depending on how the system is
configured, it may be a short name ("myhost") or a fully qualified
one ("myhost.example.com").

This matters more once the config can depend on the hostname, which
a later commit adds as an includeIf condition. Without a way to see
the value Git uses, users would have to guess what to write in their
config file.

Add a GIT_HOSTNAME variable to "git var" that prints the hostname
Git sees. If the hostname can't be determined, "git var GIT_HOSTNAME"
exits with a non-zero status, and "git var -l" omits the variable
instead of failing.

An option to "git config" to show the hostname was also discussed,
but "git var" was chosen, since the hostname is not specific to
the configuration code.

The test only checks that a non-empty value is printed. The test has
no independent way to know the expected hostname, as the "hostname"
command may not agree with what Git sees on every platform. The
includeIf tests added later check that the value matches what the
configuration code uses.

Suggested-by: Eric Sunshine <sunshine@sunshineco.com>
Suggested-by: Jeff King <peff@peff.net>
Signed-off-by: Isabella Caselli <bellacaselli20@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 12:12:50 -07:00
Karthik Nayak 7c7389a817 fetch: commit references fetched before backfilling tags
In 0e358de64a (fetch: use batched reference updates, 2025-05-19), the
fetch code was modified to use batched updates to provide a good
performance improvement. Wherein batched updates were used to fetch both
references and backfill tags.

When using batched updates, the references aren't yet committed to disk
when we start backfilling tags. This means in situations such as shallow
fetching the negotiation during backfilling tags, the client doesn't
have any references to report in the 'have' section. Since backfilling
doesn't use a depth limit, this can cause the server to send all the
objects present in the repository.

Fix this by committing the previous batched update and initiating a new
one for backfilling tags. Also add a test which captures this regression.

While this does make it a little slower than master, due to two
transactions:

Benchmark 1: fetch: many refs (refformat = reftable, refcount = 10000, revision = master)
  Time (mean ± σ):      82.1 ms ±   3.3 ms    [User: 60.2 ms, System: 24.4 ms]
  Range (min … max):    77.4 ms …  89.4 ms    33 runs

Benchmark 2: fetch: many refs (refformat = reftable, refcount = 10000, revision = HEAD)
  Time (mean ± σ):      82.6 ms ±   2.4 ms    [User: 59.3 ms, System: 25.2 ms]
  Range (min … max):    78.1 ms …  88.7 ms    31 runs

Summary
  fetch: many refs (refformat = reftable, refcount = 10000, revision = master) ran
   1.01 ± 0.05 times faster than fetch: many refs (refformat = reftable, refcount = 10000, revision = HEAD)

It is still faster than not using batched updates:

Benchmark 1: fetch: many refs (refformat = reftable, refcount = 10000, revision = 0e358de64a9e014575d11ef884bfc9beb931e37f~1)
  Time (mean ± σ):      1.468 s ±  0.041 s    [User: 0.839 s, System: 0.587 s]
  Range (min … max):    1.427 s …  1.558 s    10 runs

Benchmark 2: fetch: many refs (refformat = reftable, refcount = 10000, revision = HEAD)
  Time (mean ± σ):      84.4 ms ±   1.7 ms    [User: 60.9 ms, System: 25.8 ms]
  Range (min … max):    81.4 ms …  88.6 ms    29 runs

Summary
  fetch: many refs (refformat = reftable, refcount = 10000, revision = HEAD) ran
   17.38 ± 0.61 times faster than fetch: many refs (refformat = reftable, refcount = 10000, revision = 0e358de64a9e014575d11ef884bfc9beb931e37f~1)

Reported-by: Mitja Bezenšek <mitja.bezensek@login5.org>
Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 11:59:19 -07:00
Kristofer Karlsson d97569f0c3 connected: add incremental connectivity check via rev-list
The full connectivity check uses rev-list to find commits
reachable from the incoming tips but not from the
already-connected side, then walks their object closure.  Commit
traversal stops at the connectivity boundary, but trees and blobs
reachable from that boundary still need to be walked so they can
be marked uninteresting, allocating a struct object for each one.
On repositories where the boundary commits have large trees, the
connectivity check for small incoming changes visits and tracks
more objects than needed.

Add an alternative connectivity check that verifies incoming
commits incrementally against their parents.

The verifier processes incoming commits with ancestors first and
compares each new tree against its trusted parent trees.  Entries
already seen on the trusted side are skipped by OID, so unchanged
subtrees need not remain at the same path to be recognized.
Changed subtrees are recursively compared against same-path parent
subtrees, and new subtrees without a comparison base are verified
from scratch.

See Documentation/technical/connectivity-check.adoc for the trust
invariants and detailed algorithm.

The incremental check runs as an internal
--verify-trees-incremental mode in rev-list.  After the normal
revision walk identifies the incoming commits, the verifier
consumes them before the usual object traversal; any pending
non-commit tips are still handled by the existing traversal.

Partial-clone semantics are preserved: objects promised by a
promisor remote are accepted as connected, and on-demand fetching
is prevented by excluding promisor objects from traversal.  The
new mode is selected by transfer.connectivityCheck=incremental,
with full remaining the default.  Deepening fetches fall back to
the full check because they do not have the normal
existing-reference boundary, and traversal instead follows the
effective shallow boundary.

p5413 results (median of 3), scaling one dimension at a time.
Each fixture is a repository with a flat tree of many
directories containing 100 files each.  The incoming set is a
chain of commits on top of the existing history, with each
commit changing files in different directories round-robin.
The three axes vary the total repository tree size, the number
of incoming commits, and the number of files changed per
incoming commit.

Scaling tree size (10 incoming commits, 10 files/commit):

    files    full  incr.  full/incr
      5K    0.01s  0.01s    1.0x
     50K    0.04s  0.01s    4.0x
    200K    0.15s  0.01s   15.0x
    800K    0.61s  0.03s   20.3x

The full mode must walk the trees of boundary commits, which
grows with overall tree size.  Incremental still scans the
root trees, but avoids descending into unchanged subtrees,
so it grows much more slowly with repository size.

Scaling incoming commit count (200K files, 10 files/commit):

    commits    full  incr.  full/incr
          1    0.14s  0.01s   14.0x
         10    0.15s  0.01s   15.0x
        100    0.19s  0.05s    3.8x
        500    0.32s  0.27s    1.2x
       3000    1.23s  1.52s    0.8x
       5000    1.88s  2.43s    0.8x
      10000    3.72s  5.36s    0.7x

With many commits the per-commit overhead of scanning both
the new and parent root trees accumulates and incremental
becomes slower.  Breakeven is between 500 and 3000 commits
and the ratio stabilizes near 0.7x for this fixture.

Scaling files per incoming commit (200K files, 10 commits):

    files/commit    full  incr.  full/incr
               1    0.14s  0.01s   14.0x
              10    0.15s  0.01s   15.0x
             100    0.16s  0.04s    4.0x
             500    0.23s  0.14s    1.6x
            1000    0.34s  0.28s    1.2x
            2000    0.70s  0.63s    1.1x

Breakeven is around 1000 files/commit.  At 2000 files/commit
(every directory touched), incremental remains slightly faster;
bypassing the object cache for tree reads likely helps here.

For small repositories both modes are fast enough that the
difference is difficult to measure reliably.

Selected peak RSS measurements from the same fixtures:

    case                        full    incr.  ratio
    200K files, 10 commits      31 MB    12 MB   0.4x
    800K files, 10 commits     110 MB    26 MB   0.2x
    200K files, 5000 commits   155 MB   151 MB   1.0x

Incremental uses substantially less memory when it can prune
most of the boundary tree walk.  In the long-history case the
two modes visit similar object sets and memory converges.

The regression cases in the CPU benchmarks are in wall-clock
time rather than memory, primarily from scanning some trees
more than once.

Signed-off-by: Kristofer Karlsson <krka@spotify.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 11:55:57 -07:00
Kristofer Karlsson 01955ae2e2 connected: add transfer.connectivityCheck config and rev-list flag
Add the transfer.connectivityCheck configuration option, accepting
"full" (default) and "incremental".  When set to "incremental",
check_connected() passes --verify-trees-incremental to its rev-list
subprocess.

The rev-list flag is accepted but has no effect yet; the incremental
verification will be implemented in the next commit.

Signed-off-by: Kristofer Karlsson <krka@spotify.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 11:55:57 -07:00
Kristofer Karlsson b51feb0943 p5413: add perf tests for connectivity check
Add benchmarks for the rev-list connectivity check.  Each fixture
varies one dimension: total tree size, incoming commit count, or
files changed per commit.

Signed-off-by: Kristofer Karlsson <krka@spotify.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 11:55:57 -07:00
Kristofer Karlsson 7c2ea6d664 Documentation: describe connectivity checking
Add Documentation/technical/connectivity-check.adoc describing
the connectivity invariant and the full connectivity check.

Signed-off-by: Kristofer Karlsson <krka@spotify.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 11:55:57 -07:00
Junio C Hamano 657abaf64c SQUASH??? 2026-10-12 11:37:46 -07:00
Julia Evans 71b0f996a4 doc: git-pull: link to new merge conflicts guide
Signed-off-by: Julia Evans <julia@jvns.ca>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 10:22:23 -07:00
Julia Evans 0ef2da01fb doc: git-cherry-pick: link to new merge conflicts guide
Remove the discussion of merge conflicts and replace it with a link to
the guide.

Signed-off-by: Julia Evans <julia@jvns.ca>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 10:22:23 -07:00
Julia Evans 98931ee678 doc: git-revert: link to new merge conflicts guide
Signed-off-by: Julia Evans <julia@jvns.ca>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 10:22:23 -07:00
Julia Evans 314007f6bb doc: git-rebase: link to new merge conflicts guide
Remove some of the detail about how to handle a merge conflict, since
it's explained in detail in the new guide, and there probably isn't
enough detail anyway.

Leave the steps since rebase is special and has a `--skip` option which
the other commands which cause merge conflicts don't have.

Signed-off-by: Julia Evans <julia@jvns.ca>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 10:22:23 -07:00
Julia Evans 4a1237aa8a doc: git-merge: link to new merge conflicts guide
All of the info about merge conflicts has been moved to the new guide

Signed-off-by: Julia Evans <julia@jvns.ca>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 10:22:22 -07:00
Julia Evans a957f40694 doc: add new gitmergeconflicts man page
Introduce a new page, `gitmergeconflicts`, that explains the process of
handling a merge conflict in a way that addresses the following issues,
which came from feedback from Git users on the current explanation of
merge conflicts in the `git merge` man page:

- The process for resolving a merge conflict is only explained in the
  `git merge` man page, even though there are several other commands
  which can result in conflicts
- Sometimes we use "ours" and "theirs" to refer to the two sides of
  the merge conflicts and sometimes we use HEAD and MERGE_HEAD. It should
  be consistent. Also the terms "ours" and "theirs" are not explained.
  Similarly, it says "The part before the `=======` is typically your
  side...", but doesn't explain what "typically" means.
- It introduces the merge format using an analogy to RCS, which very few
  Git users have ever used
- In "The only clean-ups you need are to reset the index file to the
  `HEAD` commit to reverse 2. and to clean up working tree changes made
  by 2. and 3.", it's not clear to users what "2" and "3" are supposed
  to mean
- It uses a cultural reference ("Conflict resolution is hard; let's go
  shopping.") which is confusing or unfamiliar to some people. I think it
  would be clearer for users to use a code example instead.
- It doesn't explain the difference between diff3 and zdiff3
- It sometimes uses the term "area" and sometimes uses the term "hunk"

Also document the unified `--abort`, `--continue` workflow in one
place, since it's a really nice example of a place Git has a consistent
interface between similar commands.

Only discuss merge, rebase, cherry-pick, and revert for now even though
there are other ways that merge conflicts can happen because it's
awkward to talk about `am`, `apply`, and `checkout -m`.

Co-Authored-By: Marie Claire LeBlanc Flanagan <hello@marieflanagan.com>
Helped-by: D. Ben Knoble <ben.knoble+github@gmail.com>
Helped-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Julia Evans <julia@jvns.ca>
Signed-off-by: Marie Claire LeBlanc Flanagan <hello@marieflanagan.com>
Signed-off-by: Julia Evans <julia@jvns.ca>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-10-12 10:22:22 -07:00
Junio C Hamano 7a64283cb2 Merge branch 'qs/repack-kept-pack-fix' into seen
The behavior of repack and pack-objects has been updated to avoid
losing objects to a '.keep' file that appears mid-run.  Instead of
pack-objects looking for '.keep' files independently, repack now
hands it a snapshot of kept packs via a new --keep-pack-from-file
option.

* qs/repack-kept-pack-fix:
  repack: tell pack-objects which packs are kept
  pack-objects: add --keep-pack-from-file
  pack-objects: sort --keep-pack list for lookup
  pack-objects: reset kept-pack cache for cruft walk
  pack-objects: keep --keep-pack open when following
2026-10-12 09:26:16 -07:00
Junio C Hamano f3125b5d67 Merge branch 'ps/ci-housekeeping-and-modernizations' into seen
Various CI jobs have been updated to use modern OS images, drop
dead code, and remove redundant jobs.  Support for Python 2 in CI
has been removed, and the linux-TEST-vars job has been renamed to
linux-exotic.

* ps/ci-housekeeping-and-modernizations:
  ci: improve reftable test coverage
  ci: drop now-dead Python 2 coverage
  ci: switch away from EOL'd Ubuntu version in linux-exotic
  ci: rename linux-TEST-vars job
  ci: switch away from unsupported i386/ubuntu image
  ci: drop unused "linux-clang" logic
  ci: fix "fedora-breaking-changes-meson" job
  t5004: skip SHA-1-only test in SHA-256 repository
2026-10-12 09:26:16 -07:00
Junio C Hamano 30b71f39c6 Merge branch 'tb/repack-cruft-less-midx-corner-cases' into seen
Various corner cases in the cruft-less MIDX feature have been fixed
to ensure reachability closure when writing reachability bitmaps,
such as properly retaining cruft packs after incremental repacks or
when containing kept packs.

* tb/repack-cruft-less-midx-corner-cases:
  repack: include required packs in incremental MIDX writes
  repack: defer allocating the append plan's write step
  repack: track the preferred pack explicitly in MIDX write steps
  repack: follow kept packs when omitting cruft from the MIDX
  repack: use a sorted list for explicitly kept packs
  repack: retain cruft packs in MIDXs after incremental repacks
  pack-objects: ensure tree/tag closure with '--stdin-packs=follow'
  pack-objects: introduce `stdin_packs_context` struct
2026-10-12 09:26:15 -07:00
Junio C Hamano 4e6f0c048d Merge branch 'je/doc-promote-git-help' into seen
The earliest part of 'man git' has been rewritten to explain various
ways to use 'git help' to get help.

* je/doc-promote-git-help:
  doc: use `man git` to teach users how to navigate the docs
2026-10-12 09:26:15 -07:00
Junio C Hamano a7083008cd Merge branch 'hn/status-push-rebased-on-newer-upstream' into seen
The 'git status' output and 'git push' rejection advice have been
improved to recognize when a pushed branch was cleanly rebased onto
a newer upstream, and now correctly suggest force-pushing instead of
pulling.

* hn/status-push-rebased-on-newer-upstream:
  push: suggest a force push after a clean rebase
  push: offer a force push after rewriting pushed commits
  push: name the branch to pull from when it is not the upstream
  status: suggest a force push after a clean rebase
  status: say when the push branch was rebased cleanly
  status: count push divergence outside the upstream
2026-10-12 09:26:15 -07:00
Junio C Hamano e59c422bfb Merge branch 'ik/fsmonitor-untracked-cache-trivial-response' into seen
The index writer has been taught to check the untracked cache
against the filesystem when an FSMonitor trivial response is
received, preventing commands like 'git add' from saving a new token
while leaving stale untracked cache entries intact.

* ik/fsmonitor-untracked-cache-trivial-response:
  fsmonitor: check the untracked cache after a trivial response
2026-10-12 09:26:14 -07:00
Junio C Hamano f09e2f0cc4 Merge branch 'ss/history-sign-rewrites' into seen
The git history command and its subcommands have been updated to
honor the commit.gpgSign configuration variable and accept the
--gpg-sign and --no-gpg-sign command-line options, ensuring both
rewritten commits and their replayed descendants are
cryptographically signed by the committer.

* ss/history-sign-rewrites:
  history: sign rewritten commits
  replay: allow callers to sign commits
2026-10-12 09:26:14 -07:00
Junio C Hamano a0c87fc8b3 Merge branch 'hn/ci-leak-sanitizer-annotations' into seen
CI on GitHub Actions gets a better annotation experience.  Leak test
scripts are stopped at their first failure with --immediate to
prevent flooding the log, and failures are correctly annotated with
their file and line number.

* hn/ci-leak-sanitizer-annotations:
  ci: point test failures and fixed known breakages at their file and line
  ci: annotate leaks and stop a leak-sanitizer script at its first failure
2026-10-12 09:26:14 -07:00
Junio C Hamano 6ee386419b Merge branch 'am/p4-apply-commit-shell-injection-fix' into seen
The `applyCommit()` function inside 'git-p4.py' has been updated to
use direct subprocess pipes in order to avoid shell interpolation,
plugging a potential shell injection vulnerability when processing
commit IDs.

* am/p4-apply-commit-shell-injection-fix:
  git-p4: avoid shell interpretation of commit ids in applyCommit
2026-10-12 09:26:13 -07:00
Junio C Hamano 51e5f306b1 Merge branch 'td/ls-files-untracked-cache' into seen
The git ls-files command has been optimized to reuse and populate
the untracked cache for the working tree, and untracked cache
implementations have been updated to share identical caches across
-unormal and -uall outputs, avoiding redundant filesystem
traversals.

* td/ls-files-untracked-cache:
  ls-files: use and update the untracked cache
  dir: share untracked caches across output modes
  dir: hash ignore files before appending newline
2026-10-12 09:26:13 -07:00
Junio C Hamano bf970699c6 Merge branch 'hn/shallow-history-advice' into seen
Providing advice when ~<n> or ^<n> resolves to a commit whose
parents are missing due to the repository being a shallow clone,
instead of an unhelpful 'not a commit' error.

* hn/shallow-history-advice:
  object-name: explain why <rev>~N fails in a shallow clone
2026-10-12 09:26:13 -07:00
Junio C Hamano d644296348 Merge branch 'mc/refs-hook-report-old-values' into seen
The 'reference-transaction' hook has been updated to report the
observed old object IDs and symref targets for unconditional ref
updates and deletions, instead of reporting the null object ID.

* mc/refs-hook-report-old-values:
  refs: report old values to transaction hooks
2026-10-12 09:26:13 -07:00