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()
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
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
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
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
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
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
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
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>
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>
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
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
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()`
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
'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
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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
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
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
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
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
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
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
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
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
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
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