When writing reflog entries to disk we also record authorship
information for the reflog. Besides the author name and mail address,
it also contains the date and timezone at which the record has been
created.
The timezone information is typically encoded in the "[+-]HHMM" format,
and we often pass it around as parsed integer. For example, the timezone
"-0700" would be passed around as -700. And this is also the value that
we eventually store in the reftable on disk.
But the specification in "Documentation/technical/reftable.adoc" notes
that the timezone is a "2-byte timezone offset in minutes (signed)". So
instead of storing -700 in the above example, we have to first convert
that value into minutes and then store -420. We don't though, so we have
a mismatch between specification and implementation.
Ideally, we'd just adapt the specification to match the implementation.
But that's easier said than done, because the specification is 11 years
old by now and reftables have already been implemented by JGit for a
long time. So if we now changed the specification, those libraries would
have to make a backwards-incompatible change.
Another alternative would be to bump the reftable format version, but
that feels suboptimal, too. Other libraries would all have to adapt, and
it wouldn't really help us to fix the discrepancy between alternative
implementations and our implementation as older versions would still be
misinterpreted.
The only viable option seems to be that we simply treat this as a bug
and fix it. This will of course make us misinterpret older reftables
that already exist on disk:
┌───────┬───────────────┬─────────────────┬────────────┐
│ tz │ HHMM encoding │ correct minutes │ divergence │
├───────┼───────────────┼─────────────────┼────────────┤
│ +1400 │ 1400 │ 840 │ 560 │
├───────┼───────────────┼─────────────────┼────────────┤
│ -1200 │ -1200 │ -720 │ 480 │
├───────┼───────────────┼─────────────────┼────────────┤
│ +0530 │ 530 │ 330 │ 200 │
├───────┼───────────────┼─────────────────┼────────────┤
│ +0000 │ 0 │ 0 │ 0 │
└───────┴───────────────┴─────────────────┴────────────┘
But this divergence ultimately doesn't matter much, as Git only uses the
timezone of reflog entries for display purposes anyway. We don't take
the timezone into account when parsing "HEAD@{1.hour.ago}" syntax, and
`should_expire_reflog_ent()` doesn't use it either to decide whether
reflog entries should be pruned.
In summary, the fallout from this change is quite contained. Adapt the
reftable backend accordingly and simply reinterpret the timezones with
the specified meaning.
Add a test to verify that we properly encode the timezone as offset in
minutes. Adapt the test helper accordingly to no longer zero-pad the
offset with "%04d", as that can be easily misinterpreted as the "HHMM"
encoding.
Reported-by: Josh McKinney <git-bugs@lists.joshka.net>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
The `test-tool dump-reftable` command can be used to dump the on-disk
contents of reftables. The "-t" subcommand specifically can be used to
dump a single table from disk.
When trying to use this subcommand though one will quickly realize that
it is broken, as it always segfaults. The root cause of this segfault is
that we try to detect the hash algorithm via the merged table's hash ID.
But that hash ID is not the same as Git's understanding of a hash ID,
and consequently we fail to look up the correct algorithm. This will
then lead to a segfault later on when we try to dereference a NULL
pointer.
This breakage went undetected until now because this particular
subcommand is not used anywhere in our test suite. So the obvious way to
fix the bug is by just removing the code outright. But in the next
commit we're about to add a user.
Fix the issue by properly converting between the two hash IDs.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
The timezones that we store in commits as part of the identity
information are encoded in "[+-]HHMM", for example "-0700" for UTC-7.
Internally we typically pass around this timezone either as string or as
a parsed integer (-700).
Some sites want to convert between this format and minutes or vice
versa, and that conversion is performed ad-hoc. We're about to introduce
another site though that wants to have access to this logic, and having
it cluttered across our codebase is a bit awkward.
Introduce two new helpers `tz_to_minutes()` and `minutes_to_tz()` that
perform the conversion for us and convert call sites to use them.
Note that we used to perform a dance in `gm_time_t()` where we first
convert `tz` into a positive value, then calculate the minutes, and
finally turn the minutes into a negative value again. This dance is
performed because it is implementation-defined in C89 whether the
division on negative values truncates towards zero or not [1]:
If either operand is negative, whether the result of the / operator is
the largest integer less than the algebraic quotient or the smallest
integer greater than the algebraic quotient is implementation-defined,
as is the sign of the result of the % operator.
So under C89, `-130 / 100` could legitimately result in -1 or -2, and
`-130 % 100` could result in either -30 or 70. For us though, the result
that we want is the first one (-1 and -30), which is called truncation
toward zero.
This part of the C language has changed in C99, where this edge case is
now well-defined to always truncate towards zero [2]:
When integers are divided, the result of the / operator is the
algebraic quotient with any fractional part discarded.90) If the
quotient a/b is representable, the expression (a/b)*b + a%b shall
equal a.
90) This is often called ''truncation toward zero''.
So in theory it's unlikely that we still need this logic. In practice
though it feels safer to just retain it as we don't require a fully
C99-compliant compiler in Git.
[1]: https://port70.net/~nsz/c/c89/c89-draft.html#3.3.5
[2]: https://port70.net/~nsz/c/c99/n1256.html#6.5.5p6
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Add a full Afrikaans translation of Git (6476 messages) and
register the Afrikaans team in po/TEAMS.
Signed-off-by: Stéfan Driaan Turvey <stefanturvey1912@gmail.com>
Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
Add the initial Brazilian Portuguese translation of Git and register
the language team in po/TEAMS.
All 6476 messages are translated against the git.pot for v2.56.0-rc1.
The file header carries a glossary documenting the terminology in use:
Git command and concept names (branch, commit, merge, rebase, checkout,
push, fetch, stash, tag, pack, worktree, ...) are kept in English while
the surrounding prose is translated, and literal configuration values
and command-line options are never translated.
Signed-off-by: Daniel Pereira <danielmaraboo@gmail.com>
Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
Restore translations for the new translatable strings reintroduced by
commit 0f8e75abeb (Revert "Merge branch 'en/no-amend-during-conflicts'",
2026-09-23).
Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
Signed-off-by: Peter Krefting <peter@softwolves.pp.se>
Reviewed-by: Tuomas Ahola <taahol@utu.fi>
Reviewed-by: AI, by way of Jiang Xin <worldhello.net@gmail.com>
The review_one_batch() function cleans up stale po/review-result*.json
files before starting a new review. On zsh, an unmatched glob causes a
"no matches found" error and aborts the command, because NOMATCH is on
by default.
Fix by enabling null_glob locally when running under zsh. This leaves
bash and other POSIX shells unaffected, since $ZSH_VERSION is unset
there.
Only the cleanup step in review_one_batch() is changed; no other
behavior is affected.
Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
Make/l10n compiles every po/*.po file. The AGENTS.md workflow keeps its
intermediate files in po/, so any .po file written there can be picked
up by a normal `make` run and cause build failures. Switch the workflow
to use GETTEXT JSON for pending/input/review work files instead of PO,
and rename the remaining PO scratch file to l10n-done.po.tmp so
Make/l10n ignores it.
This only affects the helper scripts documented in po/AGENTS.md.
Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
grep -c on msgid lines only works for PO text, not GETTEXT JSON. When
workflow intermediates move from PO to JSON, that count breaks. Use
stat -c instead; it also excludes the header, so ENTRY_COUNT - 1 is
unnecessary.
Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
Task 3 claimed a gettext-only fallback, but validation already needs
git-po-helper, and the awk|tac batch path fails on systems without tac.
Require the helper for Tasks 3 and 4, drop the unused msgattrib/PO
paths, and point agents at msg-select (with msgattrib still noted as an
option).
Pin to git-po-helper >= 0.9.1 to rely on new helper features: version
comparison for the minimum version check, and `git-po-helper stat -c`
used by the next commit to count PO entries.
Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
Reading a counter with "cmd || echo 0" breaks whenever the command
writes output but still exits non-zero. On zero matches, "grep -c"
prints 0 and exits with status 1, so the command substitution
captured two zeros and the arithmetic that follows failed with a
syntax error instead of evaluating to 0.
Fix by ignoring the exit status with "|| true" and defaulting the
empty value with "${VAR:-0}". Apply this to ENTRY_COUNT in both
l10n_one_batch() and review_one_batch(), and to the BATCH counter
read from po/review-batch.txt, which used the same fragile fallback.
Signed-off-by: Jiang Xin <worldhello.net@gmail.com>
The pathspec matching logic has been updated to avoid out-of-bounds
memory accesses when a negative pathspec is shorter than the common
prefix of positive pathspecs.
* yt/pathspec-negative-prefix:
dir: preserve pathspec prefix optimization with leading excludes
dir: do not apply prefix to negative pathspecs
Doc updates.
* tz/doc-pack-refs-and-refs-fixes:
doc/refs: backtick-quote commands and options consistently
doc/pack-refs: convert synopsis and options to new style
Normalize name formatting and map older formats to the canonical one.
Signed-off-by: Yoichi NAKAYAMA <yoichi.nakayama@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
The memory leak caused by not unusing the commit buffer returned by
repo_logmsg_reencode() during the rewording operation in 'git
history' has been plugged.
* ks/history-commit-leakfix:
builtin/history: unuse the commit buffer after use
When cross-compiling with Cargo, the output artifact is placed in a
target-specific subdirectory, which causes the build system to fail
to locate it. The build system has been updated to respect the
'CARGO_BUILD_TARGET' environment variable.
* jc/rust-cargo-build-target:
rust: respect CARGO_BUILD_TARGET when locating build output
Update Windows CI build to support Rust.
* js/rust-in-windows-ci:
ci(windows): build with Rust
rust: pick a GCC-compatible Cargo target under MSYS2/MinGW
The consistency checks for the object database (fsck) have been
decoupled from the generic builtin implementation and moved into the
backend-specific object source layers, making them pluggable for
different object storage formats.
* ps/odb-pluggable-fsck:
builtin/fsck: move loose object verification into the loose source
builtin/fsck: move multi-pack index verification into the packed source
builtin/fsck: move bitmap verification into the packed source
builtin/fsck: move reverse index verification into the packed source
builtin/fsck: move packfile verification into the packed source
odb: provide infrastructure for pluggable fsck checks
builtin/fsck: don't check alternates with "--no-full"
builtin/fsck: de-globalize option handling
builtin/fsck: merge `fsck_obj_buffer()` and `fsck_obj()`
builtin/fsck: use `fsck_obj_buffer()` when checking loose objects
The mechanism to register in-memory alternate object sources has
been removed, as submodule object databases are now accessed
natively via their own repository structures. This simplifies
object database management and prepares the codebase for migrating
alternate tracking into the files backend.
* ps/odb-stop-registering-in-memory-sources:
odb: remove the ability to link sources ad-hoc
t/helper: stop registering alternates in "ref-store" command
t/helper: adapt read-midx to not link ad-hoc source anymore
builtin/multi-pack-index: refuse unknown sources with "--object-dir="
odb/packed: fix memory leaks when freeing source
tmp-objdir: drop unused function to register alternate
odb: remove infrastructure to register submodule sources
builtin/grep: stop registering submodule ODB as source
submodule-config: stop registering submodule sources
submodule-config: stop using `the_hash_algo`
submodule-config: remove uses of `the_repository`
cache-tree: remove dependency on `the_repository`
cache-tree: drop `the_repository` in `cache_tree_fully_valid()`
Windows build switches from MINGW64 to URCR64 runtime starting Git
2.56.0; switch the cmake based build at the same time.
* js/win-cmake-use-ucrt64:
cmake(windows): accommodate for Git for Windows' migration to UCRT64
Correct tests that depend on Perl running on MinGW
* js/mingw-test-fixes-around-perl:
t9129: skip UTF-8 tests on Windows
t9700: accommodate for MSYS2 Perl reporting as `cygwin`
The git-refs doc was converted to the synopsis style in 89be7d2774
(builtin/refs: add '--no-reflog' flag to drop reflogs, 2025-02-21). The
commands and options were not backtick-quoted at that time. 84f3d6e11e
(doc lint: check that synopsis manpages have synopsis inlines,
2025-08-11) applied backtick-quotes to the existing commands and
options.
Subsequently, a number of commands and options were added without such
quoting, leaving the documentation rendered inconsistently. Apply
backtick-quotes to all entries.
Signed-off-by: Todd Zullinger <tmz@pobox.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Replace [verse] with [synopsis] in the SYNOPSIS block and remove
single-quote formatting from the command name.
Backtick-quote all option terms in the OPTIONS section via the included
pack-refs-options.adoc and convert the standalone placeholder _<branch>_
in prose.
Signed-off-by: Todd Zullinger <tmz@pobox.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Every call to repo_logmsg_reencode() must be paired with a call to
repo_unuse_commit_buffer(), or we may leak an allocated buffer. We
have such a leak in "git history", which we can fix by adding an unuse
call.
The leak-checking tests don't detect this because we only allocate a
fresh buffer sometimes: when the message is reencoded, or when we had
to load it fresh from the odb (e.g., because the commit was parsed
from the commit graph rather than the object contents). But you can
see it by running:
make SANITIZE=leak
cd t
GIT_TEST_COMMIT_GRAPH=1 ./t3451-history-reword.sh
Helped-by: Jeff King <peff@peff.net>
Signed-off-by: Kaartic Sivaraam <kaartic.sivaraam@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
The git rev-list command has been augmented with a '--missing-only'
option that filters the output to only show missing objects,
stripping the leading '?' character and suppressing present objects,
which is useful when used in combination with '--missing=print' or
'--missing=print-info'.
* sa/rev-list-missing-only:
rev-list: add --missing-only option to filter output
"git maintenance" triggered "rerere gc" in unappropriate times and
interfered with "git rebase" etc. too much. The conditions "rerere
gc" gets triggered have been tweaked.
* ps/tune-rerere-gc:
builtin/maintenance: improve heuristic for "rerere gc"
rerere: extract logic to determine whether entries are stale
The autostash fallback in 'git checkout -m' has been refined to only
retry when there are local changes. Additionally, a blank line now
visually separates autostash conflict advice from the subsequent
branch-switch message.
* hn/checkout-m-autostash-refine:
checkout: separate autostash conflict advice from branch-switch message
stash: reserve exit status 1 for conflicts
The 'git imap-send' command has been taught to take the '--draft'
option to mark uploaded messages as drafts, which helps some email
clients render them properly for editing and sending.
* wf/imap-send-draft:
imap-send: add --draft to set IMAP \Draft flag
CGI helper scripts used by HTTP-related test scripts have been updated
to use atomic filesystem operations, preventing race conditions when
Apache handles concurrent requests.
* mm/lib-httpd-cgi-safe:
t/lib-httpd: document writing concurrency-safe CGI helpers
t/lib-httpd: make http-429 first-request check atomic
t/lib-httpd: fix apply-one-time-script race under concurrent requests
Directory walks use the common directory prefix of non-exclude
pathspec items to avoid scanning unrelated portions of the working
tree or index. Exclude items only remove paths from that candidate
set, so they do not need to widen the traversal.
When an exclude item is the first pathspec item, common_prefix_len()
fails to establish a comparison base and returns a zero-length prefix.
The result is correct, but Git unnecessarily traverses from a broader
starting point even when all non-exclude items share a directory.
Use the first non-exclude item as the comparison base and return its
string together with the prefix length, allowing callers to start from
the recovered directory prefix. Exclude matching continues to use full
paths, so this restores the optimization without changing which paths
are selected. Add a unit test covering an exclude item before two
non-exclude items with a common directory.
Signed-off-by: Yannik Tausch <dev@ytausch.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
common_prefix_len() derives the common prefix solely from non-exclude
pathspec items. However, match_pathspec_with_flags() also passes that
prefix when matching exclude items.
This can produce incorrect results because that prefix does not
necessarily match an exclude item. For example, given non-exclude items
"a/b" and "a/c" and an exclude item "x/b", stripping the two-byte
prefix from both the pathname "a/b/m" and pattern "x/b" makes the
remaining strings match and incorrectly excludes the pathname.
If an exclude item is shorter than the prefix, match_pathspec_item()
instead advances item->match beyond its allocation and subtracts the
prefix from item->len, producing a negative matchlen. It then
dereferences the out-of-bounds pointer. If the resulting byte is not
NUL, matchlen is converted to size_t when passed to ps_strncmp(), which
may cause a much larger out-of-bounds read.
The out-of-bounds access can be reproduced with AddressSanitizer:
make SANITIZE=address CFLAGS="-g -O0" git
git init test &&
cd test &&
DIR=$(printf "a%.0s" {1..150}) &&
mkdir -p "$DIR" &&
touch "$DIR/f.txt" &&
git add -A &&
git commit -m test &&
../git ls-files -- "$DIR/" ":(exclude)xy"
Fix the bug by using a zero prefix when matching exclude items. Add
regression tests for both the deterministic incorrect match and the
shorter exclude item that causes the out-of-bounds access.
Signed-off-by: Yannik Tausch <dev@ytausch.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>