summaryrefslogtreecommitdiff
AgeCommit message (Collapse)AuthorFilesLines
2026-04-29sequencer: allow create_autostash to run silentlyHarald Nordgren3-9/+17
Add a silent parameter to create_autostash_internal and introduce create_autostash_ref_silent so that callers can create an autostash without printing the "Created autostash" message. Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-29stash: add --label-ours, --label-theirs, --label-base for applyHarald Nordgren4-12/+57
Allow callers of "git stash apply" to pass custom labels for conflict markers instead of the default "Updated upstream" and "Stashed changes". Document the new options and add a test. Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-29index-pack, unpack-objects: increase input buffer from 4 KiB to 128 KiBScott Bauersfeld4-5/+9
index-pack and unpack-objects both read pack data from stdin through a 4 KiB static buffer. In index-pack, each fill() flushes consumed bytes to the pack file via write_or_die(), capping every write(2) at 4 KiB. unpack-objects uses the same buffer pattern for reads. On FUSE-backed filesystems every write(2) is a synchronous round trip through the FUSE protocol (userspace -> kernel -> userspace -> back), so the 4 KiB buffer turns a clone into many unnecessary tiny writes with noticeable latency overhead. Increase the buffer from 4 KiB to 128 KiB. Introduce a shared DEFAULT_IO_BUFFER_SIZE constant in git-compat-util.h (next to MAX_IO_SIZE) and use it in index-pack, unpack-objects, and the hashfile layer in csum-file (which already used 128 KiB but hardcoded the value). Pack file writes to a FUSE filesystem with writeback caching disabled during HTTPS clones of git/git (~293 MB pack): 74,958 -> 4,687 (94% fewer) Wall-clock time of git clone over HTTPS onto a FUSE passthrough filesystem with writeback caching disabled, 3 runs per variant: vscode (~1.26 GB pack): 84.5s -> 75.7s avg (10% faster) git/git (~306 MB pack): 22.6s -> 20.0s avg (11% faster) Signed-off-by: Scott Bauersfeld <sbauersfeld@g.ucla.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-29t5564: use a short path for the SOCKS proxy socketJohannes Schindelin1-2/+9
The SOCKS proxy test introduced in 0ca365c2ed4 (http: do not ignore proxy path, 2024-08-02) creates a Unix domain socket in `$TRASH_DIRECTORY`. When the trash directory path is long (e.g. when running from a deeply nested worktree), the socket path can exceed the 108-character limit for `struct sockaddr_un.sun_path` on Linux, causing the test to fail with "Path length ... is longer than maximum supported length (108)". We cannot work around this using the chdir trick our own socket code employs, because both sides of the connection are outside our control: the socket is created by socks4-proxy.pl via Perl's IO::Socket::UNIX, and the client side is libcurl. Use `mktemp -d` to create a unique temporary directory with a short path, and place the socket inside it. This avoids collisions between concurrent test runs (e.g. `--stress`) and tmpdir-race vulnerabilities that a static `/tmp` path would be susceptible to. Helped-by: Jeff King <peff@peff.net> Assisted-by: Claude Opus 4.6 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-29t2000: consolidate second scenario into a single test blockZakariyah Ali1-57/+8
The second test scenario in t2000 consists of several fragmented test_expect_success blocks that handle data setup, tree writes, execution of git-checkout-index, and final state validation. Consolidate these nine separate blocks into a single self-contained test block. This follows the modern Git testing standard where setup, execution, and validation of a single logical scenario are kept together. As a result of this consolidation, the show_files() helper and its associated test_debug calls are no longer used and have been removed. This also removes a dependency on the non-portable 'find -ls' command. Helped-by: Karthik Nayak <karthik.188@gmail.com> Helped-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Zakariyah Ali <zakariyahali100@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-28commit: sign commit after mutating bufferbrian m. carlson2-4/+21
The ensure_utf8 function can mutate the buffer to change its encoding, so we must call it before signing the buffer so that we do not invalidate the signature, which is made over raw bytes. Fix a bug which caused the compatibility code to not convert the compatibility buffer if the main buffer was invalid UTF-8. We expect both buffers to be valid UTF-8 or both invalid, since the only data that would differ between them would be hex object IDs, which are always valid UTF-8. Add a test for this case using 0xfe and 0xff, which are never valid in UTF-8. Reported-by: Kushal Das <kushal@sunet.se> Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-28commit: name UTF-8 function appropriatelybrian m. carlson1-3/+3
We have a function named verify_utf8, but it does more than verify, it modifies the buffer if it is not UTF-8. This is different from what most people would expect, so call the function ensure_utf8, since it mutates the buffer in some cases. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-28doc: log: use the same delimiter in description listKristoffer Haugsbakk1-1/+1
We must use the same delimiter since this is a meant to be a flat list. Introducing a new legal delimiter like `::` makes an inner description list: ... full the full ref name ... auto if the output ... Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-28doc: log: fix --decorate description listKristoffer Haugsbakk1-2/+2
026f2e3b (doc: convert git-log to new documentation format, 2025-07-07) transformed the inline description of `--decorate` options to a description list: We also transform inline descriptions of possible values of option --decorate into a list, which is more readable and extensible. But a source code block was used instead of an open block. Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-27builtin/history: introduce "fixup" subcommandPatrick Steinhardt4-6/+999
The newly introduced git-history(1) command provides functionality to easily edit commit history while also rebasing dependent branches. The functionality exposed by this command is still somewhat limited though. One common use case when editing commit history that is not yet covered is fixing up a specific commit. Introduce a new subcommand that allows the user to do exactly that by performing a three-way merge into the target's commit tree, using HEAD's tree as the merge base. The flow is thus essentially: $ echo changes >file $ git add file $ git history fixup HEAD~ Like with the other commands, this will automatically rebase dependent branches, as well. Unlike the other commands though: - The command does not work in a bare repository as it interacts with the index. - The command may run into merge conflicts. If so, the command will simply abort. Especially the second item limits the usefulness of this command a bit. But there are plans to introduce first-class conflicts into Git, which will help use cases like this one. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-27builtin/history: generalize function to commit treesPatrick Steinhardt1-19/+26
The function `commit_tree_with_edited_message_ext()` can be used to commit a tree with a specific list of parents with an edited commit message. This function is useful outside of editing the commit message though, as it also performs the plumbing to extract the original commit message and strip some headers from it. Refactor the function to receive a flags field that allows the caller to control whether or not the commit message should be edited, or whether it should be retained as-is. This will be used in a subsequent commit. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-27replay: allow callers to control what happens with empty commitsPatrick Steinhardt2-5/+43
When replaying commits it may happen that some of the commits become empty relative to their parent. Such commits are for now automatically dropped by the replay subsystem without much control from the user. Introduce a new enum that allows the caller to drop, keep or abort in this case. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-27safe.bareRepository: default to "explicit" with WITH_BREAKING_CHANGESJohannes Schindelin4-4/+44
When an attacker can convince a user to clone a crafted repository that contains an embedded bare repository with malicious hooks, any Git command the user runs after entering that subdirectory will discover the bare repository and execute the hooks. The user does not even need to run a Git command explicitly: many shell prompts run `git status` in the background to display branch and dirty state information, and `git status` in turn may invoke the fsmonitor hook if so configured, making the user vulnerable the moment they `cd` into the directory. The `safe.bareRepository` configuration variable (introduced in 8959555cee7e (setup_git_directory(): add an owner check for the top-level directory, 2022-03-02)) already provides protection against this attack vector by allowing users to set it to "explicit", but the default remained "all" for backwards compatibility. Since Git 3.0 is the natural point to change defaults to safer values, flip the default from "all" to "explicit" when built with `WITH_BREAKING_CHANGES`. This means Git will refuse to work with bare repositories that are discovered implicitly by walking up the directory tree. Bare repositories specified via `--git-dir` or `GIT_DIR` continue to work, and directories that look like `.git`, worktrees, or submodule directories are unaffected (the existing `is_implicit_bare_repo()` whitelist handles those cases). Users who rely on implicit bare repository discovery can restore the previous behavior by setting `safe.bareRepository=all` in their global or system configuration. The test for the "safe.bareRepository in the repository" scenario needed a more involved fix: it writes a `safe.bareRepository=all` entry into the bare repository's own config to verify that repo-local config does not override the protected (global) setting. Previously, `test_config -C` was used to write that entry, but its cleanup runs `git -C <bare-repo> config --unset`, which itself fails when the default is "explicit" and the global config has already been cleaned up. Switching to direct git config --file access avoids going through repository discovery entirely. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-27status tests: filter `.gitconfig` from status outputJohannes Schindelin5-2/+34
Since test-lib.sh creates `$HOME/.gitconfig` when `WITH_BREAKING_CHANGES` is in effect, the file appears in `git status` output as either untracked (`?? .gitconfig`) or ignored (`!! .gitconfig` / `! .gitconfig`, depending on porcelain version), because the `.git/info/exclude` entry causes git to treat it as an ignored file rather than hiding it entirely. In t7061 and t7521, which are pervasively affected, introduce a `filter_gitconfig` helper that strips all status-prefix variants of `.gitconfig` from the output before comparison. In the remaining scripts (t7060, t7064, t7508), apply targeted adjustments. Assisted-by: Claude Opus 4.6 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-27ls-files tests: filter `.gitconfig` from `--others` outputJohannes Schindelin7-2/+21
The global `safe.bareRepository=all` setting in test-lib.sh is written to `$HOME/.gitconfig`, which unfortunately lives inside the test repository's working tree. The `.git/info/exclude` entry added alongside it handles most commands, but `git ls-files --others` without `--exclude-standard` does not consult `info/exclude` at all, so the file appears in the output. Ideally, each test that accesses a bare repository would simply specify `--git-dir` or `GIT_DIR` explicitly, which would require no global config and produce no side effects in the working tree. As that approach was not taken, filter `.gitconfig` from the output before comparing against expected results. In t7104, the test already uses `--exclude-standard`, so it suffices to switch from the bare `git ls-files -o` to `git ls-files -o --exclude-standard` which respects the `info/exclude` entry; the other tests deliberately omit `--exclude-standard` because their purpose is to verify unfiltered `--others` output. Assisted-by: Claude Opus 4.6 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-27t5601: restore `.gitconfig` after includeIf testJohannes Schindelin1-1/+3
One test in t5601 overwrites `$HOME/.gitconfig` with an `includeIf` configuration snippet and removes the file in its cleanup. This destroys the `safe.bareRepository=all` entry that test-lib.sh writes when `WITH_BREAKING_CHANGES` is in effect, causing later tests that use `git -C <bare-repo> config` to fail with "not in a git directory". Back up `.gitconfig` before overwriting and restore it in the cleanup, so the global config survives into subsequent tests. Assisted-by: Claude Opus 4.6 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-27t1305: use `--git-dir=.` for bare repo in include cycle testJohannes Schindelin1-2/+2
Earlier tests in t1305 overwrite `$HOME/.gitconfig` with their own content as part of testing config includes. This clobbers the `safe.bareRepository=all` entry that test-lib.sh writes when `WITH_BREAKING_CHANGES` is in effect, causing `git -C cycle config` to fail with "not in a git directory" when it tries to access the bare repository created by `git init --bare cycle`. Use `--git-dir=.` to access the bare repo explicitly, avoiding the dependency on global config for repository discovery. Assisted-by: Claude Opus 4.6 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-27t1300: remove global config settings injected by test-lib.shJohannes Schindelin1-0/+7
Since test-lib.sh now writes `safe.bareRepository=all` to the global config when `WITH_BREAKING_CHANGES` is in effect, that entry shows up in `git config --list` output. Tests in t1300 that expect exact config contents then fail because of this unexpected extra line. Unlike the working-tree contamination fixed in the preceding commits, this is not about the file's existence but about its content leaking into test expectations. Since t1300 does not use bare repositories, simply remove the injected setting in a preparatory step. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Assisted-by: Claude Opus 4.6 Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-27t7900: do not let `$HOME/.gitconfig` interfere with XDG testsJohannes Schindelin1-2/+10
The XDG config tests for `git maintenance register/unregister` create a fresh `$XDG_CONFIG_HOME/git/config` and expect git to use that location. However, if `$HOME/.gitconfig` exists (which may happen when test-lib.sh writes global config, e.g. to set `safe.bareRepository`), git prefers `$HOME/.gitconfig` over the XDG location, and the `maintenance.repo` entry ends up in the wrong file. This is an inherent consequence of setting global config in test-lib.sh rather than adjusting individual tests: writing any entry to `$HOME/.gitconfig` has side effects beyond the intended setting, because the mere existence of that file changes which global config location git prefers for all subsequent writes. Individual per-test adjustments would not have this interaction. Fix this by overriding `HOME` to a non-existent directory inside the subshells that test XDG behavior. Since these subshells already override `XDG_CONFIG_HOME`, they do not need `$HOME/.gitconfig` at all, and the subshell scoping ensures the original `HOME` is restored automatically. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-27test-lib: allow bare repository access when breaking changes are enabledJohannes Schindelin1-0/+13
A future patch will change the `safe.bareRepository` default from `all` to `explicit` under `WITH_BREAKING_CHANGES`. At that point, every test that operates on a bare repository through implicit discovery would fail, regardless of whether the test is actually about discovery or about how a specific command behaves once inside a bare repository. The maintainer suggested [1] setting `safe.bareRepository=all` in the test environment's global config whenever `WITH_BREAKING_CHANGES` is in effect, rather than adjusting each affected test to access bare repositories explicitly (via `--git-dir`, `GIT_DIR`, or similar). This means the test suite continues to exercise only the historical default behavior even after the user-facing default changes, relying on a small number of dedicated tests in t0035 to validate the new, stricter default. Since `$HOME` points at the trash directory (which doubles as the test repository's working tree), writing to `$HOME/.gitconfig` also creates a file inside the working tree. Exclude it via `.git/info/exclude` to limit the fallout, though this does not help tests that use `git ls-files --others` without `--exclude-standard` or `git status --ignored`; those are addressed by subsequent commits. The `.git/info/exclude` write is guarded by `test -d .git/info` rather than using `mkdir -p`, because some tests (e.g. t0008) expect to create `.git/info/` themselves and would fail with Patrick Steinhardt's `set -e` preparation (ps/test-set-e-clean) if the directory already existed. For tests using `TEST_NO_CREATE_REPO` (where no `.git/` exists at all), the guard also handles that case. [1] https://lore.kernel.org/git/xmqqse98cc51.fsf@gitster.g/ Original-patch-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-26l10n: it: fix italian usage messages alignmentMatteo Beniamino1-1/+1
Fixed a misalignment in the "usage:" and " or:" lines in the italian help messages. Signed-off-by: Matteo Beniamino <beniamino@beniamino.eu>
2026-04-25grep: fix --column --only-match for 2nd and later matchesRené Scharfe2-4/+5
"git grep --column --only-match" shows the 1-based column number of the first match on each line, but confusing numbers for further matches. Example: $ echo 123456789012345678901234567890 >file $ for d in 1 2 3 4 5 6 7 8 9 0 do git grep --no-index --column --only-matching $d file | awk -v FS=: -v l=$d: '{l = l sprintf("%3s", $2)} END {print l}' done 1: 1 2 12 2: 2 4 14 3: 3 6 16 4: 4 8 18 5: 5 10 20 6: 6 12 22 7: 7 14 24 8: 8 16 26 9: 9 18 28 0: 10 20 30 Report the column number of each match instead: $ for d in 1 2 3 4 5 6 7 8 9 0 do ./git grep --no-index --column --only-matching $d file | awk -v FS=: -v l=$d: '{l = l sprintf("%3s", $2)} END {print l}' done 1: 1 11 21 2: 2 12 22 3: 3 13 23 4: 4 14 24 5: 5 15 25 6: 6 16 26 7: 7 17 27 8: 8 18 28 9: 9 19 29 0: 10 20 30 We need to adjust the test in t7810 as well. The file it uses has the following five lines; I add a line highlighting the matches and a ruler at the bottom here, to make it easier to see that the second "mmap" indeed starts at column 14: foo mmap bar foo_mmap bar foo_mmap bar mmap foo mmap bar_mmap foo_mmap bar mmap baz ==== ==== 123456789 123456789 1 Reported-by: Brandon Chinn <brandonchinn178@gmail.com> Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-25alias: restore support for simple dotted aliasesJonatan Holmgren3-3/+34
Historically, config entries like alias.foo.bar expanded the alias "foo.bar". The subsection-based alias syntax introduced in ac1f12a9de (alias: support non-alphanumeric names via subsection syntax, 2026-02-18) broke that behavior by treating such entries as if they were subsection syntax. Restore support for the old dotted form by falling back to the full name when the final key is not "command". Add tests covering execution and help output for simple dotted aliases. Reported-by: Michael Grossfeld <michael.grossfeld@amd.com> Helped-by: Jeff King <peff@peff.net> Signed-off-by: Jonatan Holmgren <jonatan@jontes.page> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-22Revert "transport-helper, connect: use clean_on_exit to reap children on ↵Jeff King2-6/+0
abnormal exit" This reverts commit dd3693eb0859274d62feac8047e1d486b3beaf31. The goal of that commit was to avoid zombie child processes hanging around when the parent git process is killed. But it doesn't quite work when the child command is run by the shell: 1. If there is a shell, then we kill and wait for the shell, not the process spawned by the shell. And so the child process, even if it eventually exits, will hang around as a zombie forever. And this is true of most (all?) shells: bash, dash, etc. So we are not really accomplishing our goal in the first place. 2. Not all shells will exit immediately upon receiving a signal. In particular, mksh will wait for its children to exit (but not actually propagate the signal to them!) leaving us with a potential deadlock: git is wait()ing on mksh, which is wait()ing on a child process, but that child process is waiting on git to produce more input (or EOF) over a pipe. You can see several examples of this deadlock in the test suite, for example by running: make SHELL_PATH=/bin/mksh cd t ./t5702-protocol-v2.sh Because this is a regression for mksh users, and because we did not achieve our goal even with other shells, let's revert the commit for now. If there is a more clever way of doing the same thing, we can consider applying it separately on top (or do nothing and just accept the zombies and rely on PID 1 to reap them). Reported-by: Jan Palus <jpalus@fastmail.com> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-22t6112: avoid tilde expansionSZEDER Gábor1-3/+3
e987df5fe6 (list-objects-filter: implement composite filters, 2019-06-27) introduced a test to "t6112-rev-list-filters-objects.sh" that checks the output of a Git command with the following commands: grep ~$omitted_1 actual && grep ~$omitted_2 actual && grep ~$omitted_3 actual && Since the leading tilde in the pattern is not quoted/escaped, it is subject to tilde expansion. So if the system has a user whose username happens to be "$omitted_1", then "grep" would look for that user's home directory. Quote those words starting with a tilde to avoid this. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-22merge-ort: handle cached rename & trivial resolution interaction betterElijah Newren2-26/+82
Back in commit a562d90a350d (merge-ort: fix failing merges in special corner case, 2025-11-03), we hit a rename assertion due to a trivial directory resolution affecting the parent of a cached rename. Since the path didn't need to be considered, we side-stepped it with if (!newinfo) continue; in process_renames(). We have since run into a case in production where a trivial resolution of a file affects the direct target of a cached rename rather than a parent directory of it. Add a testcase demonstrating this additional case. Now, if we were to follow the lead of commit a562d90a350d, we could resolve this alternate case with an extra condition on the above if: if (!newinfo || newinfo->merged.clean) continue; However, if we had done that earlier, we would have made 979ee83e8a90 (merge-ort: fix corner case recursive submodule/directory conflict handling, 2025-12-29) harder to find and fix, and this particular position for this condition isn't actually at the root of the issue but downstream from it. Instead, let's rip out this if-check from a562d90a350d and put in an alternative that more directly addresses trivially resolved paths that happen to be cached renames or parent directories thereof, which is a better fix for the original testcase and which also solves the newly added testcase as well. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-22Fix docs for format.commitListFormatMirko Faina1-1/+1
When renaming the option --cover-letter-format to --commit-list-format we forgot to rename the opton in the section too. Fix it. Signed-off-by: Mirko Faina <mroik@delayed.space> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-22t: detect errors outside of test casesPatrick Steinhardt2-0/+31
We have recently merged a patch series that had a simple misspelling of `test_expect_success`. Instead of making our tests fail though, this typo went completely undetected and all of our tests passed, which is of course unfortunate. This is a more general issue with our test suite: all commands that run outside of a specific test case can fail, and if we don't explicitly check for such failure then this failure will be silently ignored. Improve the status quo by enabling the errexit option so that any such unchecked failures will cause us to abort immediately. Note that for now, we only enable this option for Bash 5 and newer. This is because other shells have wildly different behaviour, and older versions of Bash (especially on macOS) are buggy. The list of enabled shells may be extended going forward. Helped-by: Jeff King <peff@peff.net> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-22t9902: fix use of `read` with `set -e`Patrick Steinhardt1-4/+2
In t9902 we're using the `read` builtin to read some values into a variable. This is done by using `-d ""`, which cause us to read until the end of the heredoc. As the read is terminated by EOF, the command will end up returning a non-zero error code. This hasn't been an issue until now as we didn't run with `set -e`, but that'll change in a subsequent commit. Prepare for this change by not using read at all, as we can simply store the multi-line value directly. Suggested-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-22t6002: fix use of `expr` with `set -e`Patrick Steinhardt1-6/+9
In `test_bisection_diff ()` we use `expr` to perform some math. This command has some gotchas though in that it will only return success when the result is neither null nor zero. In some of our cases though it actually _is_ zero, and that will cause the expressions to fail once we enable `set -e`. Prepare for this change by instead using `$(( ))`, which doesn't have the same issue. While at it, modernize the function a tiny bit. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-22t1301: don't fail in case setfacl(1) doesn't exist or failsPatrick Steinhardt1-1/+1
In t1301 we're trying to remove any potentially-existing default ACLs that might exist on the transh directory by executing setfacl(1). According to 8ed0a740dd (t1301-shared-repo.sh: don't let a default ACL interfere with the test, 2008-10-16), this is done because we play around with permissions and umasks in this test suite. The setfacl(1) binary may not exist on some systems though, even though tests ultimately still pass. This doesn't matter currently, but will cause the test to fail once we start running with `set -e`. Silence such failures by ignoring failures here. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-22t0008: silence error in subshell when using `grep -v`Patrick Steinhardt1-2/+2
In t0008 we use `grep -v` in a subshell, but expect that this command will sometimes not match anything. This would cause grep(1) to return an error code, but given that we don't run with `set -e` we swallow this error. We're about to enable `set -e`. Prepare for this by ignoring any errors. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-22t: prepare `test_when_finished ()`/`test_atexit()` for `set -e`Patrick Steinhardt1-2/+2
Both `test_when_finished ()` and `test_atexit ()` build up a chain of cleanup commands by prepending each new command to the existing cleanup string. To preserve the exit code of the test body across cleanup execution, we append the following logic: } && (exit "$eval_ret"); eval_ret=$?; ... The intent of this is to run the cleanup block and then unconditionally restore `eval_ret`. The original behaviour of this is is: +------------------+---------+------------------------------------+ |test body │ cleanup │ old behaviour │ +------------------+---------+------------------------------------+ │pass (eval_ret=0) | pass │ && taken -> (exit 0) -> eval_ret=0 | +------------------+---------+------------------------------------+ │pass (eval_ret=0) | fail │ && not taken -> eval_ret=$? | +------------------+---------+------------------------------------+ │fail (eval_ret=1) | pass │ && taken -> (exit 1) -> eval_ret=1 | +------------------+---------+------------------------------------+ │fail (eval_ret=1) | fail | && not taken -> eval_ret=$? | +------------------+---------+------------------------------------+ This logic will start to fail once we enable `set -e`. When `$eval_ret` is non-zero, the subshell we create will fail, and with `set -e` we'll thus bail out without evaluating the logic after the semicolon. Fix this issue by instead using `|| eval_ret=\$?; ...`. Besides being a bit simpler, it also retains the original behaviour: +------------------+---------+------------------------------------+ |test body │ cleanup │ old behaviour │ +------------------+---------+------------------------------------+ │pass (eval_ret=0) | pass │ || not taken -> eval_ret unchanged | +------------------+---------+------------------------------------+ │pass (eval_ret=0) | fail │ || taken -> eval_ret=$? | +------------------+---------+------------------------------------+ │fail (eval_ret=1) | pass │ || not taken -> eval_ret unchanged | +------------------+---------+------------------------------------+ │fail (eval_ret=1) | fail | || taken -> eval_ret=$? | +------------------+---------+------------------------------------+ Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-22t: prepare execution of potentially failing commands for `set -e`Patrick Steinhardt11-24/+24
Several of our tests verify whether a certain binary can be executed, potentially skipping tests in case we cannot, for example because the binary doesn't exist. In those cases we often run the binary outside of any conditionally. This will start to fail once we enable `set -e`, as that will cause us to bail out the test immediately. Improve these tests by executing them inside of a conditional instead. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-22t: prepare conditional test execution for `set -e`Patrick Steinhardt2-16/+20
We have some test in our test suite where we use the pattern of `test ... && test_expect_succeess` to conditionally execute a test. The problem is that when we decide to not execute the test, we'll indeed skip the test, but the overall statement will also be unsuccessful. This will become a problem once we enable `set -e`. Prepare for this future by turning this into a proper conditional, which is also a bit easier to read overall. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-22t: prepare `git config --unset` calls for `set -e`Patrick Steinhardt3-5/+5
We have a couple of calls to `git config --unset` that ultimately end up as no-ops as the configuration variables aren't set (anymore) in the first place. These calls are mostly intended to recover unconditionally from tests that may have executed only partially, but they'll ultimately fail during a normal test run. This hasn't been a problem until now as we aren't running tests with `set -e`. This is about to change though, so let's silence the case where we cannot unset the config keys. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-22t: prepare `stop_git_daemon ()` for `set -e`Patrick Steinhardt1-3/+5
We have a couple of calls to `stop_git_daemon ()` outside of specific test cases that will kill a backgrounded git-daemon(1) process and expect the process with a specific error code. While these function calls do end up killing git-daemon(1), the error handling we have in those contexts is basically ineffective. So while we expect the process to exit with a specific error code, we will just continue with any error in case it doesn't. This will change once we enable `set -e` in a subsequent commit. There's two issues though that will make this _always_ fail: - Our call to `wait` is expected to fail, but because it's not part of a condition it will cause us to bail out immediately with `set -e`. - We try to kill git-daemon(1) a second time via the pidfile. We can generally expect that this is the same PID though as we had in the "GIT_DAEMON_PID" environment variable, and thus it's more likely than not that we have already killed it, and the call to kill will fail. Prepare for this change by handling the failure of `wait` with `||` and by silencing failures of the second call to `kill`. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-22t: prepare `test_must_fail ()` for `set -e`Patrick Steinhardt1-2/+3
The helper function `test_must_fail ()` executes a specific Git command that may or may not fail in a specific way. This is done by executing the command in question and then comparing its exit code against a set of conditions. This works, but once we run our test suite with `set -e` we may bail out of `test_must_fail ()` early in case the command actually fails, even though we expect it to fail. Prepare for this change by handling the failed case with `||`. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-22t: prepare `test_match_signal ()` calls for `set -e`Patrick Steinhardt2-3/+3
We have a couple of calls to `test_match_signal ()` where we execute a Git command and expect it to die with a specific signal. These calls will essentially execute the process in a subshell via `foo; echo $?`, but as we expect `foo` to fail this will cause the overall subshell to fail once we `set -e`. Fix this issue by using `foo && echo 0 || echo $?` instead. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-21t7004: avoid subshells to capture git exit codesSiddharth Shrimali1-8/+18
Several tests in t7004 use the 'test$(git ...) = ...' or the '! (git ...)' subshell pattern. This swallows git's exit code. If git crashes (e.g. segmentation fault) the crash would go undetected, and the test would fail due to a mismatch or an inverted exit code. Modernize these tests by directly writing output to files(actual) and verifying them with 'test_cmp' or 'test_grep'. Replace subshell negations with 'test_must_fail'. This way, if git crashes, the test fails immediately and clearly instead of hiding the error behind a string mismatch. Signed-off-by: Siddharth Shrimali <r.siddharth.shrimali@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-21t7004: dynamically grab expected state in testsSiddharth Shrimali1-9/+2
The tests for 'Multiple -l or --list options' and 'trying to delete tags without params', hardcodes that exactly one or two specific tags ('myhead', 'mytag') exist in the repository. If other tests are added, modified, or removed earlier in the script, this expected global state will change, resulting in these tests to fail for completely unrelated reasons. Instead of hardcoding the expected tags, dynamically grab the state of the repository before running the commands under test ('git tag -l' and 'git tag -d'), and verify that the output matches or remains unchanged afterward. This keeps the tests independent from the script's overall state. Signed-off-by: Siddharth Shrimali <r.siddharth.shrimali@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-21t7004: drop hardcoded tag count for state verificationSiddharth Shrimali1-4/+3
The test 'trying to create a tag with a non-valid name should fail', checked that exactly one tag existed in the repository before and after attempting to create invalid tags. As pointed out by Junio, this makes the test brittle by relying on a specific global tag count. If future tests are added or removed before this test, the expected state changes and this test would break for completely unrelated reasons. Modernize the test by taking a snapshot of the existing tags before the failure attempts and comparing it to a snapshot taken after. This provides a "belt-and-suspenders" approach: we verify that 'git tag' both exits with the expected error code and leaves the repository state untouched, without being brittle to the specific number of tags present. This replaces the hardcoded 'test_line_count = 1' checks with 'test_cmp' to ensure the tag list remains identical. Suggested-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Siddharth Shrimali <r.siddharth.shrimali@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-20diff: fix out-of-bounds reads and NULL deref in diffstat UTF-8 truncationElijah Newren2-2/+49
f85b49f3d4a (diff: improve scaling of filenames in diffstat to handle UTF-8 chars, 2026-01-16) introduced a loop in show_stats() that calls utf8_width() repeatedly to skip leading characters until the displayed width fits. However, utf8_width() can return problematic values: - For invalid UTF-8 sequences, pick_one_utf8_char() sets the name pointer to NULL and utf8_width() returns 0. Since name_len does not change, the loop iterates once more and pick_one_utf8_char() dereferences the NULL pointer, crashing. - For control characters, utf8_width() returns -1, so name_len grows when it is expected to shrink. This can cause the loop to consume more characters than the string contains, reading past the trailing NUL. By default, fill_print_name() will C-quote filenames which escapes control characters and invalid bytes to printable text. That avoids this bug from being triggered; however, with core.quotePath=false, most characters are no longer escaped (though some control characters still are) and raw bytes can reach this code. Add tests exercising both failure modes with core.quotePath=false and a narrow --stat-name-width to force truncation: one with a bare 0xC0 byte (invalid UTF-8 lead byte, triggers NULL deref) and one with several C1 control characters (repeats of 0xC2 0x9F, causing the loop to read past the end of the string). The second test reliably catches the out-of-bounds read when run under ASan, though it may pass silently without sanitizers. Fix both issues by introducing utf8_ish_width(), a thin wrapper around utf8_width() that guarantees the pointer always advances and the returned width is never negative: - On invalid UTF-8 it restores the pointer, advances by one byte, and returns width 1 (matching the strlen()-based fallback used by utf8_strwidth()). - On a control character it returns 0 (matching utf8_strnwidth() which skips them). Also add a "&& *name" guard to the while-loop condition so it terminates at end-of-string even when utf8_strwidth()'s strlen() fallback causes name_len to exceed the sum of per-character widths. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-19Git 2.54v2.54.0Junio C Hamano1-1/+1
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-19Merge tag 'l10n-2.54.0-v2' of https://github.com/git-l10n/git-poJunio C Hamano13-4689/+11585
l10n-2.54.0-v2 * tag 'l10n-2.54.0-v2' of https://github.com/git-l10n/git-po: l10n: bg.po: Updated Bulgarian translation (6226t) l10n: zh_TW: update translation for Git 2.54 l10n: Update Catalan Translation l10n: ga.po: update for Git 2.54 l10n: fr: v2.54.0 l10n: tr: Update Turkish translations l10n: sv.po: Update Swedish translation l10n: sv.po: correct various translations l10n: zh_CN: updated translation for 2.54 l10n: bg.po: Updated Bulgarian translation (6226t) l10n: zh_CN: post-2.53 code review l10n: document AI and PO helper in po/README l10n: docs: add review instructions in AGENTS.md l10n: docs: add translation instructions in AGENTS.md l10n: docs: add update PO instructions in AGENTS.md l10n: docs: add AGENTS.md with update POT instructions l10n: add .gitattributes to simplify location filtering l10n: fix 'zh_TW.po' 'Applying patch'
2026-04-20Merge branch 'master' of github.com:alshopov/git-poJiang Xin1-28/+34
* 'master' of github.com:alshopov/git-po: l10n: bg.po: Updated Bulgarian translation (6226t)
2026-04-19gitk: spanish translationsbasuradeluis1-204/+284
Signed-off-by: basuradeluis <basuradeluis@gmail.com>
2026-04-19l10n: bg.po: Updated Bulgarian translation (6226t)Alexander Shopov1-28/+34
Improvements prompted by AI-assisted review Signed-off-by: Alexander Shopov <ash@kambanaria.org>
2026-04-19l10n: zh_TW: update translation for Git 2.54Yi-Jyun Pan1-905/+1782
Signed-off-by: Yi-Jyun Pan <pan93412@gmail.com>
2026-04-19Merge branch 'fr_v2.54.0' of github.com:jnavila/gitJiang Xin1-322/+914
* 'fr_v2.54.0' of github.com:jnavila/git: l10n: fr: v2.54.0