The hint printed when tracking configuration fails to be written has
been corrected to produce a valid remote-tracking branch name.
* ti/branch-set-upstream-hint-fix:
branch: strip refs/heads/ from the --set-upstream-to hint
The messages 'git checkout' prints to describe orphaned commits and
multiple references have been updated to use the Q_() macro, allowing
translators to use the correct plural forms for numbers greater than
one.
* tj/checkout-orphan-more-plural:
checkout: use Q_() for messages with counts
The verbose "Checking connectivity" message in 'git fsck' has been
updated to use the pluralizing translation macro.
* ag/fsck-connectivity-msg-i18n:
fsck: use Q_() for the verbose connectivity message
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 "auto" connectivity check mode
connected: add incremental connectivity check via rev-list
connected: add transfer.connectivityCheck config
connected: drop dependency on `the_repository`
p5413: add perf tests for connectivity check
Documentation: describe connectivity checking
The creation of '.keep' lockfiles during object database
transactions has been deferred to commit time, explicitly managing
the lockfiles within the files backend rather than relying on
'git-index-pack', to prevent race conditions that could lead to
concurrent lockfiles being erroneously deleted.
* jt/odb-keep-lockfile-fix:
object-file: write ".keep" lockfiles during transaction commit
object-file: explicitly write ".keep" lockfile
pack-write: lift and expose index-pack report parsing
pack-write: make index-pack output comment hash agnostic
A test script ('t2104') has been updated to avoid piping the output of
a 'git' command into another command, which would hide its exit code.
* cu/t2104-avoid-pipes:
t2104: avoid suppressing git's exit code
The Makefile has been updated to explicitly pass '--target-dir
target' to 'cargo' when building the 'gitcore' library, fixing a
link error that occurs when the user has a custom target directory
configured via 'CARGO_TARGET_DIR' or their Cargo configuration.
* ak/cargo-pin-target-dir:
Makefile: pin cargo --target-dir to ./target
The test in 't5301' has been modernized to use the
'test_path_is_file' helper instead of the raw 'test -f' command.
* rk/t5301-use-test-path-helpers:
t5301: use test_path_is_file instead of test -f
The loose refs cache in the files backend has been updated to avoid
caching root refs (like 'HEAD'), preventing them from being omitted
from subsequent iterators that explicitly request them when a
previous iterator populated the cache without them.
* ak/refs-files-root-refs-cache:
refs/files: keep root refs out of loose ref cache
The macOS CI jobs have been updated to use a mixture of 'macos-15' and
'macos-latest' images, as the 'macos-14' hosted runner image is being
deprecated by GitHub.
* jc/ci-update-macos-15:
github-ci: update macos jobs from macos-14
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:
archive-zip: omit UT extra field if mtime is out of range
The internal config file parser has been updated to treat the
content read from a blob as a sequence of unsigned bytes, preventing
bytes with the high bit set from being mistakenly interpreted as
'EOF'.
* of/config-buf-fgetc-unsigned:
config: read the bytes of a blob as unsigned characters
The 'git bundle create' command has been updated to initialize the
revs_copy structure at declaration. This prevents a potential crash
caused by reading uninitialized stack memory during cleanup when an
unrecognized argument is provided.
* of/bundle-uninitialized-memory-fix:
bundle: do not free uninitialized memory on bad arguments
The internal write_index_as_tree() function has been updated to
take the index lock gently. This allows it to skip the optional
cache-tree write-back when the lock is held by another process,
preventing commands like 'git rebase' from dying due to background
tasks holding the lock.
* sw/cache-tree-ignore-locked-index:
cache-tree: do not die when the index is locked
The '--dry-run' option of 'git repack --drop-filtered' used to
actually rebuild packs and delete redundant ones, which has been
corrected to only list the candidates without making changes.
* ss/repack-drop-filtered-dry-run:
repack: do not rebuild packs on --dry-run
Instead of failing to record conflicts to be resolved immediately,
wait while "rerere gc" is ongoing.
* tb/rerere-wait-for-merge-rr-lock:
rerere: add "gc --skip-locked" for auto maintenance
rerere: wait for MERGE_RR.lock before giving up
The lazy prerequisite set-up script can be fed as a here-doc, just
like test_expect_{success,failure} scripts these days.
* jk/test-lazy-prereq-heredoc:
test-lib: allow lazy prerequisite snippets as here-docs
The object database "files" backend has been optimized to check
packfiles across all alternate object directories before falling
back to checking loose objects, significantly reducing the number of
'stat(3p)' system calls. Additional refactoring drops the generic
'local' flag from the object database source interface in favor of
backend-specific fields, and simplifies the retry loop for missing
objects.
* ps/odb-files-alternates-cleanups:
odb/source: drop `local` flag
odb: don't try re-fetching corrupt objects
odb: remove read loop for found objects
odb/source-files: make the second read an implementation detail
odb/source-files: fix performance when streaming objects with alternates
odb/source-files: fix performance when reading objects with alternates
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
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
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-feature-testbed.
* 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-feature-testbed
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: fix test creating an archive with large objects under SHA256
The branch decoration logic in the sequencer has been updated to use
an allocated buffer for the HEAD reference name, preventing it from
being clobbered when evaluating branches checked out in other
worktrees.
* ak/sequencer-head-refdup:
sequencer: don't clobber HEAD ref name in worktree lookup
The 'from' command in 'git fast-import' has been updated to
correctly resolve references to newly created commits and tags by
checking the internal object table, preventing a crash when the
objects are not yet available in the object database.
* mb/fast-import-reference-pending:
fast-import: allow 'from' to reference new commits and tags by oid
A boundary check in 'git fsck' against the big file threshold has
been corrected to prevent bogus corruption reports on packed objects
whose sizes exactly match the threshold.
* ps/pack-check-bigfile-threshold:
pack-check: fix bogus corruption report with core.bigFileThreshold
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()`
'git blame' and 'git annotate' have been updated to automatically
use the '.git-blame-ignore-revs' file from the working tree (or
'HEAD:.git-blame-ignore-revs' in bare repositories) as the default
ignore list if it exists, and the parser has been hardened.
* rm/blame-default-ignore-revs:
blame: ignore revs in .git-blame-ignore-revs by default
blame: harden ignore-revs parser and tag peeling
The incremental connectivity check pays a per-commit cost. For
every incoming commit it reads the new trees along the changed
paths, and the trees at the same paths in its parents to compare
against. A parent tree is often read again even though an earlier
commit already read it: on git.git, about a third of the tree reads
for 2000 incoming commits are such re-reads. The full check
instead pays a mostly fixed cost for walking the boundary trees,
so with many incoming commits the incremental check becomes the
slower one (see the previous commit). Users who mostly
receive small pushes but occasionally a large one should not have
to choose between the two.
Add an "auto" value for transfer.connectivityCheck that picks the
mode based on the incoming history. When the revision walk is
limited, which is the case whenever the receiving repository has
references, the incoming commit list is already computed by
limit_list(), so counting it is cheap. "auto" then uses the
incremental check for up to 1000 incoming commits, and the full
check above that.
The cutoff is a fixed constant based on the p5413 fixture in the
previous commit, where breakeven is between 500 and 3000 commits.
It is conservative for repositories with large trees, where the
fixed cost of the full check is higher. Measured on real
repositories (rev-list against a single boundary commit, mean
of at least 10 runs):
repository files commits full incr. full/incr
internal A 556K 1000 1.71s 0.61s 2.8x
internal A 556K 4000 2.78s 2.83s 1.0x
internal B 288K 1000 1.78s 0.88s 2.0x
linux 95K 598 0.33s 0.12s 2.7x
linux 95K 1728 0.56s 0.35s 1.6x
git 4.9K 984 0.22s 0.27s 0.8x
With small trees incremental can be slower within the cutoff,
but both modes are fast enough there (0.22s vs 0.27s for git
above) that the difference does not matter in practice.
No single cutoff is optimal for every repository, so it can be set
with "auto=<cutoff>"; plain "auto" uses 1000. A malformed cutoff
is treated like any other unknown value: it falls back to "full"
with a warning.
Suggested-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Kristofer Karlsson <krka@spotify.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
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 inside rev-list, selected by the
internal --connectivity-check option. 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.
A new transfer.connectivityCheck value "incremental" selects the
new mode, 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.
Clones and pushes into an empty repository also use the full
check. Without negative revisions there is no trusted boundary,
and the incremental check would have to verify all of history
from scratch like the full check does, with extra per-commit
overhead on top. On git.git, checking 70K commits without a
boundary takes 5.3s with the full check and 9.2s with the
incremental one.
p5413 results (best 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.13s 0.01s 13.0x
800K 0.54s 0.03s 18.0x
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.13s 0.01s 13.0x
10 0.13s 0.01s 13.0x
100 0.16s 0.06s 2.7x
500 0.29s 0.25s 1.2x
3000 1.14s 1.44s 0.8x
5000 1.87s 2.39s 0.8x
10000 3.45s 5.13s 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.13s 0.01s 13.0x
10 0.13s 0.01s 13.0x
100 0.15s 0.03s 5.0x
500 0.23s 0.13s 1.8x
1000 0.34s 0.27s 1.3x
2000 0.65s 0.56s 1.2x
The advantage shrinks as more files change per commit, but
incremental stays slightly faster even at 2000 files/commit,
where every directory is touched.
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 less memory when it can prune enough 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: a commit's tree is read as a candidate when the
commit is verified, and again as a trusted parent tree when its
children are verified.
Signed-off-by: Kristofer Karlsson <krka@spotify.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Add the transfer.connectivityCheck configuration option to choose
the algorithm used for the connectivity check. For now the only
accepted value is "full", which is the existing behavior and the
default. Unknown values fall back to "full" with a warning, so
that configuration written for a newer version of Git does not
break fetches and pushes; "full" is always a correct check.
check_connected() now always tells its rev-list subprocess which
algorithm to use with an internal --connectivity-check=<mode>
option, which so far only accepts "full". Passing the mode
explicitly means rev-list knows it is running a connectivity
check, so later optimizations can be limited to that case.
This prepares for an incremental check added in the next commit.
Suggested-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Kristofer Karlsson <krka@spotify.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
The next commits will need to use the repository to read configuration
in check_connected(). Rather than accessing `the_repository`, refactor
the code to instead require the caller to pass in a repository so that
we can remove `USE_THE_REPOSITORY_VARIABLE`.
Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Kristofer Karlsson <krka@spotify.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
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>
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>
The progress message emitted by the 'delta-islands' subsystem has
been updated to use the Q_() macro, allowing translators to properly
handle plural forms based on the number of islands marked.
* oa/delta-islands-i18n-use-q:
delta-islands: use Q_() for island count
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
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
When recreating a merge conflict using 'git checkout -m', the
original conflict labels (such as branch names) were lost and
replaced with generic ones. The merge machinery has been updated to
record the original labels in '.git/MERGE_LABELS', allowing 'git
checkout -m' to restore them.
* pw/checkout-m-conflict-labels:
merge: remember conflict labels
checkout -m <path>: cache merge settings
remove_branch_state: convert boolean argument to flags
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
A new 'uploadpack.lazyFetchTrusted' configuration variable has been
introduced to allow 'upload-pack' to lazily fetch missing objects from
configured promisor remotes when serving trusted repositories.
* cc/lazy-fetch-trusted-bit:
builtin/upload-pack: don't disable lazy fetching on trusted repo
promisor-remote: prevent infinite recursion when lazy fetching
upload-pack: read uploadpack.lazyFetchTrusted
setup: extract path_allowlist_apply()
promisor-remote: factor out lazy_fetch_objects()
Two messages in builtin/checkout.c show a count but are
marked with a plain _(), so translators can only give a
single form for them:
- " ... and %d more." at the end of the list of orphaned
commits left behind when leaving a detached HEAD, and
- "only one reference expected, %d given." when more than
one reference is given before "--".
Use Q_() for both. Translators of a language that phrases
"2 more" and "3 more" the same way now have to translate
these messages twice. At that cost, however, we help
translators of languages that need to phrase "2 more",
"3 more", and "5 more" differently.
Helped-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Tanga Joris <tangajoris@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
When git switch fails to write the tracking config, it prints a hint
with the command to set the upstream by hand. For example, if
.git/config.lock exists:
error: could not lock config file .git/config: File exists
error: unable to write upstream branch configuration
hint:
hint: After fixing the error cause you may try to fix up
hint: the remote tracking information by invoking:
hint: git branch --set-upstream-to=origin/refs/heads/feat
The hint says origin/refs/heads/feat, but the correct name is
origin/feat. Running the command as printed fails, because the full
ref name is not a valid remote-tracking branch name here.
This has been wrong since a3f40ec4b0 (branch: accept multiple upstream
branches for tracking, 2021-12-20).
Strip refs/heads/ from the hint, as the success message in the same
function already does. The git config --add line for multiple upstreams
still needs the full ref name, so it is not changed.
Signed-off-by: tsukasa inoue <inoue.tsukasa.4@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
The "files" ODB backend writes a ".keep" lockfile into the transaction
quarantine directory via `odb_transaction_files_write_pack()`. When the
ODB transaction is committed, the ".keep" lockfile is migrated to the
primary ODB alongside its packfile. Writing the temporary lockfile in
this manner has a couple of downsides:
- Migrating quarantined objects via `tmp_objdir_migrate()` doesn't
immediately stop if a ".keep" lockfile already exists for the same
packfile in the primary ODB and instead allows all the remaining
objects to be migrated. So even though `odb_transaction_commit()`
ultimately returns an error here, the objects are needlessly written
to the primary ODB anyways.
- Even more concerning, the ".keep" tempfile atexit(3) handler tries
to remove any lockfile of the same name regardless of whether it was
created by the same process. If the ".keep" lockfile of the same
name for a concurrent process gets deleted prematurely, its packfile
becomes at risk of being deleted by concurrent housekeeping.
Stop creating/registering the temporary lockfiles when writing the
packfile to the transaction and instead do so when committing the
transaction. This ensures the lockfile is properly acquired prior to
migrating objects and that only the owning process can delete its own
lockfiles.
Reported-by: Qin ShiCheng <qeesung@live.com>
Signed-off-by: Justin Tobler <jltobler@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
The `odb_transaction_write_pack()` interface for the "files" backend
relies on git-index-pack(1) to write the specified packfile into an ODB
transaction as a packfile. To prevent a concurrent housekeeping
operation from deleting the newly written packfile prior to the
references being updated, a ".keep" lockfile is also generated by
git-index-pack(1) via the `--keep` option. Consequently, the ".keep"
lockfile is written into the ODB transaction alongside the packfile and
later migrated together to the primary ODB during transaction commit.
In a subsequent commit, writing the lockfile is deferred until
transaction commit and thus cannot rely on git-index-pack(1) to write
it. In preparation for this, update `odb_transaction_files_write_pack()`
to explicitly generate the same ".keep" lockfile itself.
Signed-off-by: Justin Tobler <jltobler@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Once git-index-pack(1) finishes writing a packfile, it reports the
hexadecimal name of that packfile on stdout prefixed with either "pack"
or "keep" depending on whether a ".keep" file was also created alongside
it. Callers that are required to manage the lifecycle of ".keep" files
parse this report via `index_pack_lockfile()`, which provides the path
to the temporary ".keep" file.
In a subsequent commit, the "files" ODB transaction begins creating the
pack lockfiles during transaction commit instead of eagerly staging them
in the transaction quarantine directory with the packfile. Extract the
generic parsing logic for the git-index-pack(1) output into
`read_index_pack_report()` in preparation for recording the names of
newly written packfiles.
Signed-off-by: Justin Tobler <jltobler@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
The code comment in `index_pack_lockfile()` explains the expected format
of output from git-index-pack(1). As written it explicitly mentions
SHA1, but both the git-index-pack(1) output and the parsing are not
specific to SHA1 and also support SHA256.
Update the comment explanation to be hash agnostic accordingly.
Signed-off-by: Justin Tobler <jltobler@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
The exit code of the upstream command in a pipeline is lost, so a
crash in 'git ls-files' would go unnoticed. Write the output to a
file and compare that instead.
Signed-off-by: Cynthia Uche <herroyalpriestess@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>