The performance of ref updates and reads using the 'reftable' backend
in the presence of many deletion tombstone records has been optimized
by removing the tombstone suppression flag from the merged iterator
and instead skipping tombstones at higher-level call sites where
iteration bounds are known.
* kk/reftable-tombstone-quadratic-fix:
reftable: fix quadratic behavior in the presence of tombstones
t/perf: add perf test for ref tombstone scenarios
The 'topo_levels' slab was propagated only to the topmost layer of a
split commit-graph chain, causing topological levels for commits in
base layers to be recomputed during incremental writes. This has been
corrected.
* kk/commit-graph-topo-levels-fix:
commit-graph: propagate topo_levels slab to all chain layers
commit-graph: add trace2 instrumentation for generation DFS
The global configuration variable 'ignore_case' (representing the
'core.ignorecase' configuration) has been migrated into 'struct
repo_config_values' to tie it to a specific repository instance.
* ty/migrate-ignorecase:
config: use repo_ignore_case() to access core.ignorecase
environment: move ignore_case into repo_config_values
The client-side parser of the server-advertised bundle-URI list has
been updated to drain the remaining response in order to avoid
protocol desynchronization when the server sends a misconfigured list.
Also, the server-side has been taught to omit empty configuration
values instead of sending invalid key-value lines.
* tc/bundle-uri-empty-fix:
bundle-uri: stop sending invalid bundle configuration
bundle-uri: drain remaining response on invalid bundle-uri lines
The cache-scanning loop in 'next_cache_entry()' has been optimized
to avoid rescanning already-unpacked index entries, preventing a
quadratic performance slow-down when diffing the working tree
against a commit with a pathspec matching early index entries.
* hf/unpack-trees-quadratic-scan:
unpack-trees: avoid quadratic index scan in next_cache_entry()
The contributor guide has been updated to advise new contributors to
trim irrelevant quoted text when replying to review comments, matching
the existing advice given to reviewers.
* wy/doc-myfirstcontribution-trim-quotes:
MyFirstContribution: mention trimming quoted text in replies
The pipelines in 't1410-reflog.sh' have been replaced with the
'test_stdout_line_count' helper to avoid suppressing the exit code of
'git' commands, ensuring failures are not hidden from the test suite.
* gr/t1410-reflog-exit-code:
t1410-reflog.sh: avoid suppressing git's exit code in pipelines
The test suite has been updated to use the 'test_grep' helper instead
of bare 'grep' for test assertions, allowing file contents to be
printed on failure for easier debugging. A new 'greplint' linter has
been introduced to detect and prevent new bare 'grep' assertions from
being added to the test suite.
* mm/test-grep-lint:
t: add greplint to detect bare grep assertions
t: convert grep assertions to test_grep
t: fix Lexer line count for $() inside double-quoted strings
t: extract chainlint's parser into shared module
t: fix grep assertions missing file arguments
t/README: document test_grep helper
The build system has been updated to support building universal macOS
binaries when 'Rust' is enabled, by compiling separate static archives
for each target triple listed in 'RUST_TARGETS' and combining them
using the macOS 'lipo' tool. The 'git-credential-osxkeychain' helper
has been updated to link against '$(RUST_LIB)' when 'Rust' is enabled.
* sn/osxkeychain-rust-universal:
contrib: wire up osxkeychain in contrib/Makefile on macOS
Makefile: support universal macOS builds via RUST_TARGETS
Makefile: add $(RUST_LIB) prerequisite to osxkeychain
Option parsing with 'git rev-parse --parseopt' and in most 'git'
subcommands has been updated to exit with 0 (instead of 129) when the
help option ('-h' or '--help') is requested directly by the user,
aligning with standard Unix convention.
* bc/parse-options-exit-0-on-help:
parse-options: exit 0 on -h
rev-parse: have --parseopt callers exit 0 on --help
parse-options: add a separate case for help output on error
t1517: skip svn tests if svn is not installed
The 'SubmittingPatches' document has been updated to explicitly
describe the expectation for contributors to retract or abandon their
patch series when they are no longer pursuing it.
* jc/submitting-patches-abandoning:
SubmittingPatches: document how to retract a topic
The early-exit optimization in 'paint_down_to_common()' has been
gated on the queue being generation-ordered, fixing a bug where
'git merge-base' (without '--all') could return incorrect results
on repositories with v1 commit graphs and clock skew.
* kk/commit-reach-find-all-fix:
commit-reach: guard !FIND_ALL early exit with generation ordering check
t6600: add test for merge-base early exit with clock skew
A description in the release notes for Git 2.55.0 has been
retroactively updated to clarify that Rust support is enabled by
default, but still optional, and will become mandatory in Git 3.0.
* jc/relnotes-2.55-rust-fix:
Rust: fix description in Release Notes to 2.55
The repository discovery and repository configuration phases, which
were previously intertwined in 'setup.c', have been split. Repository
discovery has been updated to populate a 'struct repo_discovery'
without modifying the repository state, which is then taken by
repository configuration to initialize the repository, paving the way
for clean unification of repository configuration.
* ps/setup-split-discovery-and-setup:
setup: mark `set_git_work_tree()` as file-local
setup: pass worktree to `init_db()`
setup: drop redundant configuration of `startup_info->have_repository`
setup: make repository discovery self-contained
setup: propagate prefix via repository discovery
setup: drop static `cwd` variable
setup: move prefix into repository
setup: embed repository format in discovery
setup: introduce explicit repository discovery
setup: split up concerns of `setup_git_env_internal()`
setup: unify setup of shallow file
setup: mark bogus worktree in `apply_repository_format()`
setup: rename `check_repository_format_gently()`
The 'reftable' code has been hardened against corrupted tables by
fixing out-of-bounds writes, out-of-bounds reads, and abort calls
during parsing.
* ps/reftable-hardening:
reftable/table: fix OOB read on truncated table
reftable/table: fix NULL pointer access when seeking to bogus offsets
reftable/block: fix OOB read with bogus restart offset
reftable/block: fix use of uninitialized memory when binsearch fails
reftable/block: fix OOB read with bogus restart count
reftable/block: fix OOB read with bogus block size
reftable/block: fix OOB write with bogus inflated log size
t/unit-tests: introduce test helper to write reftable blocks
reftable/record: don't abort when decoding invalid ref value type
reftable/basics: fix OOB read on binary search of empty range
oss-fuzz: add fuzzer for parsing reftables
meson: support building fuzzers with libFuzzer
The sideband demultiplexer has been updated to recognize ANSI SGR
escape sequences that use colon-separated subfields (e.g., for
256-color or true-color codes).
* mm/sideband-ansi-sgr-colon-fix:
sideband: allow ANSI SGR with colon-separated subfields
The 'git_hash_*()' wrappers have been updated to be used consistently
across the codebase instead of direct calls to members of 'struct
git_hash_algo', and 'git_hash_discard()' has been made idempotent to
simplify cleanups.
* jk/git-hash-cleanups:
hash: check ctx->active flag in all wrapper functions
http: use idempotent git_hash_discard()
csum-file: use idempotent git_hash_discard()
hash: make git_hash_discard() idempotent
hash: document function pointers and wrappers
hash: convert remaining direct function calls
hash: use git_hash_init() consistently
The UTF-8 precomposition wrapper on macOS has been updated to use a
flexible array member to represent the name of a directory entry,
preventing fortified libc checks from failing when the name is
reallocated to be larger than 'NAME_MAX' bytes.
* ih/precompose-flex-array:
precompose_utf8: use a flex array for d_name
Various test scripts have been updated to clean up large temporary
files and repositories, reducing peak disk usage during testing.
Also, expensive tests have been disabled on platforms that lack
sufficient resources (like 32-bit platforms and Windows CI runners),
and the long test suite has been enabled in GitLab CI.
* ps/t-fixes-for-git-test-long:
gitlab-ci: enable "GIT_TEST_LONG"
gitlab-ci: disable RAM disk on macOS jobs
t: use `test_bool_env` to parse GIT_TEST_LONG
t7900: clean up large EXPENSIVE repository
t7508: skip EXPENSIVE test that is broken without SIZE_T_IS_64BIT
t5608: reduce maximum disk usage
t4141: fix inefficient use of dd(1)
t0021: skip EXPENSIVE test that is broken without SIZE_T_IS_64BIT
README: add GitLab CI badge to make it more discoverable
Dockerized CI jobs running in private GitHub repositories have been
adjusted to use explicit process and file limits, preventing resource
exhaustion errors on private runners.
* js/ci-dockerized-pid-limit:
ci(dockerized): raise the PID limit for private repositories
Various resource leaks, invalid file descriptor closures, and process
handle ownership issues flagged by Coverity have been fixed.
* js/coverity-fixes:
mingw: make `exit_process()` own the process handle on all paths
fsmonitor: plug token-data leak on early daemon-startup failures
reftable/table: release filter on error path
imap-send: avoid leaking the IMAP upload buffer
worktree: fix resource leaks when branch creation fails
submodule: fix cwd leak in `get_superproject_working_tree()`
dir: free allocations on parse-error paths in `read_one_dir()`
line-log: avoid redundant copy that leaks in process_ranges
run-command: avoid `close(-1)` in `start_command()` error paths
download_https_uri_to_file(): do not leak fd upon failure
loose: avoid closing invalid fd on error path
load_one_loose_object_map(): fix resource leak
Various code paths that initialize a cryptographic hash context but
bail out or finish without calling 'git_hash_final()' have been taught
to call 'git_hash_discard()' to release allocated resources, fixing
memory leaks when Git is built with non-default backends like
'OpenSSL' or 'libgcrypt'.
* jk/hash-algo-leak-fixes:
hash: add platform-specific discard functions
hash: fix memory leak copying sha256 gcrypt handles
http: discard hash in dumb-http http_object_request
check_stream_oid(): discard hash on read error
patch-id: discard hash when done
csum-file: provide a function to release checkpoints
csum-file: always finalize or discard hash
hash: add discard primitive
csum-file: drop discard_hashfile()
The wincred credential helper has been updated to avoid memory
corruption when erasing credentials and to prevent silent
credential loss when storing OAuth tokens, by correcting buffer
allocations and arguments passed to safe-CRT APIs.
* js/wincred-fixes:
wincred: prevent silent credential loss when storing OAuth tokens
wincred: avoid memory corruption when erasing a credential
When `git credential approve` hands the wincred helper a password
together with an `oauth_refresh_token`, the OAuth branch of
`store_credential()` writes one WCHAR past the allocation while
formatting both fields into a single `CredentialBlob`. On Windows
this trips heap verification and tears the helper down with status
`0xC0000374`; `approve` masks the failure, so the credential the
user meant to save never reaches `CredWriteW()` and the next
session prompts for it again.
The bug has the same shape as the one fixed in the previous commit:
the allocation leaves no room for the terminating NUL, and the
`sizeOfBuffer` argument to `_snwprintf_s()` is a byte count where
the API expects a WCHAR count, which lets the safe-CRT runtime
write the terminator out of bounds.
Apply the same remedy d22a488482 (wincred: avoid memory corruption,
2025-11-17) applied in `get_credential()`: allocate `(wlen + 1) *
sizeof(WCHAR)` bytes and pass `wlen + 1` as the destination
capacity in WCHARs.
This closes the second of the two heap writes tracked under
GHSA-rxqw-wxqg-g7hw.
Assisted-by: Opus 4.7
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
The earlier d22a488482 (wincred: avoid memory corruption, 2025-11-17)
repaired only get_credential(); match_cred_password() has the same
defect and is reached on `git credential reject`. When Git asks the
helper to erase a stored credential whose password was supplied by
the caller, the helper copies the candidate's password into a freshly
allocated buffer for comparison. That copy overruns the allocation
by one WCHAR of NUL, which on uninstrumented Windows manifests as
process termination with status 0xC0000374. Because the helper can
die before reaching CredDeleteW(), `git credential reject` masks the
failure and the rejected credential remains stored.
CredentialBlobSize is documented as a byte count, so for an N-WCHAR
blob it equals N * sizeof(WCHAR). The pre-fix code allocated that
many bytes and asked wcsncpy_s to copy N wide characters, but
wcsncpy_s always appends a terminating NUL WCHAR, writing one WCHAR
past the allocation. The destination-capacity argument was also
passed in bytes rather than in WCHAR elements as the API requires,
so the safe-CRT runtime never rejected the copy.
See GHSA-rxqw-wxqg-g7hw.
Assisted-by: Opus 4.7
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
* 'master' of https://github.com/j6t/git-gui:
git-gui: allow larger width for the commit message field
git-gui: reduce complexity of the quiet msgfmt rule
git-gui: drop msgfmt --statistics output
git-gui i18n: Update Bulgarian translation (562t)
The alignment of commit object name abbreviations in 'git blame'
output has been optimized to reserve a column for marks (caret,
question mark, or asterisk) only when such marks are actually shown.
* rs/blame-abbrev-marks:
blame: reserve mark column only if necessary
A racy build failure under Meson has been corrected by ensuring that
the generated header file 'hook-list.h' is built before compiling
files in 'builtin_sources' that depend on it.
* mg/meson-hook-list-buildfix:
meson: restore hook-list.h to builtin_sources
Various memory leaks in the Bloom-filter code paths that are exposed
when running tests with the 'GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS=1'
environment variable have been plugged.
* jk/bloom-leak-fixes:
line-log: drop extra copy of range with bloom filters
revision: avoid leaking bloom keyvecs with multiple traversals
bloom: make bloom-filter slab initialization idempotent
The experimental 'git history' command has been taught a new 'drop'
subcommand to remove a commit, with its descendants replayed onto its
parent.
* ps/history-drop:
builtin/history: implement "drop" subcommand
builtin/history: split handling of ref updates into two phases
replay: expose `replay_result_queue_update()`
reset: stop assuming that the caller passes in a clean index
reset: allow the caller to specify the current HEAD object
reset: introduce ability to skip updating HEAD
reset: introduce dry-run mode
reset: modernize flags passed to `reset_working_tree()`
reset: rename `reset_head()`
reset: drop `USE_THE_REPOSITORY_VARIABLE`
read-cache: split out function to drop unmerged entries to stage 0
The 'whence' field in 'struct object_info' has been removed. The
backend-specific object information retrieval has been refactored into
an opt-in 'struct object_info_source' structure.
* ps/odb-drop-whence:
odb: document object info fields
odb: drop `whence` field from object info
treewide: convert users of `whence` to the new source field
odb: add `source` field to struct object_info_source
odb: make backend-specific fields optional
packfile: thread odb_source_packed through packed_object_info()
The 'git refs' toolbox has been extended with new 'create', 'delete',
'update', and 'rename' subcommands to create, delete, update, and
rename references, respectively.
* ps/refs-writing-subcommands:
builtin/refs: add "rename" subcommand
builtin/refs: add "create" subcommand
builtin/refs: add "update" subcommand
builtin/refs: add "delete" subcommand
builtin/refs: drop `the_repository`
A write file stream resource leak has been fixed as part of a code
cleanup.
* jc/history-message-prep-fix:
history: streamline message preparation and plug file stream leak
The 'reprepare()' callback for object database sources has been
generalized into a 'prepare()' callback with an optional flush cache
flag, and a new 'odb_prepare()' wrapper has been introduced to allow
pre-opening object database sources.
* ps/odb-generalize-prepare:
odb: introduce `odb_prepare()`
odb/source: generalize `reprepare()` callback
The lazy priority queue optimization pattern (deferring actual removal
in 'prio_queue_get()' to allow get+put fusion) has been folded
directly into 'prio_queue' itself, speeding up commit traversal
workflows and simplifying callers.
* kk/prio-queue-get-put-fusion:
prio-queue: fold lazy_queue into prio_queue for automatic get+put fusion
prio-queue: rename .nr to .nr_ and add accessor helpers
When 'git push origin/main' or 'git branch origin main' is run, the
command is now recognized as a potential typo, and advice has been
added to offer a typo fix.
* hn/branch-push-slip-advice:
push: suggest <remote> <branch> for a slash slip
branch: suggest <remote>/<branch> on upstream slip
A memory leak in the '--base' handling of 'git format-patch' has been
plugged, and the leak reporting of the test suite when running under a
TAP harness has been improved.
* jk/format-patch-leakfix:
format-patch: fix leak of rev_info in prepare_bases()
t: move LSan errors from stdout to stderr
A memory leak in the 'reftable_writer_new()' initialization function
has been fixed by delaying the allocation of 'struct reftable_writer'
until after input options are validated.
* jk/reftable-leakfix:
reftable: fix unlikely leak on API error
The GPG and SSH signature parsing code has been corrected to strip
carriage return characters only when they immediately precede line
feeds, instead of unconditionally stripping all carriage returns.
* ad/gpg-strip-cr-before-lf:
gpg-interface: fix strip_cr_before_lf to only remove CR before LF
When many tombstones are present in a reftable, operations that need
to look up or iterate over refs exhibit quadratic behavior. With
8000 refs deleted and re-created, update-ref takes ~15s, quadrupling
for each doubling of input size.
The root cause is the merged iterator's suppress_deletions flag.
When set, merged_iter_next_void() silently consumes tombstone records
in a tight internal loop before returning to the caller. This
prevents higher-level code from checking iteration bounds (such as
prefix or refname comparisons) until after all tombstones have been
scanned.
This affects any code path that seeks into a range containing
tombstones, including:
- refs_verify_refnames_available() seeks to "refs/tags/foo-1/" to
check for D/F conflicts and must scan through all subsequent
tombstones before the caller can see that they are past the prefix
of interest.
- reftable_backend_read_ref() seeks to a specific refname and must
scan through all subsequent tombstones before returning "not
found", because the merged iterator skips the matching tombstone
and searches for the next live record.
Fix this by making suppress_deletions configurable via
reftable_stack_options instead of unconditionally enabling it. Git
no longer sets the flag, so tombstones are now returned to callers in
the reftable backend, which skip them after their existing bounds
checks. This allows iteration to terminate as soon as a tombstone
past the relevant bound is encountered.
Downstream users of the reftable library (e.g. libgit2) can still
enable suppress_deletions through the stack options to retain the
previous behavior.
This also requires adding deletion checks to the log iteration paths,
since suppress_deletions applied to both ref and log iterators.
Both tests in p1401 go from ~13s to ~0.2s with this change.
Reported-by: Jeff King <peff@peff.net>
Signed-off-by: Kristofer Karlsson <krka@spotify.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Add performance tests for update-ref when many tombstones are present
in a reftable.
The first test exercises the scenario where all refs are deleted
(creating tombstones) and then re-created with the same names, which
currently exhibits quadratic behavior.
The second test uses a separate repository with an asymmetric variant
where refs are deleted and then new, differently-named refs are
created. When the tombstones sort after the new refs, every create
scans all tombstones, making this case even worse than re-creating
the same refs.
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Kristofer Karlsson <krka@spotify.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
The topo_levels slab is only propagated to the topmost graph
layer instead of all layers in the chain. Commits from lower
layers appear to have no generation numbers, so the DFS
re-walks the entire ancestry.
Fix by making topo_levels visible to all layers, not just
the first one.
Signed-off-by: Kristofer Karlsson <krka@spotify.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Count the number of steps taken in
compute_reachable_generation_numbers() and expose it via
trace2 to make it easier to detect performance regressions.
Add a failing test for such a regression, introduced in
199d452758 (commit-graph: return the prepared commit graph
from `prepare_commit_graph()`, 2025-09-04), where incremental
commit-graph writes do not see existing generation numbers
from lower graph layers and fall back to walking the full
ancestry.
Signed-off-by: Kristofer Karlsson <krka@spotify.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>