aboutsummaryrefslogtreecommitdiffstats
path: root/t
AgeCommit message (Collapse)AuthorFilesLines
43 hoursMerge branch 'jc/capability-leak'Junio C Hamano2-0/+40
Leakfix. * jc/capability-leak: connect: plug protocol capability leak
5 daysMerge branch 'lo/repo-struct-z'Junio C Hamano1-0/+7
"git repo struct" learned to take "-z" as a synonym to "--format=nul". * lo/repo-struct-z: repo: add -z as an alias for --format=nul to git-repo-structure repo: use [--format=... | -z] instead of [-z] in git-repo-info synopsis repo: remove blank line from Documentation/git-repo.adoc
5 daysMerge branch 'kh/advise-w-git-help-in-branch'Junio C Hamano1-3/+3
A help message from "git branch" now mentions "git help" instead of "man" when suggesting to read some documentation. * kh/advise-w-git-help-in-branch: branch: advice using git-help(1) instead of man(1)
5 daysMerge branch 'js/last-modified-with-sparse-checkouts'Junio C Hamano1-0/+8
"git last-modified" used to mishandle "--" to mark the beginning of pathspec, which has been corrected. * js/last-modified-with-sparse-checkouts: last-modified: support sparse checkouts
10 daysMerge branch 'bc/zsh-testsuite'Junio C Hamano2-3/+3
A few tests have been updated to work under the shell compatible mode of zsh. * bc/zsh-testsuite: t5564: fix test hang under zsh's sh mode t0614: use numerical comparison with test_line_count
10 daysconnect: plug protocol capability leakJunio C Hamano2-0/+40
When pushing to a set of remotes using a nickname for the group, the client initializes the connection to each remote, talks to the remote and reads and parses capabilities line, and holds the capabilities in a file-scope static variable server_capabilities_v1. There are a few other such file-scope static variables, and these connections cannot be parallelized until they are refactored to a structure that keeps track of active connections. Which is *not* the theme of this patch ;-) For a single connection, the server_capabilities_v1 variable is initialized to NULL (at the program initialization), populated when we talk to the other side, used to look up capabilities of the other side possibly multiple times, and the memory is held by the variable until program exit, without leaking. When talking to multiple remotes, however, the server capabilities from the second connection overwrites without freeing the one from the first connection, which leaks. ==1080970==ERROR: LeakSanitizer: detected memory leaks Direct leak of 421 byte(s) in 2 object(s) allocated from: #0 0x5615305f849e in strdup (/home/gitster/g/git-jch/bin/bin/git+0x2b349e) (BuildId: 54d149994c9e85374831958f694bd0aa3b8b1e26) #1 0x561530e76cc4 in xstrdup /home/gitster/w/build/wrapper.c:43:14 #2 0x5615309cd7fa in process_capabilities /home/gitster/w/build/connect.c:243:27 #3 0x5615309cd502 in get_remote_heads /home/gitster/w/build/connect.c:366:4 #4 0x561530e2cb0b in handshake /home/gitster/w/build/transport.c:372:3 #5 0x561530e29ed7 in get_refs_via_connect /home/gitster/w/build/transport.c:398:9 #6 0x561530e26464 in transport_push /home/gitster/w/build/transport.c:1421:16 #7 0x561530800bec in push_with_options /home/gitster/w/build/builtin/push.c:387:8 #8 0x5615307ffb99 in do_push /home/gitster/w/build/builtin/push.c:442:7 #9 0x5615307fe926 in cmd_push /home/gitster/w/build/builtin/push.c:664:7 #10 0x56153065673f in run_builtin /home/gitster/w/build/git.c:506:11 #11 0x56153065342f in handle_builtin /home/gitster/w/build/git.c:779:9 #12 0x561530655b89 in run_argv /home/gitster/w/build/git.c:862:4 #13 0x561530652cba in cmd_main /home/gitster/w/build/git.c:984:19 #14 0x5615308dda0a in main /home/gitster/w/build/common-main.c:9:11 #15 0x7f051651bca7 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16 SUMMARY: AddressSanitizer: 421 byte(s) leaked in 2 allocation(s). Free the capablities data for the previous server before overwriting it with the next server to plug this leak. The added test fails without the freeing with SANITIZE=leak; I somehow couldn't get it fail reliably with SANITIZE=leak,address though. Signed-off-by: Junio C Hamano <gitster@pobox.com>
14 daysMerge branch 'ps/object-source-management'Junio C Hamano2-14/+18
Code refactoring around object database sources. * ps/object-source-management: odb: handle recreation of quarantine directories odb: handle changing a repository's commondir chdir-notify: add function to unregister listeners odb: handle initialization of sources in `odb_new()` http-push: stop setting up `the_repository` for each reference t/helper: stop setting up `the_repository` repeatedly builtin/index-pack: fix deferred fsck outside repos oidset: introduce `oidset_equal()` odb: move logic to disable ref updates into repo odb: refactor `odb_clear()` to `odb_free()` odb: adopt logic to close object databases setup: convert `set_git_dir()` to have file scope path: move `enter_repo()` into "setup.c"
14 daysMerge branch 'cc/fast-import-strip-if-invalid'Junio C Hamano1-1/+68
"git fast-import" learns "--strip-if-invalid" option to drop invalid cryptographic signature from objects. * cc/fast-import-strip-if-invalid: fast-import: add 'strip-if-invalid' mode to --signed-commits=<mode> commit: refactor verify_commit_buffer() fast-import: refactor finalize_commit_buffer()
14 daysMerge branch 'jc/optional-path'Junio C Hamano2-0/+39
"git config get --path" segfaulted on an ":(optional)path" that does not exist, which has been corrected. * jc/optional-path: config: really treat missing optional path as not configured config: really pretend missing :(optional) value is not there config: mark otherwise unused function as file-scope static
14 daysrepo: add -z as an alias for --format=nul to git-repo-structureLucas Seiki Oshiro1-0/+7
Other Git commands that have nul-terminated output, such as git-config, git-status, git-ls-files, and git-repo-info have a flag `-z` for using the null character as the record separator. Add the `-z` flag to git-repo-structure as an alias for `--format=nul`, making it consistent with the behavior of the other commands. Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-12-03last-modified: support sparse checkoutsJohannes Schindelin1-0/+8
In a sparse checkout, a user might want to run `last-modified` on a directory outside the worktree. And even in non-sparse checkouts, a user might need to run that command on a directory that does not exist in the worktree. These use cases should be supported via the `--` separator between revision and file arguments, which is even advertised in the documentation. This patch fixes a tiny bug that prevents that from working. This fixes https://github.com/git-for-windows/git/issues/5978 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Acked-by: Derrick Stolee <stolee@gmail.com> Acked-by: Toon Claes <toon@iotcl.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-12-03branch: advice using git-help(1) instead of man(1)Kristoffer Haugsbakk1-3/+3
8fbd903e (branch: advise about ref syntax rules, 2024-03-05) added an advice about checking git-check-ref-format(1) for the ref syntax rules. The advice uses man(1). But git(1) is a multi-platform tool and man(1) may not be available on some platforms. It might also be slightly jarring to see a suggestion for running a command which is not from the Git suite. Let’s instead use git-help(1) in order to stay inside the land of git(1). This also means that `help.format` (for `man`, `html` or other formats) will be used if set. Also change to using single quotes (') to quote the command since that is more conventional. While here let’s also update the test to use `{SQ}`, which is more readable and easier to edit. Signed-off-by: Kristoffer Haugsbakk <code@khaugsbakk.name> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-30Merge branch 'jk/asan-bonanza'Junio C Hamano1-0/+1
Various issues detected by Asan have been corrected. * jk/asan-bonanza: t: enable ASan's strict_string_checks option fsck: avoid parse_timestamp() on buffer that isn't NUL-terminated fsck: remove redundant date timestamp check fsck: avoid strcspn() in fsck_ident() fsck: assert newline presence in fsck_ident() cache-tree: avoid strtol() on non-string buffer Makefile: turn on NO_MMAP when building with ASan pack-bitmap: handle name-hash lookups in incremental bitmaps compat/mmap: mark unused argument in git_munmap()
2025-11-30Merge branch 'jc/whitespace-incomplete-line'Junio C Hamano2-4/+250
Both "git apply" and "git diff" learn a new whitespace error class, "incomplete-line". * jc/whitespace-incomplete-line: attr: enable incomplete-line whitespace error for this project diff: highlight and error out on incomplete lines apply: check and fix incomplete lines whitespace: allocate a few more bits and define WS_INCOMPLETE_LINE apply: revamp the parsing of incomplete lines diff: update the way rewrite diff handles incomplete lines diff: call emit_callback ecbdata everywhere diff: refactor output of incomplete line diff: keep track of the type of the last line seen diff: correct suppress_blank_empty hack diff: emit_line_ws_markup() if/else style fix whitespace: correct bit assignment comments
2025-11-30Merge branch 'lo/repo-info-all'Junio C Hamano1-0/+21
"git repo info" learned "--all" option. * lo/repo-info-all: repo: add --all to git-repo-info repo: factor out field printing to dedicated function
2025-11-27t5564: fix test hang under zsh's sh modebrian m. carlson1-2/+2
This test starts a SOCKS server in Perl in the background and then kills it after the tests are done. However, when using zsh (in sh mode) in the tests, the start_socks function hangs until the background process is killed. Note that this does not reproduce in a simple shell script, so there is likely some interaction between job handling, our heavy use of eval in the test framework, and possibly other complexities of our test framework. What is clear, however, is that switching from a compound statement to a subshell fixes the problem entirely and the test passes with no problem, so do that. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-27t0614: use numerical comparison with test_line_countbrian m. carlson1-1/+1
In this comparison, we want to know whether the number of lines is greater than 1. Our test_line_count function passes the first argument as the comparison operator to test, so what we want is a numerical comparison, not a string comparison. While this does not produce a functional problem now, it could very well if we expected two or more items, in which case the value "10" would not match when it should. Furthermore, the "<" and ">" comparisons are new in POSIX 1003.1-2024 and we don't want to require such a new version of POSIX since many popular and supported operating systems were released before that version of POSIX was released. Finally, zsh's builtin test operator does not like the greater-than sign in "test", since it is only supported in the double-bracket extension. This has been reported and will be addressed in a future version, but since our code is also technically incorrect, as well as not very compatible, let's fix it by using a numeric comparison. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-26Merge branch 'jk/ci-windows-meson-test-fix'Junio C Hamano1-0/+1
"Windows+meson" job at the GitHub Actions CI was hard to debug, as it did not show and save failed test artifacts, which has been corrected. * jk/ci-windows-meson-test-fix: ci(windows-meson-test): handle options and output like other test jobs unit-test: ignore --no-chain-lint
2025-11-26Merge branch 'pw/worktree-list-display-width-fix'Junio C Hamano1-13/+24
"git worktree list" attempts to show paths to worktrees while aligning them, but miscounted display columns for the paths when non-ASCII characters were involved, which has been corrected. * pw/worktree-list-display-width-fix: worktree list: quote paths worktree list: fix column spacing
2025-11-26Merge branch 'jk/test-mktemp-leakfix'Junio C Hamano1-1/+7
Test leakfix. * jk/test-mktemp-leakfix: test-mktemp: plug memory and descriptor leaks
2025-11-26Merge branch 'ad/blame-diff-algorithm'Junio C Hamano2-0/+204
"git blame" learns "--diff-algorithm=<algo>" option. * ad/blame-diff-algorithm: blame: make diff algorithm configurable xdiff: add 'minimal' to XDF_DIFF_ALGORITHM_MASK
2025-11-26Merge branch 'en/ort-rename-another-fix'Junio C Hamano1-8/+85
Yet another corner case fix around renames in the "ort" merge strategy. * en/ort-rename-another-fix: merge-ort: fix failing merges in special corner case merge-ort: remove debugging crud t6429: update comment to mention correct tool
2025-11-26fast-import: add 'strip-if-invalid' mode to --signed-commits=<mode>Christian Couder1-1/+68
Tools like `git filter-repo`[1] use `git fast-export` and `git fast-import` to rewrite repository history. When rewriting history using one such tool though, commit signatures might become invalid because the commits they sign changed due to the changes in the repository history made by the tool between the fast-export and the fast-import steps. Note that as far as signature handling goes: * Since fast-export doesn't know what changes filter-repo may make to the stream, it can't know whether the signatures will still be valid. * Since filter-repo doesn't know what history canonicalizations fast-export performed (and it performs a few), it can't know whether the signatures will still be valid. * Therefore, fast-import is the only process in the pipeline that can know whether a specified signature remains valid. Having invalid signatures in a rewritten repository could be confusing, so users rewritting history might prefer to simply discard signatures that are invalid at the fast-import step. For example a common use case is to rewrite only "recent" history. While specifying commit ranges corresponding to "recent" commits could work, users worry about getting it wrong and want to just automatically rewrite everything, expecting older commit signatures to be untouched. To let them do that, let's add a new 'strip-if-invalid' mode to the `--signed-commits=<mode>` option of `git fast-import`. It would be interesting for the `--signed-tags=<mode>` option to have this mode too, but we leave that for a future improvement. It might also be possible for `git fast-export` to have such a mode in its `--signed-commits=<mode>` and `--signed-tags=<mode>` options, but the use cases for it are much less clear, so we also leave that for possible future improvements. For now let's just die() if 'strip-if-invalid' is passed to these options where it hasn't been implemented yet. [1]: https://github.com/newren/git-filter-repo Helped-by: Elijah Newren <newren@gmail.com> Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-25t/helper: stop setting up `the_repository` repeatedlyPatrick Steinhardt1-14/+2
The "repository" test helper sets up `the_repository` twice. In fact though, we don't even have to set it up even once: all we need is to set up its hash algorithm, because we still depend on some subsystems that aren't free of `the_repository`. Refactor the code accordingly. This prepares for a subsequent change, where setting up the repository repeatedly will lead to a `BUG()`. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-25builtin/index-pack: fix deferred fsck outside reposPatrick Steinhardt1-0/+16
When asked to perform object consistency checks via the `--fsck-objects` flag we verify that each object part of the pack is valid. In general, this check can even be performed outside of a Git repository: we don't need an initialized object database as we simply read the object from the packfile directly. But there's one exception: a subset of the object checks may be deferred to a later point in time. For now, this only concerns ".gitmodules" and ".gitattributes" files: whenever we see a tree referencing these files we queue them for a deferred check. This is done because we need to do some extra checks for those files to ensure that they are well-formed, and these checks need to be done regardless of whether the corresponding blobs are part of the packfile or not. This works inside a repository, but unfortunately the logic leads to a segfault when running outside of one. This is because we eventually call `odb_read_object()`, which will crash because the object database has not been initialized. There's multiple options here: - We could in theory create a purely in-memory database with only a packfile store that contains the single packfile. We don't really have the infrastructure for this yet though, and it would end up being quite hacky. - We could refuse to perform consistency checks outside of a repository. But most of the checks work alright, so this would be a regression. - We can skip the finalizing consistency checks when running outside of a repository. This is not as invasive as skipping all checks, but it's not great to randomly skip a subset of tests, either. None of these options really feel perfect. The first one would be the obvious choice if easily possible. There's another option though: instead of skipping the final object checks, we can die if there are any queued object checks. With this change we now die exactly if and only if we would have previously segfaulted. Like this we ensure that objects that _may_ fail the consistency checks won't be silently skipped, and at the same time we give users a much better error message. Refactor the code accordingly and add a test that would have triggered the segfault. Note that we also move down the logic to add the packfile to the store. There is no point doing this any earlier than right before we execute `fsck_finish()`, and it ensures that the logic to set up and perform the consistency check is self-contained. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-24config: really pretend missing :(optional) value is not thereJunio C Hamano2-0/+39
Earlier we added support for a value spelled as ":(optional)path" for configuration variables whose values are of type "path", with the documented semantics "if the path is missing, behave as if such a variable definition is not even there." This has worked OK for code paths that reads configuration files and stores the configured value as a string, where NULL in such a string is treated as if the setting is not there, left as the default. However, there are other code paths that do not _ignore_ such NULL values and misbehave. "git config get --path" is one of them. When git_config_pathname() helper function finds that the value of the variable is an optional path *and* the path is missing, it leaves the destination pointer intact (which usually is left to NULL) and returns 0 to signal a success. format_config() helper however assumed that the destination pointer always gets a string, which no longer is the case, and segfaulted. Make sure that git_config_pathname() clears the destination pointer in such a case, and teach format_config() to react to the condition by returning 1 (which is different from 0 that is a normal success and negative that is an error) to its callers. Adjust the callers to react to this new return value that tells them to pretend as if they did not even see this partcular <key, value> pair. Reported-by: Han Jiang <jhcarl0814@gmail.com> Helped-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-24Merge branch 'jx/repo-struct-utf8width-fix'Junio C Hamano2-0/+135
The "git repo structure" subcommand tried to align its output but mixed up byte count and display column width, which has been corrected. * jx/repo-struct-utf8width-fix: builtin/repo: fix table alignment for UTF-8 characters t/unit-tests: add UTF-8 width tests for CJK chars
2025-11-24Merge branch 'sa/replay-atomic-ref-updates'Junio C Hamano1-8/+105
"git replay" (experimental) learned to perform ref updates itself in a transaction by default, instead of emitting where each refs should point at and leaving the actual update to another command. * sa/replay-atomic-ref-updates: replay: add replay.refAction config option replay: make atomic ref updates the default behavior replay: use die_for_incompatible_opt2() for option validation
2025-11-24Merge branch 'bc/submodule-force-same-hash'Junio C Hamano2-0/+51
Adding a repository that uses a different hash function is a no-no, but "git submodule add" did nt prevent it, which has been corrected. * bc/submodule-force-same-hash: read-cache: drop submodule check from add_to_cache() object-file: disallow adding submodules of different hash algo
2025-11-24Merge branch 'jk/attr-macroexpand-wo-recursion'Junio C Hamano1-0/+20
The code to expand attribute macros has been rewritten to avoid recursion to avoid running out of stack space in an uncontrolled way. * jk/attr-macroexpand-wo-recursion: attr: avoid recursion when expanding attribute macros
2025-11-21Merge branch 'kn/maintenance-is-needed'Junio C Hamano2-18/+48
"git maintenance" command learned "is-needed" subcommand to tell if it is necessary to perform various maintenance tasks. * kn/maintenance-is-needed: maintenance: add 'is-needed' subcommand maintenance: add checking logic in `pack_refs_condition()` refs: add a `optimize_required` field to `struct ref_storage_be` reftable/stack: add function to check if optimization is required reftable/stack: return stack segments directly
2025-11-21Merge branch 'rs/diff-quiet-no-rename'Junio C Hamano1-0/+10
As "git diff --quiet" only cares about the existence of any changes, disable rename/copy detection to skip more expensive processing whose result will be discarded anyway. * rs/diff-quiet-no-rename: diff: disable rename detection with --quiet
2025-11-19Merge branch 'kn/refs-optim-cleanup'Junio C Hamano3-2/+4
Code clean-up. * kn/refs-optim-cleanup: t/pack-refs-tests: move the 'test_done' to callees refs: rename 'pack_refs_opts' to 'refs_optimize_opts' refs: move to using the '.optimize' functions
2025-11-19Merge branch 'ps/ref-peeled-tags'Junio C Hamano6-23/+106
Some ref backend storage can hold not just the object name of an annotated tag, but the object name of the object the tag points at. The code to handle this information has been streamlined. * ps/ref-peeled-tags: t7004: do not chdir around in the main process ref-filter: fix stale parsed objects ref-filter: parse objects on demand ref-filter: detect broken tags when dereferencing them refs: don't store peeled object IDs for invalid tags object: add flag to `peel_object()` to verify object type refs: drop infrastructure to peel via iterators refs: drop `current_ref_iter` hack builtin/show-ref: convert to use `reference_get_peeled_oid()` ref-filter: propagate peeled object ID upload-pack: convert to use `reference_get_peeled_oid()` refs: expose peeled object ID via the iterator refs: refactor reference status flags refs: fully reset `struct ref_iterator::ref` on iteration refs: introduce `.ref` field for the base iterator refs: introduce wrapper struct for `each_ref_fn`
2025-11-18repo: add --all to git-repo-infoLucas Seiki Oshiro1-0/+21
Add a new flag `--all` to git-repo-info for requesting values for all the available keys. By using this flag, the user can retrieve all the values instead of searching what are the desired keys for what they wants. Helped-by: Karthik Nayak <karthik.188@gmail.com> Helped-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Lucas Seiki Oshiro <lucasseikioshiro@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-18worktree list: quote pathsPhillip Wood1-1/+14
If a worktree path contains newlines or other control characters it messes up the output of "git worktree list". Fix this by using quote_path() to display the worktree path. The output of "git worktree list" is designed for human consumption, scripts should be using the "--porcelain" option so this change should not break them. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-18worktree list: fix column spacingPhillip Wood1-12/+10
The output of "git worktree list" displays a table containing the worktree path, HEAD OID and branch name for each worktree. The code aligns the columns by measuring the visual width of the worktree path when it is printed. Unfortunately it fails to use the visual width when calculating the width of the column so, if any of the paths contain a multibyte character, we can end up with excess padding between columns. The simplest fix would be to replace strlen() with utf8_strwidth() in measure_widths(). However that leaves us measuring the visual width twice and the byte length once. By caching the visual width and printing the padding separately to the worktree path, we only need to calculate the visual width once and do not need the byte length at all. The visual widths are stored in an arrays of structs rather than an array of ints as the next commit will add more struct members. Even if there are no multibyte characters in any of the paths we still print an extra space between the path and the object id as the field width is calculated as one plus the length of the path and we print an explicit space as well. This is fixed by not printing the extra space. The tests are updated to include multibyte characters in one of the worktree paths and to check the spacing of the columns. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-18test-mktemp: plug memory and descriptor leaksJeff King1-1/+7
We test xmkstemp() in our helper by just calling: xmkstemp(xstrdup(argv[1])); This leaks both the copied string as well as the descriptor returned by the function. In practice this isn't a big deal, since we immediately exit the program, but: 1. LSan will complain about the memory leak. The only reason we did not notice this in our leak-checking builds is that both of the callers in the test suite (both in t0070) pass a broken template (and expect failure). So the function calls die() before we can actually leak. But it's an accident waiting to happen if anybody adds a call which succeeds. 2. Coverity complains about the descriptor leak. There's a long list of uninteresting or false positives in Coverity's results, but since we're here we might as well fix it, too. I didn't bother adding a new test that triggers the leak. It's not even in real production code, but just in the test-helper itself. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-18unit-test: ignore --no-chain-lintJeff King1-0/+1
In the same spirit as 9faf3963b6 (t: introduce compatibility options to clar-based tests, 2024-12-13), we should ignore --no-chain-lint passed to our clar tests, since it may appear in GIT_TEST_OPTS to be used with other tests. This is particularly important on Windows CI, where --no-chain-lint is added to the test options by default, and the meson build will pass all options to the unit tests. The only reason our meson Windows CI job does not run into this currently is that it is not respecting GIT_TEST_OPTS at all! So ignoring this option is a prerequisite to fixing that situation. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-18t: enable ASan's strict_string_checks optionJeff King1-0/+1
ASan has an option to enable strict string checking, where any pointer passed to a function that expects a NUL-terminated string will be checked for that NUL termination. This can sometimes produce false positives. E.g., it is not wrong to pass a buffer with { '1', '2', '\n' } into strtoul(). Even though it is not NUL-terminated, it will stop at the newline. But in trying it out, it identified two problematic spots in our test suite (which have now been adjusted): 1. The strtol() parsing in cache-tree.c was a real potential problem, which would have been very hard to find otherwise (since it required constructing a very specific broken index file). 2. The use of string functions in fsck_ident() were false positives, because we knew that there was always a trailing newline which would stop the functions from reading off the end of the buffer. But the reasoning behind that is somewhat fragile, and silencing those complaints made the code easier to reason about. So even though this did not find any earth-shattering bugs, and even had a few false positives, I'm sufficiently convinced that its complaints are more helpful than hurtful. Let's turn it on by default (since the test suite now runs cleanly with it) and see if it ever turns up any other instances. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-17merge-ort: fix failing merges in special corner caseElijah Newren1-0/+78
At GitHub, we had a repository that was triggering git: merge-ort.c:3032: process_renames: Assertion `newinfo && !newinfo->merged.clean` failed. during git replay. This sounds similar to the somewhat recent f6ecb603ff8a (merge-ort: fix directory rename on top of source of other rename/delete, 2025-08-06), but the cause is different. Unlike that case, there are no rename-to-self situations arising in this case, and new to this case it can only be triggered during a replay operation on the 2nd or later commit being replayed, never on the first merge in the sequence. To trigger, the repository needs: * an upstream which: * renames a file to a different directory, e.g. old/file -> new/file * leaves other files remaining in the original directory (so that e.g. "old/" still exists upstream even though file has been removed from it and placed elsewhere) * a topic branch being rebased where: * a commit in the sequence: * modifies old/file * a subsequent commit in the sequence being replayed: * does NOT touch *anything* under new/ * does NOT touch old/file * DOES modify other paths under old/ * does NOT have any relevant renames that we need to detect _anywhere_ elsewhere in the tree (meaning this interacts interestingly with both directory renames and cached renames) In such a case, the assertion will trigger. The fix turns out to be surprisingly simple. I have a very vague recollection that I actually considered whether to add such an if-check years ago when I added the very similar one for oldinfo in 1b6b902d95a5 (merge-ort: process_renames() now needs more defensiveness, 2021-01-19), but I think I couldn't figure out a possible way to trigger it and was worried at the time that if I didn't know how to trigger it then I wasn't so sure that simply skipping it was correct. Waiting did give me a chance to put more thorough tests and checks into place for the rename-to-self cases a few months back, which I might not have found as easily otherwise. Anyway, put the check in place now and add a test that demonstrates the fix. Note that this bug, as demonstrated by the conditions listed above, runs at the intersection of relevant renames, trivial directory resolutions, and cached renames. All three of those optimizations are ones that unfortunately make the code (and testcases!) a bit more complex, and threading all three makes it a bit more so. However, the testcase isn't crazy enough that I'd expect no one to ever hit it in practice, and was confused why we didn't see it before. After some digging, I discovered that merge.directoryRenames=false is a workaround to this bug, and GitHub used that setting until recently (it was a "temporary" match-what-libgit2-does piece of code that lasted years longer than intended). Since the conditions I gave above for triggering this bug rule out the possibility of there being directory renames, one might assume that it shouldn't matter whether you try to detect such renames if there aren't any. However, due to commit a16e8efe5c2b (merge-ort: fix merge.directoryRenames=false, 2025-03-13), the heavy hammer used there means that merge.directoryRenames=false ALSO turns off rename caching, which is critical to triggering the bug. This becomes a bit more than an aside since... Re-reading that old commit, a16e8efe5c2b (merge-ort: fix merge.directoryRenames=false, 2025-03-13), it appears that the solution to this latest bug might have been at least a partial alternative solution to that old commit. And it may have been an improved alternative (or at least help implement one), since it may be able to avoid the heavy-handed disabling of rename cache. That might be an interesting future thing to investigate, but is not critical for the current fix. However, since I spent time digging it all up, at least leave a small comment tweak breadcrumb to help some future reader (myself or others) who wants to dig further to connect the dots a little quicker. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-17t6429: update comment to mention correct toolElijah Newren1-8/+7
A comment at the top of t6429 mentions why the test doesn't exercise git rebase or git cherry-pick. However, it claims that it uses `test-tool fast-rebase`. That was true when the comment was written, but commit f920b0289ba3 (replay: introduce new builtin, 2023-11-24) changed it to use git replay without updating this comment. We could potentially just strike this second comment, since git replay is a bona fide built-in, but perhaps the explanation about why it focuses on git replay is still useful. Update the comment to make it accurate again. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-17blame: make diff algorithm configurableAntonin Delpeuch2-0/+204
The diff algorithm used in 'git-blame(1)' is set to 'myers', without the possibility to change it aside from the `--minimal` option. There has been long-standing interest in changing the default diff algorithm to "histogram", and Git 3.0 was floated as a possible occasion for taking some steps towards that: https://lore.kernel.org/git/xmqqed873vgn.fsf@gitster.g/ As a preparation for this move, it is worth making sure that the diff algorithm is configurable where useful. Make it configurable in the `git-blame(1)` command by introducing the `--diff-algorithm` option and make honor the `diff.algorithm` config variable. Keep Myers diff as the default. Signed-off-by: Antonin Delpeuch <antonin@delpeuch.eu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-16builtin/repo: fix table alignment for UTF-8 charactersJiang Xin1-0/+37
The output table from "git repo structure" is misaligned when displaying UTF-8 characters (e.g., non-ASCII glyphs). E.g.: | 仓库结构 | 值 | | -------------- | ---- | | * 引用 | | | * 计数 | 67 | The previous implementation used simple width formatting with printf() which didn't properly handle multi-byte UTF-8 characters, causing misaligned table columns when displaying repository structure information. This change modifies the stats_table_print_structure function to use strbuf_utf8_align() instead of basic printf width specifiers. This ensures proper column alignment regardless of the character encoding of the content being displayed. Also add test cases for strbuf_utf8_align(), a function newly introduced in "builtin/repo.c". Signed-off-by: Jiang Xin <worldhello.net@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-16t/unit-tests: add UTF-8 width tests for CJK charsJiang Xin2-0/+98
The file "builtin/repo.c" uses utf8_strwidth() to calculate the display width of UTF-8 characters in a table, but the resulting output is still misaligned. Add test cases for both utf8_strwidth and utf8_strnwidth to verify that they correctly compute the display width for UTF-8 characters. Also updated the build configuration in Makefile and meson.build to include the new test suite in the build process. Signed-off-by: Jiang Xin <worldhello.net@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-15read-cache: drop submodule check from add_to_cache()Jeff King1-0/+1
In add_to_cache(), we treat any directories as submodules, and complain if we can't resolve their HEAD. This call to resolve_gitlink_ref() was added by f937bc2f86 (add: error appropriately on repository with no commits, 2019-04-09), with the goal of improving the error message for empty repositories. But we already resolve the submodule HEAD in index_path(), which is where we find the actual oid we're going to use. Resolving it again here introduces some downsides: 1. It's more work, since we have to open up the submodule repository's files twice. 2. There are call paths that get to index_path() without going through add_to_cache(). For instance, we'd want a similar informative message if "git diff empty" finds that it can't resolve the submodule's HEAD. (In theory we can also get there through update-index, but AFAICT it refuses to consider directories as submodules at all, and just complains about them). 3. The resolution in index_path() catches more errors that we don't handle here. In particular, it will validate that the object format for the submodule matches that of the superproject. This isn't a bug, since our call in add_to_cache() throws away the oid it gets without looking at it. But it certainly caused confusion for me when looking at where the object-format check should go. So instead of resolving the submodule HEAD in add_to_cache(), let's just teach the call in index_path() to actually produce an error message (which it already does for other cases). That's probably what f937bc2f86 should have done in the first place, and it gives us a single point of resolution when adding a submodule to the index. The resulting output is slightly more verbose, as we propagate the error up the call stack, but I think that's OK (and again, matches many other errors we get when indexing fails). I've left the text of the error message as-is, though it is perhaps overly specific. There are many reasons that resolving the submodule HEAD might fail, though outside of corruption or system errors it is probably most likely that the submodule HEAD is simply on an unborn branch. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-15object-file: disallow adding submodules of different hash algobrian m. carlson2-0/+50
The design of the hash algorithm transition plan is that objects stored must be entirely in one algorithm since we lack any way to indicate a mix of algorithms. This also includes submodules, but we have traditionally not enforced this, which leads to various problems when trying to clone or check out the the submodule from the remote. Since this cannot work in the general case, restrict adding a submodule of a different algorithm to the index. Add tests for git add and git submodule add that these are rejected. Note that we cannot check this in git fsck because the malformed submodule is stored in the tree as an object ID which is either truncated (when a SHA-256 submodule is added to a SHA-1 repository) or padded with zeros (when a SHA-1 submodule is added to a SHA-256 repository). We cannot detect even the latter case because someone could have an actual submodule that actually ends in 24 zeros, which would be a false positive. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-12diff: highlight and error out on incomplete linesJunio C Hamano1-4/+63
Teach "git diff" to highlight "\ No newline at end of file" message as a whitespace error when incomplete-line whitespace error class is in effect. Thanks to the previous refactoring of complete rewrite code path, we can do this at a single place. Unlike whitespace errors in the payload where we need to annotate in line, possibly using colors, the line that has whitespace problems, we have a dedicated line already that can serve as the error message, so paint it as a whitespace error message. Also teach "git diff --check" to notice incomplete lines as whitespace errors and report when incomplete-line whitespace error class is in effect. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-12apply: check and fix incomplete linesJunio C Hamano1-0/+187
The final line of a file that lacks the terminating newline at its end is called an incomplete line. In general they are frowned upon for many reasons (imagine concatenating two files with "cat A B" and what happens when A ends in an incomplete line, for example), and text-oriented tools often mishandle such a line. Implement checks in "git apply" for incomplete lines, which is off by default for backward compatibility's sake, so that "git apply --whitespace={fix,warn,error}" can notice, warn against, and fix them. As one of the new test shows, if you modify contents on an incomplete line in the original and leave the resulting line incomplete, it is still considered a whitespace error, the reasoning being that "you'd better fix it while at it if you are making a change on an incomplete line anyway", which may controversial. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-12Merge branch 'tc/last-modified-active-paths-optimization'Junio C Hamano1-1/+1
"git last-modified" was optimized by narrowing the set of paths to follow as it dug deeper in the history. * tc/last-modified-active-paths-optimization: last-modified: implement faster algorithm
2025-11-12attr: avoid recursion when expanding attribute macrosJeff King1-0/+20
Given a set of attribute macros like: [attr]a1 a2 [attr]a2 a3 ... [attr]a300000 -text file a1 expanding the attributes for "file" requires expanding "a1" to "a2", "a2" to "a3", and so on until hitting a non-macro expansion ("-text", in this case). We implement this via recursion: fill_one() calls macroexpand_one(), which then recurses back to fill_one(). As a result, very deep macro chains like the one above can run out of stack space and cause us to segfault. The required stack space is fairly small; I needed on the order of 200,000 entries to get a segfault on Linux. So it's unlikely anybody would hit this accidentally, leaving only malicious inputs. There you can easily construct a repo which will segfault on clone (we look at attributes during the checkout step, but you'd see the same trying to do other operations, like diff in a bare repo). It's mostly harmless, since anybody constructing such a repo is only preventing victims from cloning their evil garbage, but it could be a nuisance for hosting sites. One option to prevent this is to limit the depth of recursion we'll allow. This is conceptually easy to implement, but it raises other questions: what should the limit be, and do we need a configuration knob for it? The recursion here is simple enough that we can avoid those questions by just converting it to iteration instead. Rather than iterate over the states of a match_attr in fill_one(), we'll put them all in a queue, and the expansion of each can add to the queue rather than recursing. Note that this is a LIFO queue in order to keep the same depth-first order we did with the recursive implementation. I've avoided using the word "stack" in the code because the term is already heavily used to refer to the stack of .gitattribute files that matches the tree structure of the repository. The test uses a limited stack size so we can trigger the problem with a much smaller input than the one shown above. The value here (3000) is enough to trigger the issue on my x86_64 Linux machine. Reported-by: Ben Stav <benstav@miggo.io> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-10diff: disable rename detection with --quietRené Scharfe1-0/+10
Detecting renames and copies improves diff's output. This effort is wasted if we don't show any. Disable detection in that case. This actually fixes the error code when using the options --cached, --find-copies-harder, --no-ext-diff and --quiet together: run_diff_index() indirectly calls diff-lib.c::show_modified(), which queues even non-modified entries using diff_change() because we need them for copy detection. diff_change() sets flags.has_changes, though, which causes diff_can_quit_early() to declare we're done after seeing only the very first entry -- way too soon. Using --cached, --find-copies-harder and --quiet together without --no-ext-diff was not affected even before, as it causes the flag flags.diff_from_contents to be set, which disables the optimization in a different way. Reported-by: D. Ben Knoble <ben.knoble@gmail.com> Suggested-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-10maintenance: add 'is-needed' subcommandKarthik Nayak1-16/+38
The 'git-maintenance(1)' command provides tooling to run maintenance tasks over Git repositories. The 'run' subcommand, as the name suggests, runs the maintenance tasks. When used with the '--auto' flag, it uses heuristics to determine if the required thresholds are met for running said maintenance tasks. There is however a lack of insight into these heuristics. Meaning, the checks are linked to the execution. Add a new 'is-needed' subcommand to 'git-maintenance(1)' which allows users to simply check if it is needed to run maintenance without performing it. This subcommand can check if it is needed to run maintenance without actually running it. Ideally it should be used with the '--auto' flag, which would allow users to check if the thresholds required are met. The subcommand also supports the '--task' flag which can be used to check specific maintenance tasks. While adding the respective tests in 't/t7900-maintenance.sh', remove a duplicate of the test: 'worktree-prune task with --auto honors maintenance.worktree-prune.auto'. Signed-off-by: Karthik Nayak <karthik.188@gmail.com> Acked-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-10reftable/stack: add function to check if optimization is requiredKarthik Nayak1-2/+10
The reftable backend performs auto-compaction as part of its regular flow, which is required to keep the number of tables part of a stack at bay. This allows it to stay optimized. Compaction can also be triggered voluntarily by the user via the 'git pack-refs' or the 'git refs optimize' command. However, currently there is no way for the user to check if optimization is required without actually performing it. Extract out the heuristics logic from 'reftable_stack_auto_compact()' into an internal function 'update_segment_if_compaction_required()'. Then use this to add and expose `reftable_stack_compaction_required()` which will allow users to check if the reftable backend can be optimized. Signed-off-by: Karthik Nayak <karthik.188@gmail.com> Acked-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-06Merge branch 'cc/fast-import-export-i18n-cleanup'Junio C Hamano1-10/+10
Messages from fast-import/export are now marked for i18n. * cc/fast-import-export-i18n-cleanup: gpg-interface: mark a string for translation fast-import: mark strings for translation fast-export: mark strings for translation gpg-interface: use left shift to define GPG_VERIFY_* gpg-interface: simplify ssh fingerprint parsing
2025-11-05Merge branch 'rz/t0450-bisect-doc-update'Junio C Hamano1-1/+0
The help text and manual page of "git bisect" command have been made consistent with each other. * rz/t0450-bisect-doc-update: bisect: update usage and docs to match each other
2025-11-05replay: add replay.refAction config optionSiddharth Asthana1-0/+46
Add a configuration variable to control the default behavior of git replay for updating references. This allows users who prefer the traditional pipeline output to set it once in their config instead of passing --ref-action=print with every command. The config variable uses string values that mirror the behavior modes: * replay.refAction = update (default): atomic ref updates * replay.refAction = print: output commands for pipeline Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Elijah Newren <newren@gmail.com> Helped-by: Christian Couder <christian.couder@gmail.com> Helped-by: Phillip Wood <phillip.wood123@gmail.com> Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-05replay: make atomic ref updates the default behaviorSiddharth Asthana1-8/+59
The git replay command currently outputs update commands that can be piped to update-ref to achieve a rebase, e.g. git replay --onto main topic1..topic2 | git update-ref --stdin This separation had advantages for three special cases: * it made testing easy (when state isn't modified from one step to the next, you don't need to make temporary branches or have undo commands, or try to track the changes) * it provided a natural can-it-rebase-cleanly (and what would it rebase to) capability without automatically updating refs, similar to a --dry-run * it provided a natural low-level tool for the suite of hash-object, mktree, commit-tree, mktag, merge-tree, and update-ref, allowing users to have another building block for experimentation and making new tools However, it should be noted that all three of these are somewhat special cases; users, whether on the client or server side, would almost certainly find it more ergonomic to simply have the updating of refs be the default. For server-side operations in particular, the pipeline architecture creates process coordination overhead. Server implementations that need to perform rebases atomically must maintain additional code to: 1. Spawn and manage a pipeline between git-replay and git-update-ref 2. Coordinate stdout/stderr streams across the pipe boundary 3. Handle partial failure states if the pipeline breaks mid-execution 4. Parse and validate the update-ref command output Change the default behavior to update refs directly, and atomically (at least to the extent supported by the refs backend in use). This eliminates the process coordination overhead for the common case. For users needing the traditional pipeline workflow, add a new --ref-action=<mode> option that preserves the original behavior: git replay --ref-action=print --onto main topic1..topic2 | git update-ref --stdin The mode can be: * update (default): Update refs directly using an atomic transaction * print: Output update-ref commands for pipeline use Test suite changes: All existing tests that expected command output now use --ref-action=print to preserve their original behavior. This keeps the tests valid while allowing them to verify that the pipeline workflow still works correctly. New tests were added to verify: - Default atomic behavior (no output, refs updated directly) - Bare repository support (server-side use case) - Equivalence between traditional pipeline and atomic updates - Real atomicity using a lock file to verify all-or-nothing guarantee - Test isolation using test_when_finished to clean up state - Reflog messages include replay mode and target A following commit will add a replay.refAction configuration option for users who prefer the traditional pipeline output as their default behavior. Helped-by: Elijah Newren <newren@gmail.com> Helped-by: Patrick Steinhardt <ps@pks.im> Helped-by: Christian Couder <christian.couder@gmail.com> Helped-by: Phillip Wood <phillip.wood123@gmail.com> Signed-off-by: Siddharth Asthana <siddharthasthana31@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-04Merge branch 'jk/doc-backslash-in-exclude'Junio C Hamano1-0/+2
The patterns used in the .gitignore files use backslash in the way documented for fnmatch(3); document as such to reduce confusion. * jk/doc-backslash-in-exclude: doc: document backslash in gitignore patterns
2025-11-04Merge branch 'jk/test-delete-gpgsig-leakfix'Junio C Hamano1-3/+4
Leakfix. * jk/test-delete-gpgsig-leakfix: test-tool: fix leak in delete-gpgsig command
2025-11-04Merge branch 'eb/t1016-hash-transition-fix'Junio C Hamano2-1/+7
Test fix. * eb/t1016-hash-transition-fix: t1016-compatObjectFormat: really freeze time for reproduciblity
2025-11-04Merge branch 'tz/test-prepare-gnupghome'Junio C Hamano1-0/+1
Tests did not set up GNUPGHOME correctly, which is fixed but some flaky tests are exposed in t1016, which needs to be addressed before this topic can move forward. * tz/test-prepare-gnupghome: t/lib-gpg: call prepare_gnupghome() in GPG2 prereq t/lib-gpg: add prepare_gnupghome() to create GNUPGHOME dir
2025-11-04Merge branch 'jt/repo-structure'Junio C Hamano2-0/+130
"git repo structure", a new command. * jt/repo-structure: builtin/repo: add progress meter for structure stats builtin/repo: add keyvalue and nul format for structure stats builtin/repo: add object counts in structure output builtin/repo: introduce structure subcommand ref-filter: export ref_kind_from_refname() ref-filter: allow NULL filter pattern builtin/repo: rename repo_info() to cmd_repo_info()
2025-11-04Merge branch 'kn/refs-optim-cleanup' into kn/maintenance-is-neededJunio C Hamano3-2/+4
* kn/refs-optim-cleanup: t/pack-refs-tests: move the 'test_done' to callees refs: rename 'pack_refs_opts' to 'refs_optimize_opts' refs: move to using the '.optimize' functions
2025-11-04Merge branch 'ps/ref-peeled-tags' into kn/maintenance-is-neededJunio C Hamano8-23/+236
* ps/ref-peeled-tags: (23 commits) t7004: do not chdir around in the main process ref-filter: fix stale parsed objects ref-filter: parse objects on demand ref-filter: detect broken tags when dereferencing them refs: don't store peeled object IDs for invalid tags object: add flag to `peel_object()` to verify object type refs: drop infrastructure to peel via iterators refs: drop `current_ref_iter` hack builtin/show-ref: convert to use `reference_get_peeled_oid()` ref-filter: propagate peeled object ID upload-pack: convert to use `reference_get_peeled_oid()` refs: expose peeled object ID via the iterator refs: refactor reference status flags refs: fully reset `struct ref_iterator::ref` on iteration refs: introduce `.ref` field for the base iterator refs: introduce wrapper struct for `each_ref_fn` builtin/repo: add progress meter for structure stats builtin/repo: add keyvalue and nul format for structure stats builtin/repo: add object counts in structure output builtin/repo: introduce structure subcommand ...
2025-11-04t/pack-refs-tests: move the 'test_done' to calleesKarthik Nayak3-2/+4
In ac0bad0af4 (t0601: refactor tests to be shareable, 2025-09-19), we refactored 't/t0601-reffiles-pack-refs.sh' to move all of the tests to 't/pack-refs-tests.sh', which became a common test suite which was also used by 't/t1463-refs-optimize.sh'. This also moved the 'test_done' directive to 't/pack-refs-tests.sh'. Which inhibits additional tests from being added to either of the tests. Let's move the directive out to both the tests, so that we can add additional specific tests to them. Also the test flow logic shouldn't be part of tests which can be embedded in other test scripts. Signed-off-by: Karthik Nayak <karthik.188@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-04t7004: do not chdir around in the main processJunio C Hamano1-18/+20
Move down to no-contains subdirectory inside a subshell, just like the previous step that created and used it does. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-04ref-filter: fix stale parsed objectsPatrick Steinhardt1-0/+20
In 054f5f457e (ref-filter: parse objects on demand, 2025-10-23) we have started to skip parsing some objects in case we don't need to access their values in the first place. This was done by introducing a new member `struct expand_data::maybe_object` that gets populated on demand via `get_or_parse_object()`. This has led to a regression though where the object now gets reused because we don't reset it properly. The `oi` structure is declared in global scope, and there is no single place where we reset it before invoking `get_object()`. The consequence is that the `maybe_object` member doesn't get reset across calls, so subsequent calls will end up reusing the same object. This is only an issue for a subset of retrieved values, as not all of the infrastructure ends up calling `get_or_parse_object()`. So the effect is limited, which is probably why the issue wasn't detected earlier. Fix the issue by resetting `maybe_object` in `get_object()`. Reported-by: Junio C Hamano <gitster@pobox.com> Based-on-patch-by: Jeff King <peff@peff.net> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-04ref-filter: detect broken tags when dereferencing themPatrick Steinhardt1-1/+3
Users can ask git-for-each-ref(1) to peel tags and return information of the tagged object by adding an asterisk to the format, like for example "%(*$objectname)". If so, git-for-each-ref(1) peels that object to the first non-tag object and then returns its values. As mentioned in preceding commits, it can happen that the tagged object type and the claimed object type differ, effectively resulting in a corrupt tag. git-for-each-ref(1) would notice this mismatch, print an error and then bail out when trying to peel the tag. But we only notice this corruption in some very specific edge cases! While we have a test in "t/for-each-ref-tests.sh" that verifies the above scenario, this test is specifically crafted to detect the issue at hand. Namely, we create two tags: - One tag points to a specific object with the correct type. - The other tag points to the *same* object with a different type. The fact that both tags point to the same object is important here: `peel_object()` wouldn't notice the corruption if the tagged objects were different. The root cause is that `peel_object()` calls `lookup_${type}()` eventually, where the type is the same type declared in the tag object. Consequently, when we have two tags pointing to the same object but with different declared types we'll call two different lookup functions. The first lookup will store the object with an unverified type A, whereas the second lookup will try to look up the object with a different unverified type B. And it is only now that we notice the discrepancy in object types, even though type A could've already been the wrong type. Fix the issue by verifying the object type in `populate_value()`. With this change we'll also notice type mismatches when only dereferencing a tag once. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-04refs: don't store peeled object IDs for invalid tagsPatrick Steinhardt2-0/+60
Both the "files" and "reftable" backend store peeled object IDs for references that point to tags: - The "files" backend stores the value when packing refs, where each peeled object ID is prefixed with "^". - The "reftable" backend stores the value whenever writing a new reference that points to a tag via a special ref record type. Both of these backends use `peel_object()` to find the peeled object ID. But as explained in the preceding commit, that function does not detect the case where the tag's tagged object and its claimed type mismatch. The consequence of storing these bogus peeled object IDs is that we're less likely to detect such corruption in other parts of Git. git-for-each-ref(1) for example does not notice anymore that the tag is broken when using "--format=%(*objectname)" to dereference tags. One could claim that this is good, because it still allows us to mostly use the tag as intended. But the biggest problem here is that we now have different behaviour for such a broken tag depending on whether or not we have its peeled value in the refdb. Fix the issue by verifying the object type when peeling the object. If that verification fails we simply skip storing the peeled value in either of the reference formats. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-04object: add flag to `peel_object()` to verify object typePatrick Steinhardt1-1/+1
When peeling a tag to a non-tag object we repeatedly call `parse_object()` on the tagged object until we find the first object that isn't a tag. While this feels sensible at first, there is a big catch here: `parse_object()` doesn't actually verify the type of the tagged object. The relevant code path here eventually ends up in `parse_tag_buffer()`. Here, we parse the various fields of the tag, including the "type". Once we've figured out the type and the tagged object ID, we call one of the `lookup_${type}()` functions for whatever type we have found. There is two possible outcomes in the successful case: 1. The object is already part of our cached objects. In that case we double-check whether the type we're trying to look up matches the type that was cached. 2. The object is _not_ part of our cached objects. In that case, we simply create a new object with the expected type, but we don't parse that object. In the first case we might notice type mismatches, but only in the case where our cache has the object with the correct type. In the second case, we'll blindly assume that the type is correct and then go with it. We'll only notice that the type might be wrong when we try to parse the object at a later point. Now arguably, we could change `parse_tag_buffer()` to verify the tagged object's type for us. But that would have the effect that such a tag cannot be parsed at all anymore, and we have a small bunch of tests for exactly this case that assert we still can open such tags. So this change does not feel like something we can retroactively tighten, even though one shouldn't ever hit such corrupted tags. Instead, add a new `flags` field to `peel_object()` that allows the caller to opt in to strict object verification. This will be wired up at a subset of callsites over the next few commits. Note that this change also inlines `deref_tag_noverify()`. There's only been two callsites of that function, the one we're changing and one in our test helpers. The latter callsite can trivially use `deref_tag()` instead, so by inlining the function we avoid having to pass down the flag. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-04refs: introduce wrapper struct for `each_ref_fn`Patrick Steinhardt1-3/+2
The `each_ref_fn` callback function type is used across our code base for several different functions that iterate through reference. There's a bunch of callbacks implementing this type, which makes any changes to the callback signature extremely noisy. An example of the required churn is e8207717f1 (refs: add referent to each_ref_fn, 2024-08-09): adding a single argument required us to change 48 files. It was already proposed back then [1] that we might want to introduce a wrapper structure to alleviate the pain going forward. While this of course requires the same kind of global refactoring as just introducing a new parameter, it at least allows us to more change the callback type afterwards by just extending the wrapper structure. One counterargument to this refactoring is that it makes the structure more opaque. While it is obvious which callsites need to be fixed up when we change the function type, it's not obvious anymore once we use a structure. That being said, we only have a handful of sites that actually need to populate this wrapper structure: our ref backends, "refs/iterator.c" as well as very few sites that invoke the iterator callback functions directly. Introduce this wrapper structure so that we can adapt the iterator interfaces more readily. [1]: <ZmarVcF5JjsZx0dl@tanuki> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-03last-modified: implement faster algorithmToon Claes1-1/+1
The current implementation of git-last-modified(1) works by doing a revision walk, and inspecting the diff at each level of that walk to annotate entries remaining in the hashmap of paths. In other words, if the diff at some level touches a path which has not yet been associated with a commit, then that commit becomes associated with the path. While a perfectly reasonable implementation, it can perform poorly in either one of two scenarios: 1. There are many entries of interest, in which case there is simply a lot of work to do. 2. Or, there are (even a few) entries which have not been updated in a long time, and so we must walk through a lot of history in order to find a commit that touches that path. This patch rewrites the last-modified implementation that addresses the second point. The idea behind the algorithm is to propagate a set of 'active' paths (a path is 'active' if it does not yet belong to a commit) up to parents and do a truncated revision walk. The walk is truncated because it does not produce a revision for every change in the original pathspec, but rather only for active paths. More specifically, consider a priority queue of commits sorted by generation number. First, enqueue the set of boundary commits with all paths in the original spec marked as interesting. Then, while the queue is not empty, do the following: 1. Pop an element, say, 'c', off of the queue, making sure that 'c' isn't reachable by anything in the '--not' set. 2. For each parent 'p' (with index 'parent_i') of 'c', do the following: a. Compute the diff between 'c' and 'p'. b. Pass any active paths that are TREESAME from 'c' to 'p'. c. If 'p' has any active paths, push it onto the queue. 3. Any path that remains active on 'c' is associated to that commit. This ends up being equivalent to doing something like 'git log -1 -- $path' for each path simultaneously. But, it allows us to go much faster than the original implementation by limiting the number of diffs we compute, since we can avoid parts of history that would have been considered by the revision walk in the original implementation, but are known to be uninteresting to us because we have already marked all paths in that area to be inactive. To avoid computing many first-parent diffs, add another trick on top of this and check if all paths active in 'c' are DEFINITELY NOT in c's Bloom filter. Since the commit-graph only stores first-parent diffs in the Bloom filters, we can only apply this trick to first-parent diffs. Comparing the performance of this new algorithm shows about a 2.5x improvement on git.git: Benchmark 1: master no bloom Time (mean ± σ): 2.868 s ± 0.023 s [User: 2.811 s, System: 0.051 s] Range (min … max): 2.847 s … 2.926 s 10 runs Benchmark 2: master with bloom Time (mean ± σ): 949.9 ms ± 15.2 ms [User: 907.6 ms, System: 39.5 ms] Range (min … max): 933.3 ms … 971.2 ms 10 runs Benchmark 3: HEAD no bloom Time (mean ± σ): 782.0 ms ± 6.3 ms [User: 740.7 ms, System: 39.2 ms] Range (min … max): 776.4 ms … 798.2 ms 10 runs Benchmark 4: HEAD with bloom Time (mean ± σ): 307.1 ms ± 1.7 ms [User: 276.4 ms, System: 29.9 ms] Range (min … max): 303.7 ms … 309.5 ms 10 runs Summary HEAD with bloom ran 2.55 ± 0.02 times faster than HEAD no bloom 3.09 ± 0.05 times faster than master with bloom 9.34 ± 0.09 times faster than master no bloom In short, the existing implementation is comparably fast *with* Bloom filters as the new implementation is *without* Bloom filters. So, most repositories should get a dramatic speed-up by just deploying this (even without computing Bloom filters), and all repositories should get faster still when computing Bloom filters. When comparing a more extreme example of `git last-modified -- COPYING t`, the difference is even 5 times better: Benchmark 1: master Time (mean ± σ): 4.372 s ± 0.057 s [User: 4.286 s, System: 0.062 s] Range (min … max): 4.308 s … 4.509 s 10 runs Benchmark 2: HEAD Time (mean ± σ): 826.3 ms ± 22.3 ms [User: 784.1 ms, System: 39.2 ms] Range (min … max): 810.6 ms … 881.2 ms 10 runs Summary HEAD ran 5.29 ± 0.16 times faster than master As an added benefit, results are more consistent now. For example implementation in 'master' gives: $ git log --max-count=1 --format=%H -- pkt-line.h 15df15fe07ef66b51302bb77e393f3c5502629de $ git last-modified -- pkt-line.h 15df15fe07ef66b51302bb77e393f3c5502629de pkt-line.h $ git last-modified | grep pkt-line.h 5b49c1af03e600c286f63d9d9c9fb01403230b9f pkt-line.h With the changes in this patch the results of git-last-modified(1) always match those of `git log --max-count=1`. One thing to note though, the results might be outputted in a different order than before. This is not considerd to be an issue because nowhere is documented the order is guaranteed. Based-on-patches-by: Derrick Stolee <stolee@gmail.com> Based-on-patches-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Toon Claes <toon@iotcl.com> Acked-by: Taylor Blau <me@ttaylorr.com> [jc: tweaked use of xcalloc() to unbreak coccicheck] Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-11-03Merge branch 'rs/merge-base-optim'Junio C Hamano1-0/+101
The code to walk revision graph to compute merge base has been optimized. * rs/merge-base-optim: commit-reach: avoid commit_list_insert_by_date()
2025-11-03Merge branch 'jk/diff-patch-dry-run-cleanup'Junio C Hamano1-0/+10
Finishing touches to fixes to the recent regression in "git diff -w --quiet" and anything that needs to internally generate patch to see if it turns empty. * jk/diff-patch-dry-run-cleanup: diff: simplify run_external_diff() quiet logic diff: drop dry-run redirection to /dev/null diff: replace diff_options.dry_run flag with NULL file diff: drop save/restore of color_moved in dry-run mode diff: send external diff output to diff_options.file
2025-11-03Merge branch 'ps/maintenance-geometric'Junio C Hamano1-0/+245
"git maintenance" command learns the "geometric" strategy where it avoids doing maintenance tasks that rebuilds everything from scratch. * ps/maintenance-geometric: t7900: fix a flaky test due to git-repack always regenerating MIDX builtin/maintenance: introduce "geometric" strategy builtin/maintenance: make "gc" strategy accessible builtin/maintenance: extend "maintenance.strategy" to manual maintenance builtin/maintenance: run maintenance tasks depending on type builtin/maintenance: improve readability of strategies builtin/maintenance: don't silently ignore invalid strategy builtin/maintenance: make the geometric factor configurable builtin/maintenance: introduce "geometric-repack" task builtin/gc: make `too_many_loose_objects()` reusable without GC config builtin/gc: remove global `repack` variable
2025-11-03Merge branch 'jk/match-pathname-fix'Junio C Hamano1-0/+11
The wildmatch code had a corner case bug that mistakenly makes "foo**/bar" match with "foobar", which has been corrected. * jk/match-pathname-fix: match_pathname(): give fnmatch one char of prefix context match_pathname(): reorder prefix-match check
2025-11-03Merge branch 'rs/add-patch-quit'Junio C Hamano1-0/+11
The 'q'(uit) command in "git add -p" has been improved to quit without doing any meaningless work before leaving, and giving EOF (typically control-D) to the prompt is made to behave the same way. * rs/add-patch-quit: add-patch: quit on EOF add-patch: quit without skipping undecided hunks
2025-10-30Merge branch 'ly/diff-name-only-with-diff-from-content'Junio C Hamano1-0/+37
Regression fixes for a topic that has already been merged. * ly/diff-name-only-with-diff-from-content: diff: stop output garbled message in dry run mode
2025-10-30Merge branch 'ps/remove-packfile-store-get-packs'Junio C Hamano2-2/+3
Two slightly different ways to get at "all the packfiles" in API has been cleaned up. * ps/remove-packfile-store-get-packs: packfile: rename `packfile_store_get_all_packs()` packfile: introduce macro to iterate through packs packfile: drop `packfile_store_get_packs()` builtin/grep: simplify how we preload packs builtin/gc: convert to use `packfile_store_get_all_packs()` object-name: convert to use `packfile_store_get_all_packs()`
2025-10-30Merge branch 'ps/symlink-symref-deprecation'Junio C Hamano1-3/+23
"Symlink symref" has been added to the list of things that will disappear at Git 3.0 boundary. * ps/symlink-symref-deprecation: refs/files: deprecate writing symrefs as symbolic links
2025-10-30Merge branch 'ey/commit-graph-changed-paths-config'Junio C Hamano1-0/+44
A new configuration variable commitGraph.changedPaths allows to turn "--changed-paths" on by default for "git commit-graph". * ey/commit-graph-changed-paths-config: commit-graph: add new config for changed-paths & recommend it in scalar
2025-10-30fast-import: mark strings for translationChristian Couder1-10/+10
Some error or warning messages in "builtin/fast-import.c" are marked for translation, but many are not. To be more consistent and provide a better experience to people using a translated version, let's mark all the remaining error or warning messages for translation. While at it, let's make the following small changes: - replace "GIT" or "git" in a few error messages to just "Git", - replace "Expected from command, got %s" to "expected 'from' command, got '%s'", which makes it clearer that "from" is a command and should not be translated, - downcase error and warning messages that start with an uppercase, - fix test cases in "t9300-fast-import.sh" that broke because an error or warning message was downcased, - split error and warning messages that are too long, - adjust the indentation of some arguments of the error functions. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-29test-tool: fix leak in delete-gpgsig commandJeff King1-3/+4
We read the input into a strbuf, so we must free it. Without this, t1016 complains in SANITIZE=leak mode. The bug was introduced in 7673ecd2dc (t1016-compatObjectFormat: add tests to verify the conversion between objects, 2023-10-01). But nobody seems to have noticed, probably because CI did not run these tests until the fix in 6cd8369ef3 (t/lib-gpg: call prepare_gnupghome() in GPG2 prereq, 2024-07-03). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-29doc: document backslash in gitignore patternsJeff King1-0/+2
Because gitignore patterns are passed to fnmatch, the handling of backslashes is the same as it is there: it can be used to escape metacharacters. We do reference fnmatch(3) for more details, but it may be friendlier to point out this implication explicitly (especially for people who want to know about backslash handling and search the documentation for that word). There are also two cases that I've seen some other backslash-escaping systems handle differently, so let's describe those: 1. A backslash before any character treats that character literally, even if it's not otherwise a meta-character. As opposed to including the backslash itself (like "foo\bar" in shell expands to "foo\bar") or forbidding it ("foo\zar" is required to produce a diagnostic in C). 2. A backslash at the end of the string is an invalid pattern (and not a literal backslash). This second one in particular was a point of confusion between our implementation and the one in JGit. Our wildmatch behavior matches what POSIX specifies for fnmatch, so the code and documentation are in line. But let's add a test to cover this case. Note that the behavior here differs between wildmatch itself (which is what gitignore will use) and pathspec matching (which will only turn to wildmatch if a literal match fails). So we match "foo\" to "foo\" in pathspecs, but not via gitignore. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-28t1016-compatObjectFormat: really freeze time for reproduciblityEric W. Biederman2-1/+7
The strategy in t1016-compatObjectFormat is to build two trees with identical commits, one tree encoded in sha1 the other tree encoded in sha256 and to use the compatibility code to test and see if the two trees are identical. GPG signatures include the current time as part of the signature. To make gpg deterministic I forced the use of gpg --faked-system-time. Unfortunately I did not look closely enough. By default gpg still allows time to move forward with --faked-system-time. So in those rare instances when the system is heavily loaded and gpg runs slower than other times, signatures over the exact same data differ due to timestamps with a minuscule difference. Reading through the gpg documentation with a close eye, time can be frozen by including an exclamation point at the end of the argument to --faked-system-time. Add the exclamation point so gpg really runs with a fixed notion of time, resulting in the exact same data having identical gpg signatures. That is enough that I can run "t1016-compatObjectFormat.sh --stress" and I don't see any failures. It is possible a future change to gpg will make replay protection more robust and not provide a way to allow two separate runs of gpg to produce exactly the same signature for exactly the same data. If that happens a deeper comparison of the two repositories will need to be performed. A comparison that simply verifies the signatures and compares the data for equality. For now that is a lot of work for no gain so I am just documenting the possibility. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-28bisect: update usage and docs to match each otherRuoyu Zhong1-1/+0
Update the usage string of `git bisect` and documentation to match each other. While at it, also: 1. Move the synopsis of `git bisect` subcommands to the synopsis section, so that the test `t0450-txt-doc-vs-help.sh` can pass. 2. Document the `git bisect next` subcommand, which exists in the code but is missing from the documentation. See also: [1]. [1]: https://lore.kernel.org/git/3DA38465-7636-4EEF-B074-53E4628F5355@gmail.com/ Suggested-by: Ben Knoble <ben.knoble@gmail.com> Signed-off-by: Ruoyu Zhong <zhongruoyu@outlook.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-28Merge branch 'cc/fast-import-strip-signed-tags'Junio C Hamano4-8/+145
"git fast-import" is taught to handle signed tags, just like it recently learned to handle signed commits, in different ways. * cc/fast-import-strip-signed-tags: fast-import: add '--signed-tags=<mode>' option fast-export: handle all kinds of tag signatures t9350: properly count annotated tags lib-gpg: allow tests with GPGSM or GPGSSH prereq first doc: git-tag: stop focusing on GPG signed tags
2025-10-28Merge branch 'ds/sparse-checkout-clean'Junio C Hamano1-0/+175
"git sparse-checkout" subcommand learned a new "clean" action to prune otherwise unused working-tree files that are outside the areas of interest. * ds/sparse-checkout-clean: sparse-index: improve advice message instructions t: expand tests around sparse merges and clean sparse-index: point users to new 'clean' action sparse-checkout: add --verbose option to 'clean' dir: add generic "walk all files" helper sparse-checkout: match some 'clean' behavior sparse-checkout: add basics of 'clean' command sparse-checkout: remove use of the_repository
2025-10-27t7900: fix a flaky test due to git-repack always regenerating MIDXPatrick Steinhardt1-2/+2
When a supposedly no-op "git repack" runs across a second boundary, because the command always touches the MIDX file and updates its timestamp, "ls -l $GIT_DIR/objects/pack/" before and after the operation can change, which causes such a test to fail. Only compare the *.pack files in the directory before and after the operation to work around this flakyness. Arguably, git-repack(1) should learn to not rewrite the MIDX in case we know it is already up-to-date. But this is not a new problem introduced via the new geometric maintenance task, so for now it should be good enough to paper over the issue. Signed-off-by: Patrick Steinhardt <ps@pks.im> [jc: taken from diff to v4 from v3 that was already merged to 'next'] Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-26Merge branch 'so/t2401-use-test-path-helpers' into maint-2.51Junio C Hamano1-17/+17
Test modernization. * so/t2401-use-test-path-helpers: t2401: update path checks using test_path helpers
2025-10-26Merge branch 'ps/t7528-ssh-agent-uds-workaround' into maint-2.51Junio C Hamano1-1/+1
Recent OpenSSH creates the Unix domain socket to communicate with ssh-agent under $HOME instead of /tmp, which causes our test to fail doe to overly long pathname in our test environment, which has been worked around by using "ssh-agent -T". * ps/t7528-ssh-agent-uds-workaround: t7528: work around ETOOMANY in OpenSSH 10.1 and newer
2025-10-26Merge branch 'jk/status-z-short-fix' into maint-2.51Junio C Hamano1-0/+11
The "--short" option of "git status" that meant output for humans and "-z" option to show NUL delimited output format did not mix well, and colored some but not all things. The command has been updated to color all elements consistently in such a case. * jk/status-z-short-fix: status: make coloring of "-z --short" consistent
2025-10-26Merge branch 'jk/diff-no-index-with-pathspec-fix' into maint-2.51Junio C Hamano1-0/+16
An earlier addition to "git diff --no-index A B" to limit the output with pathspec after the two directories misbehaved when these directories were given with a trailing slash, which has been corrected. * jk/diff-no-index-with-pathspec-fix: diff --no-index: fix logic for paths ending in '/'
2025-10-26Merge branch 'jk/diff-from-contents-fix' into maint-2.51Junio C Hamano1-0/+4
Recently we attempted to improve "git diff -w" and friends to handle cases where patch output would be suppressed, but it introduced a bug that emits unnecessary output, which has been corrected. * jk/diff-from-contents-fix: diff: restore redirection to /dev/null for diff_from_contents
2025-10-26add-patch: quit on EOFRené Scharfe1-0/+11
If we reach the end of the input, e.g. because the user pressed ctrl-D on Linux, there is no point in showing any more prompts, as we won't get any reply. Do the same as option 'q' would: Quit. Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-26match_pathname(): give fnmatch one char of prefix contextJeff King1-0/+11
In match_pathname(), which we use for matching .gitignore and .gitattribute patterns, we are comparing paths with fnmatch patterns (actually our extended wildmatch, which will be important). There's an extra optimization there: we pre-compute the number of non-wildcard characters at the beginning of the pattern and do an fspathncmp() on that prefix. That lets us avoid fnmatch entirely on patterns without wildcards, and shrinks the amount of work we hand off to fnmatch. For a pattern like "foo*.txt" and a path "foobar.txt", we'd cut away the matching "foo" prefix and just pass "*.txt" and "bar.txt" to fnmatch(). But this misses a subtle corner case. In fnmatch(), we'll think "bar.txt" is the start of the path, but it's not. This doesn't matter for the pattern above, but consider the wildmatch pattern "foo**/bar" and the path "foobar". These two should not match, because there is no file named "bar", and the "**" applies only to the containing directory name. But after removing the "foo" prefix, fnmatch will get "**/bar" and "bar", which it does consider a match, because "**/" can match zero directories. We can solve this by giving fnmatch a bit more context. As long as it has one byte of the matched prefix, then it will know that "bar" is not the start of the path. In this example it would get "o**/bar" and "obar", and realize that they cannot match. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-24Merge branch 'ps/t7528-ssh-agent-uds-workaround'Junio C Hamano1-1/+1
Recent OpenSSH creates the Unix domain socket to communicate with ssh-agent under $HOME instead of /tmp, which causes our test to fail doe to overly long pathname in our test environment, which has been worked around by using "ssh-agent -T". * ps/t7528-ssh-agent-uds-workaround: t7528: work around ETOOMANY in OpenSSH 10.1 and newer
2025-10-24Merge branch 'rs/add-patch-document-p-for-pager'Junio C Hamano1-22/+22
Show 'P'ipe command in "git add -p". * rs/add-patch-document-p-for-pager: add-patch: fully document option P
2025-10-24Merge branch 'jc/t1016-setup-fix'Junio C Hamano1-1/+1
GPG signing test set-up has been broken for a year, which has been corrected. * jc/t1016-setup-fix: t1016: make sure to use specified GPG
2025-10-24Merge branch 'jk/status-z-short-fix'Junio C Hamano1-0/+11
The "--short" option of "git status" that meant output for humans and "-z" option to show NUL delimited output format did not mix well, and colored some but not all things. The command has been updated to color all elements consistently in such a case. * jk/status-z-short-fix: status: make coloring of "-z --short" consistent
2025-10-24Merge branch 'js/t7500-pwd-windows-fix'Junio C Hamano1-5/+14
Test fix. * js/t7500-pwd-windows-fix: t7500: fix tests with absolute path following ":(optional)" on Windows
2025-10-24builtin/maintenance: introduce "geometric" strategyPatrick Steinhardt1-1/+19
We have two different repacking strategies in Git: - The "gc" strategy uses git-gc(1). - The "incremental" strategy uses multi-pack indices and `git multi-pack-index repack` to merge together smaller packfiles as determined by a specific batch size. The former strategy is our old and trusted default, whereas the latter has historically been used for our scheduled maintenance. But both strategies have their shortcomings: - The "gc" strategy performs regular all-into-one repacks. Furthermore it is rather inflexible, as it is not easily possible for a user to enable or disable specific subtasks. - The "incremental" strategy is not a full replacement for the "gc" strategy as it doesn't know to prune stale data. So today, we don't have a strategy that is well-suited for large repos while being a full replacement for the "gc" strategy. Introduce a new "geometric" strategy that aims to fill this gap. This strategy invokes all the usual cleanup tasks that git-gc(1) does like pruning reflogs and rerere caches as well as stale worktrees. But where it differs from both the "gc" and "incremental" strategy is that it uses our geometric repacking infrastructure exposed by git-repack(1) to repack packfiles. The advantage of geometric repacking is that we only need to perform an all-into-one repack when the object count in a repo has grown significantly. One downside of this strategy is that pruning of unreferenced objects is not going to happen regularly anymore. Every geometric repack knows to soak up all loose objects regardless of their reachability, and merging two or more packs doesn't consider reachability, either. Consequently, the number of unreachable objects will grow over time. This is remedied by doing an all-into-one repack instead of a geometric repack whenever we determine that the geometric repack would end up merging all packfiles anyway. This all-into-one repack then performs our usual reachability checks and writes unreachable objects into a cruft pack. As cruft packs won't ever be merged during geometric repacks we can thus phase out these objects over time. Of course, this still means that we retain unreachable objects for far longer than with the "gc" strategy. But the maintenance strategy is intended especially for large repositories, where the basic assumption is that the set of unreachable objects will be significantly dwarfed by the number of reachable objects. If this assumption is ever proven to be too disadvantageous we could for example introduce a time-based strategy: if the largest packfile has not been touched for longer than $T, we perform an all-into-one repack. But for now, such a mechanism is deferred into the future as it is not clear yet whether it is needed in the first place. Signed-off-by: Patrick Steinhardt <ps@pks.im> Acked-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-24builtin/maintenance: make "gc" strategy accessiblePatrick Steinhardt1-1/+13
While the user can pick the "incremental" maintenance strategy, it is not possible to explicitly use the "gc" strategy. This has two downsides: - It is impossible to use the default "gc" strategy for a specific repository when the strategy was globally set to a different strategy. - It is not possible to use git-gc(1) for scheduled maintenance. Address these issues by making making the "gc" strategy configurable. Furthermore, extend the strategy so that git-gc(1) runs for both manual and scheduled maintenance. Signed-off-by: Patrick Steinhardt <ps@pks.im> Acked-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-24builtin/maintenance: extend "maintenance.strategy" to manual maintenancePatrick Steinhardt1-0/+40
The "maintenance.strategy" configuration allows users to configure how Git is supposed to perform repository maintenance. The idea is that we provide a set of high-level strategies that may be useful in different contexts, like for example when handling a large monorepo. Furthermore, the strategy can be tweaked by the user by overriding specific tasks. In its current form though, the strategy only applies to scheduled maintenance. This creates something of a gap, as scheduled and manual maintenance will now use _different_ strategies as the latter would continue to use git-gc(1) by default. This makes the strategies way less useful than they could be on the one hand. But even more importantly, the two different strategies might clash with one another, where one of the strategies performs maintenance in such a way that it discards benefits from the other strategy. So ideally, it should be possible to pick one strategy that then applies globally to all the different ways that we perform maintenance. This doesn't necessarily mean that the strategy always does the _same_ thing for every maintenance type. But it means that the strategy can configure the different types to work in tandem with each other. Change the meaning of "maintenance.strategy" accordingly so that the strategy is applied to both types, manual and scheduled. As preceding commits have introduced logic to run maintenance tasks depending on this type we can tweak strategies so that they perform those tasks depending on the context. Note that this raises the question of backwards compatibility: when the user has configured the "incremental" strategy we would have ignored that strategy beforehand. Instead, repository maintenance would have continued to use git-gc(1) by default. But luckily, we can match that behaviour by: - Keeping all current tasks of the incremental strategy as `MAINTENANCE_TYPE_SCHEDULED`. This ensures that those tasks will not run during manual maintenance. - Configuring the "gc" task so that it is invoked during manual maintenance. Like this, the user shouldn't observe any difference in behaviour. Signed-off-by: Patrick Steinhardt <ps@pks.im> Acked-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-24builtin/maintenance: don't silently ignore invalid strategyPatrick Steinhardt1-0/+5
When parsing maintenance strategies we completely ignore the user-configured value in case it is unknown to us. This makes it basically undiscoverable to the user that scheduled maintenance is devolving into a no-op. Change this to instead die when seeing an unknown maintenance strategy. While at it, pull out the parsing logic into a separate function so that we can reuse it in a subsequent commit. Signed-off-by: Patrick Steinhardt <ps@pks.im> Acked-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-24builtin/maintenance: make the geometric factor configurablePatrick Steinhardt1-0/+32
The geometric repacking task uses a factor of two for its geometric sequence, meaning that each next pack must contain at least twice as many objects as the next-smaller one. In some cases it may be helpful to configure this factor though to reduce the number of packfile merges even further, e.g. in very big repositories. But while git-repack(1) itself supports doing this, the maintenance task does not give us a way to tune it. Introduce a new "maintenance.geometric-repack.splitFactor" configuration to plug this gap. Signed-off-by: Patrick Steinhardt <ps@pks.im> Acked-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-24builtin/maintenance: introduce "geometric-repack" taskPatrick Steinhardt1-0/+138
Introduce a new "geometric-repack" task. This task uses our geometric repack infrastructure as provided by git-repack(1) itself, which is a strategy that especially hosting providers tend to use to amortize the costs of repacking objects. There is one issue though with geometric repacks, namely that they unconditionally pack all loose objects, regardless of whether or not they are reachable. This is done because it means that we can completely skip the reachability step, which significantly speeds up the operation. But it has the big downside that we are unable to expire objects over time. To address this issue we thus use a split strategy in this new task: whenever a geometric repack would merge together all packs, we instead do an all-into-one repack. By default, these all-into-one repacks have cruft packs enabled, so unreachable objects would now be written into their own pack. Consequently, they won't be soaked up during geometric repacking anymore and can be expired with the next full repack, assuming that their expiry date has surpassed. Signed-off-by: Patrick Steinhardt <ps@pks.im> Acked-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-24diff: send external diff output to diff_options.fileJeff King1-0/+10
Diff output usually goes to the process stdout, but it can be redirected with the "--output" option. We store this in the "file" pointer of diff_options, and all of the diff code should write there instead of to stdout. But there's one spot we missed: running an external diff cmd. We don't redirect its output at all, so it just defaults to the stdout of the parent process. We should instead point its stdout at our output file. There are a few caveats to watch out for when doing so: - The stdout field takes a descriptor, not a FILE pointer. We can pull out the descriptor with fileno(). - The run-command API always closes the stdout descriptor we pass to it. So we must duplicate it (otherwise we break the FILE pointer, since it now points to a closed descriptor). - We don't need to worry about closing our dup'd descriptor, since the point is that run-command will do it for us (even in the case of an error). But we do need to make sure we skip the dup() if we set no_stdout (because then run-command will not look at it at all). - When the output is going to stdout, it would not be wrong to dup() the descriptor, but we don't need to. We can skip that extra work with a simple pointer comparison. - It seems like you'd need to fflush() the descriptor before handing off a copy to the child process to prevent out-of-order writes. But that was true even before this patch! It works because run-command always calls fflush(NULL) before running the child. The new test shows the breakage (and fix). The need for duplicating the descriptor doesn't need a new test; that is covered by the later test "GIT_EXTERNAL_DIFF with more than one changed files". Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-24commit-reach: avoid commit_list_insert_by_date()René Scharfe1-0/+101
Building a list using commit_list_insert_by_date() has quadratic worst case complexity. Avoid it by just appending in the loop and sorting at the end. The number of merge bases is usually small, so don't expect speedups in normal repositories. It has no limit, though. The added perf test shows a nice improvement when dealing with 16384 merge bases: Test v2.51.1 HEAD ----------------------------------------------------------------- 6010.2: git merge-base 0.55(0.54+0.00) 0.03(0.02+0.00) -94.5% Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-24Merge branch 'jk/diff-from-contents-fix'Junio C Hamano1-0/+4
Recently we attempted to improve "git diff -w" and friends to handle cases where patch output would be suppressed, but it introduced a bug that emits unnecessary output, which has been corrected. * jk/diff-from-contents-fix: diff: restore redirection to /dev/null for diff_from_contents
2025-10-23t7528: work around ETOOMANY in OpenSSH 10.1 and newerPatrick Steinhardt1-1/+1
In t7528 we spawn an SSH agent to verify that we can sign a commit via it. This test has started to fail on some machines: +++ ssh-agent unix_listener_tmp: path "/home/pks/Development/git/build/test-output/trash directory.t7528-signed-commit-ssh/.ssh/agent/s.UTulegefEg.agent.UrPHumMXPq" too long for Unix domain socket main: Couldn't prepare agent socket As it turns out this is caused by a change in OpenSSH 10.1 [1]: * ssh-agent(1), sshd(8): move agent listener sockets from /tmp to under ~/.ssh/agent for both ssh-agent(1) and forwarded sockets in sshd(8). Instead of creating the socket in "/tmp", OpenSSH now creates the socket in our home directory. And as the home directory gets modified to be located in our test output directory we end up with paths that are somewhat long. But Linux has a rather short limit of 108 characters for socket paths, and other systems have even lower limits, so it is very easy now to exceed the limit and run into the above error. Work around the issue by using `ssh-agent -T`, which instructs it to use the old behaviour and create the socket in "/tmp" again. This switch has only been introduced with 10.1 though, so for older versions we have to fall back to not using it. That's fine though, as older versions know to put the socket into "/tmp" already. An alternative approach would be to abbreviate the socket name itself so that we create it as e.g. "sshsock" in the trash directory. But taking the above example we'd still end up with a path that is 91 characters long. So we wouldn't really have a lot of headroom, and it is quite likely that some developers would see the issue on their machines. [1]: https://www.openssh.com/txt/release-10.1 Reported-by: Xi Ruoyao <xry111@xry111.site> Suggested-by: brian m. carlson <sandals@crustytoothpaste.net> Helped-by: Jeff King <peff@peff.net> Helped-by: Lauri Tirkkonen <lauri@hacktheplanet.fi> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-23diff: stop output garbled message in dry run modeLidong Yan1-0/+37
Earlier, b55e6d36 (diff: ensure consistent diff behavior with ignore options, 2025-08-08) introduced "dry-run" mode to the diff machinery so that content-based diff filtering (like ignoring space changes or those that match -I<regex>) can first try to produce a patch without emitting any output to see if under the given diff filtering condition we would get any output lines, and a new helper function diff_flush_patch_quietly() was introduced to use the mode to see an individual filepair needs to be shown. However, the solution was not complete. When files are deleted, file modes change, or there are unmerged entries in the index, dry-run mode still produces output because we overlooked these conditions, and as a result, dry-run mode was not quiet. To fix this, return early in emit_diff_symbol_from_struct() if we are in dry-run mode. This function will be called by all the emit functions to output the results. Returning early can avoid diff output when files are deleted or file modes are changed. Stop print message in dry-run mode if we have unmerged entries in index. Discard output of external diff tool in dry-run mode. Signed-off-by: Lidong Yan <yldhome2d2@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-22Merge branch 'jk/diff-from-contents-fix' into ↵Junio C Hamano1-0/+4
ly/diff-name-only-with-diff-from-content * jk/diff-from-contents-fix: diff: restore redirection to /dev/null for diff_from_contents
2025-10-22Merge branch 'so/t2401-use-test-path-helpers'Junio C Hamano1-17/+17
Test modernization. * so/t2401-use-test-path-helpers: t2401: update path checks using test_path helpers
2025-10-22Merge branch 'bc/sha1-256-interop-01'Junio C Hamano5-7/+116
The beginning of SHA1-SHA256 interoperability work. * bc/sha1-256-interop-01: t1010: use BROKEN_OBJECTS prerequisite t: allow specifying compatibility hash fsck: consider gpgsig headers expected in tags rev-parse: allow printing compatibility hash docs: add documentation for loose objects docs: improve ambiguous areas of pack format documentation docs: reflect actual double signature for tags docs: update offset order for pack index v3 docs: update pack index v3 format
2025-10-22commit-graph: add new config for changed-paths & recommend it in scalarEmily Yang1-0/+44
The changed-path Bloom filters feature has proven stable and reliable over several years of use, delivering significant performance improvement for file history computation in large monorepos. Currently a user can opt-in to writing the changed-path Bloom filters using the "--changed-paths" option to "git commit-graph write". The filters will be persisted until the user drops the filters using the "--no-changed-paths" option. For this functionality, refer to 0087a87ba8 (commit-graph: persist existence of changed-paths, 2020-07-01). Large monorepos using Git's background maintenance to build and update commit-graph files could use an easy switch to enable this feature without a foreground computation. In this commit, we're proposing a new config option "commitGraph.changedPaths": * If "true", "git commit-graph write" will write Bloom filters, equivalent to passing "--changed-paths"; * If "false" or "unset", Bloom filters will be written during "git commit-graph write" only if the filters already exist in the current commit-graph file. This matches the default behaviour of "git commit-graph write" without any "--[no-]changed-paths" option. Note "false" can disable a previous "true" config value but doesn't imply "--no-changed-paths". This config will always respect the precedence of command line option "--[no-]changed-paths". We also set this new config as optional recommended config in scalar to turn on this feature for large repos. Helped-by: Derrick Stolee <stolee@gmail.com> Signed-off-by: Emily Yang <emilyyang.git@gmail.com> Acked-by: Derrick Stolee <stolee@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-22Merge branch 'jt/repo-structure' into ps/ref-peeled-tagsJunio C Hamano2-0/+130
* jt/repo-structure: builtin/repo: add progress meter for structure stats builtin/repo: add keyvalue and nul format for structure stats builtin/repo: add object counts in structure output builtin/repo: introduce structure subcommand ref-filter: export ref_kind_from_refname() ref-filter: allow NULL filter pattern builtin/repo: rename repo_info() to cmd_repo_info()
2025-10-21builtin/repo: add progress meter for structure statsJustin Tobler1-0/+20
When using the structure subcommand for git-repo(1), evaluating a repository may take some time depending on its shape. Add a progress meter to provide feedback to the user about what is happening. The progress meter is enabled by default when the command is executed from a tty. It can also be explicitly enabled/disabled via the --[no-]progress option. Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-21builtin/repo: add keyvalue and nul format for structure statsJustin Tobler1-0/+33
All repository structure stats are outputted in a human-friendly table form. This format is not suitable for machine parsing. Add a --format option that supports three output modes: `table`, `keyvalue`, and `nul`. The `table` mode is the default format and prints the same table output as before. With the `keyvalue` mode, each line of output contains a key-value pair of a repository stat. The '=' character is used to delimit between keys and values. The `nul` mode is similar to `keyvalue`, but key-values are delimited by a NUL character instead of a newline. Also, instead of a '=' character to delimit between keys and values, a newline character is used. This allows stat values to support special characters without having to cquote them. These two new modes provides output that is more machine-friendly. Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-21builtin/repo: add object counts in structure outputJustin Tobler1-2/+17
The amount of objects in a repository can provide insight regarding its shape. To surface this information, use the path-walk API to count the number of reachable objects in the repository by object type. All regular references are used to determine the reachable set of objects. The object counts are appended to the same table containing the reference information. Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-21builtin/repo: introduce structure subcommandJustin Tobler2-0/+62
The structure of a repository's history can have huge impacts on the performance and health of the repository itself. Currently, Git lacks a means to surface repository metrics regarding its structure/shape via a single command. Acquiring this information requires users to be familiar with the relevant data points and the various Git commands required to surface them. To fill this gap, supplemental tools such as git-sizer(1) have been developed. To allow users to more readily identify repository structure related information, introduce the "structure" subcommand in git-repo(1). The goal of this subcommand is to eventually provide similar functionality to git-sizer(1), but natively in Git. The initial version of this command only iterates through all references in the repository and tracks the count of branches, tags, remote refs, and other reference types. The corresponding information is displayed in a human-friendly table formatted in a very similar manner to git-sizer(1). The width of each table column is adjusted automatically to satisfy the requirements of the widest row contained. Subsequent commits will surface additional relevant data points to output and also provide other more machine-friendly output formats. Based-on-patch-by: Derrick Stolee <stolee@gmail.com> Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-21add-patch: fully document option PRené Scharfe1-22/+22
Show option P in the prompt and explain it properly on a dedicated line in online help and documentation. Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-21Merge branch 'tb/incremental-midx-part-3.1' into ps/maintenance-geometricJunio C Hamano2-2/+2
* tb/incremental-midx-part-3.1: (64 commits) builtin/repack.c: clean up unused `#include`s repack: move `write_cruft_pack()` out of the builtin repack: move `write_filtered_pack()` out of the builtin repack: move `pack_kept_objects` to `struct pack_objects_args` repack: move `finish_pack_objects_cmd()` out of the builtin builtin/repack.c: pass `write_pack_opts` to `finish_pack_objects_cmd()` repack: extract `write_pack_opts_is_local()` repack: move `find_pack_prefix()` out of the builtin builtin/repack.c: use `write_pack_opts` within `write_cruft_pack()` builtin/repack.c: introduce `struct write_pack_opts` repack: 'write_midx_included_packs' API from the builtin builtin/repack.c: inline packs within `write_midx_included_packs()` builtin/repack.c: pass `repack_write_midx_opts` to `midx_included_packs` builtin/repack.c: inline `remove_redundant_bitmaps()` builtin/repack.c: reorder `remove_redundant_bitmaps()` repack: keep track of MIDX pack names using existing_packs builtin/repack.c: use a string_list for 'midx_pack_names' builtin/repack.c: extract opts struct for 'write_midx_included_packs()' builtin/repack.c: remove ref snapshotting from builtin repack: remove pack_geometry API from the builtin ...
2025-10-20t7500: fix tests with absolute path following ":(optional)" on WindowsJohannes Sixt1-5/+14
On Windows, the MSYS layer translates absolute path names generated by a shell script from the POSIX style /c/dir/file to the Windows style C:/dir/file form that is understood by git.exe. This happens only when the absolute path stands on its own as a program argument or a value of an environment variable. The earlier commits 749d6d166d (config: values of pathname type can be prefixed with :(optional), 2025-09-28) and ccfcaf399f (parseopt: values of pathname type can be prefixed with :(optional), 2025-09-28) added test cases where ":(optional)" is inserted before an absolute path. $PWD is used to construct the absolute paths, which gives the POSIX form, and the result is ":(optional)/c/dir/template". Such command line arguments are no longer recognized as absolute paths and do not undergo translation. Existing test cases that expect that the specified file does not exist are not incorrect (after all, git.exe will not find /c/dir/template). Yet, they are conceptually incorrect. That the use of $PWD is erroneous is revealed by a test case that expects that the optional file exists. Since no such test case is present, add one. Use "$(pwd)" to generate the absolute paths, so that the command line arguments become ":(optional)C:/dir/template". Signed-off-by: Johannes Sixt <j6t@kdbg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-17status: make coloring of "-z --short" consistentJeff King1-0/+11
When running "git status -z --short", the marker on modified index entries (e.g., "M") is colorized, but the "??" marker for untracked entries is not. Let's fix the "??" entries to show color here. At first glance you might think that neither should be colorized, as usually one would use "-z" to get machine-readable output. But this is a tricky and unusual case. We have two output formats, "--short" and "--porcelain" which are substantially similar, but differ in that "--short" is for humans who want something short and "--porcelain" is for machines. And "-z" by itself, without any other output option, does default to "--porcelain", so "git status -z" will not colorize anything. But if you explicitly ask for "-z" and "--short" together, then that is asking for the human-readable output, but separated by NULs. This is unlikely to be useful directly, but could for example be used if the output will be shown to a human outside of the terminal. At any rate, the current behavior is clearly wrong (since we colorize some things but not others), and I think colorizing everything is the least-surprising thing we can do here. Reported-by: Langbart <Langbart@protonmail.com> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-17Merge branch 'jk/diff-no-index-with-pathspec-fix'Junio C Hamano1-0/+16
An earlier addition to "git diff --no-index A B" to limit the output with pathspec after the two directories misbehaved when these directories were given with a trailing slash, which has been corrected. * jk/diff-no-index-with-pathspec-fix: diff --no-index: fix logic for paths ending in '/'
2025-10-17Merge branch 'rs/add-patch-options-fix'Junio C Hamano1-15/+61
The code in "git add -p" and friends to iterate over hunks was riddled with bugs, which has been corrected. * rs/add-patch-options-fix: add-patch: reset "permitted" at loop start add-patch: let options a and d roll over like y and n add-patch: let options k and K roll over like j and J add-patch: let options y, n, j, and e roll over to next undecided add-patch: document that option J rolls over add-patch: improve help for options j, J, k, and K
2025-10-17diff: restore redirection to /dev/null for diff_from_contentsJeff King1-0/+4
In --quiet mode, since we produce only an exit code for "something was changed" and no actual output, we can often get by with just a tree-level diff. However, certain options require us to actually look at the file contents (e.g., if we are ignoring whitespace changes). We have a flag "diff_from_contents" for that, and if it is set we call diff_flush() on each path. To avoid producing any output (since we were asked to be --quiet), we traditionally just redirected the output to /dev/null. That changed in b55e6d36eb (diff: ensure consistent diff behavior with ignore options, 2025-08-08), which replaced that with a "dry_run" flag. In theory, with dry_run set, we should produce no output. But it carries a risk of regression: if we forget to respect dry_run in any of the output paths, we'll accidentally produce output. And indeed, there is at least one such regression in that commit, as it covered only the case where we actually call into xdiff, and not creation or deletion diffs, where we manually generate the headers. We even test this case in t4035, but only with diff-tree, which does not show the bug by default because it does not require diff_from_contents. But git-diff does, because it allows external diff programs by default (so we must dig into each diff filepair to decide if it requires running an external diff that may declare two distinct blobs to actually be the same). We should fix all of those code paths to respect dry_run correctly, but in the meantime we can protect ourselves more fully by restoring the redirection to /dev/null. This gives us an extra layer of protection against regressions dues to other code paths we've missed. Though the original issue was reported with "git diff" (and due to its default of --ext-diff), I've used "diff-tree -w" in the new test. It triggers the same issue, but I think the fact that "-w" implies diff_from_contents is a bit more obvious, and fits in with the rest of t4035. Reported-by: Jake Zimmerman <jake@zimmerman.io> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-17Merge branch 'ly/diff-name-only-with-diff-from-content' into ↵Junio C Hamano2-6/+15
jk/diff-from-contents-fix * ly/diff-name-only-with-diff-from-content: diff: ensure consistent diff behavior with ignore options
2025-10-16packfile: introduce macro to iterate through packsPatrick Steinhardt2-2/+3
We have a bunch of different sites that want to iterate through all packs of a given `struct packfile_store`. This pattern is somewhat verbose and repetitive, which makes it somewhat cumbersome. Introduce a new macro `repo_for_each_pack()` that removes some of the boilerplate. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-16Merge branch 'tb/incremental-midx-part-3.1' into ↵Junio C Hamano2-2/+2
ps/remove-packfile-store-get-packs * tb/incremental-midx-part-3.1: (64 commits) builtin/repack.c: clean up unused `#include`s repack: move `write_cruft_pack()` out of the builtin repack: move `write_filtered_pack()` out of the builtin repack: move `pack_kept_objects` to `struct pack_objects_args` repack: move `finish_pack_objects_cmd()` out of the builtin builtin/repack.c: pass `write_pack_opts` to `finish_pack_objects_cmd()` repack: extract `write_pack_opts_is_local()` repack: move `find_pack_prefix()` out of the builtin builtin/repack.c: use `write_pack_opts` within `write_cruft_pack()` builtin/repack.c: introduce `struct write_pack_opts` repack: 'write_midx_included_packs' API from the builtin builtin/repack.c: inline packs within `write_midx_included_packs()` builtin/repack.c: pass `repack_write_midx_opts` to `midx_included_packs` builtin/repack.c: inline `remove_redundant_bitmaps()` builtin/repack.c: reorder `remove_redundant_bitmaps()` repack: keep track of MIDX pack names using existing_packs builtin/repack.c: use a string_list for 'midx_pack_names' builtin/repack.c: extract opts struct for 'write_midx_included_packs()' builtin/repack.c: remove ref snapshotting from builtin repack: remove pack_geometry API from the builtin ...
2025-10-15t2401: update path checks using test_path helpersSolly1-17/+17
Update old-style shell path checks to use the modern test helpers 'test_path_is_file' and 'test_path_is_dir' for improved runtime diagnosis. Signed-off-by: Solly <solobarine@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-15Merge branch 'mh/doc-credential-url-prefix' into maint-2.51Junio C Hamano1-4/+15
Doc update to describe a feature that has already been implemented. * mh/doc-credential-url-prefix: docs/gitcredentials: describe URL prefix matching
2025-10-15Merge branch 'ps/odb-clean-stale-wrappers' into maint-2.51Junio C Hamano1-6/+4
Code clean-up. * ps/odb-clean-stale-wrappers: odb: drop deprecated wrapper functions
2025-10-15Merge branch 'rj/t6137-cygwin-fix' into maint-2.51Junio C Hamano1-6/+6
Test fix for breakage introduced in Git 2.50. * rj/t6137-cygwin-fix: t6137-*.sh: fix test failure on cygwin
2025-10-15Merge branch 'kn/refs-files-case-insensitive' into maint-2.51Junio C Hamano2-1/+166
Deal more gracefully with directory / file conflicts when the files backend is used for ref storage, by failing only the ones that are involved in the conflict while allowing others. * kn/refs-files-case-insensitive: refs/files: handle D/F conflicts during locking refs/files: handle F/D conflicts in case-insensitive FS refs/files: use correct error type when lock exists refs/files: catch conflicts on case-insensitive file-systems
2025-10-15Merge branch 'pw/rebase-i-cleanup-fix' into maint-2.51Junio C Hamano1-6/+22
"git rebase -i" failed to clean-up the commit log message when the command commits the final one in a chain of "fixup" commands, which has been corrected. * pw/rebase-i-cleanup-fix: sequencer: remove VERBATIM_MSG flag rebase -i: respect commit.cleanup when picking fixups
2025-10-15Merge branch 'jk/add-i-color' into maint-2.51Junio C Hamano2-0/+72
Some among "git add -p" and friends ignored color.diff and/or color.ui configuration variables, which is an old regression, which has been corrected. * jk/add-i-color: contrib/diff-highlight: mention interactive.diffFilter add-interactive: manually fall back color config to color.ui add-interactive: respect color.diff for diff coloring stash: pass --no-color to diff plumbing child processes
2025-10-15Merge branch 'sg/line-log-boundary-fixes' into maint-2.51Junio C Hamano7-0/+206
A corner case bug in "git log -L..." has been corrected. * sg/line-log-boundary-fixes: line-log: show all line ranges touched by the same diff range line-log: fix assertion error
2025-10-15Merge branch 'ps/upload-pack-oom-protection' into maint-2.51Junio C Hamano1-26/+42
A broken or malicious "git fetch" can say that it has the same object for many many times, and the upload-pack serving it can exhaust memory storing them redundantly, which has been corrected. * ps/upload-pack-oom-protection: upload-pack: don't ACK non-commits repeatedly in protocol v2 t5530: modernize tests
2025-10-15Merge branch 'ds/midx-write-fixes' into maint-2.51Junio C Hamano1-1/+21
Fixes multiple crashes around midx write-out codepaths. * ds/midx-write-fixes: midx-write: simplify error cases midx-write: reenable signed comparison errors midx-write: use uint32_t for preferred_pack_idx midx-write: use cleanup when incremental midx fails midx-write: put failing response value back midx-write: only load initialized packs
2025-10-15Merge branch 'ds/path-walk-repack-fix' into maint-2.51Junio C Hamano1-0/+63
"git repack --path-walk" lost objects in some corner cases, which has been corrected. cf. <CABPp-BHFxxGrqKc0m==TjQNjDGdO=H5Rf6EFsf2nfE1=TuraOQ@mail.gmail.com> * ds/path-walk-repack-fix: path-walk: create initializer for path lists path-walk: fix setup of pending objects
2025-10-15Merge branch 'ly/diff-name-only-with-diff-from-content' into maint-2.51Junio C Hamano2-6/+15
Various options to "git diff" that makes comparison ignore certain aspects of the differences (like "space changes are ignored", "differences in lines that match these regular expressions are ignored") did not work well with "--name-only" and friends. * ly/diff-name-only-with-diff-from-content: diff: ensure consistent diff behavior with ignore options
2025-10-15Merge branch 'jc/diff-no-index-in-subdir' into maint-2.51Junio C Hamano1-0/+17
"git diff --no-index" run inside a subdirectory under control of a Git repository operated at the top of the working tree and stripped the prefix from the output, and oddballs like "-" (stdin) did not work correctly because of it. Correct the set-up by undoing what the set-up sequence did to cwd and prefix. * jc/diff-no-index-in-subdir: diff: --no-index should ignore the worktree
2025-10-15Merge branch 'en/ort-rename-fixes' into maint-2.51Junio C Hamano1-15/+504
Various bugs about rename handling in "ort" merge strategy have been fixed. * en/ort-rename-fixes: merge-ort: fix directory rename on top of source of other rename/delete merge-ort: fix incorrect file handling merge-ort: clarify the interning of strings in opt->priv->path t6423: fix missed staging of file in testcases 12i,12j,12k t6423: document two bugs with rename-to-self testcases merge-ort: drop unnecessary temporary in check_for_directory_rename() merge-ort: update comments to modern testfile location
2025-10-15Merge branch 'dl/push-missing-object-error' into maint-2.51Junio C Hamano1-50/+4
"git push" had a code path that led to BUG() but it should have been a die(), as it is a response to a usual but invalid end-user action to attempt pushing an object that does not exist. cf. <xmqqo6spiyqp.fsf@gitster.g> * dl/push-missing-object-error: remote.c: convert if-else ladder to switch remote.c: remove BUG in show_push_unqualified_ref_name_error() t5516: remove surrounding empty lines in test bodies
2025-10-15Merge branch 'ps/reflog-migrate-fixes' into maint-2.51Junio C Hamano3-7/+142
"git refs migrate" to migrate the reflog entries from a refs backend to another had a handful of bugs squashed. * ps/reflog-migrate-fixes: refs: fix invalid old object IDs when migrating reflogs refs: stop unsetting REF_HAVE_OLD for log-only updates refs/files: detect race when generating reflog entry for HEAD refs: fix identity for migrated reflogs ident: fix type of string length parameter builtin/reflog: implement subcommand to write new entries refs: export `ref_transaction_update_reflog()` builtin/reflog: improve grouping of subcommands Documentation/git-reflog: convert to use synopsis type
2025-10-15Merge branch 'js/rebase-i-allow-drop-on-a-merge' into maint-2.51Junio C Hamano1-0/+1
During interactive rebase, using 'drop' on a merge commit lead to an error, which was incorrect. * js/rebase-i-allow-drop-on-a-merge: rebase -i: permit 'drop' of a merge commit
2025-10-15refs/files: deprecate writing symrefs as symbolic linksPatrick Steinhardt1-3/+23
The "files" backend has the ability to store symbolic refs as symbolic links, which can be configured via "core.preferSymlinkRefs". This feature stems back from the early days: the initial implementation of symbolic refs used symlinks exclusively. The symref format was only introduced in 9b143c6e15 (Teach update-ref about a symbolic ref stored in a textfile., 2005-09-25) and made the default in 9f0bb90d16 (core.prefersymlinkrefs: use symlinks for .git/HEAD, 2006-05-02). This is all about 20 years ago, and there are no known reasons nowadays why one would want to use symlinks instead of symrefs. Mark the feature for deprecation in Git 3.0. Note that this only deprecates _writing_ symrefs as symbolic links. Reading such symrefs is still supported for now. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-14Merge branch 'jk/curl-global-trace-components' into maint-2.51Junio C Hamano1-1/+3
Adjust to the way newer versions of cURL selectivel enables tracing options, so that our tests can continue to work. * jk/curl-global-trace-components: curl: add support for curl_global_trace() components
2025-10-14Merge branch 'da/cargo-serialize' into maint-2.51Junio C Hamano1-10/+4
Makefile tried to run multiple "cargo build" which would not work very well; serialize their execution to work it around. * da/cargo-serialize: Makefile: build libgit-rs and libgit-sys serially
2025-10-14Merge branch 'jc/optional-path'Junio C Hamano1-10/+28
Configuration variables that take a pathname as a value (e.g. blame.ignorerevsfile) can be marked as optional by prefixing ":(optoinal)" before its value. * jc/optional-path: parseopt: values of pathname type can be prefixed with :(optional) config: values of pathname type can be prefixed with :(optional) t7500: fix GIT_EDITOR shell snippet t7500: make each piece more independent
2025-10-14Merge branch 'kh/format-patch-range-diff-notes'Junio C Hamano1-1/+15
"git format-patch --range-diff=... --notes=..." did not drive the underlying range-diff with correct --notes parameter, ending up comparing with different set of notes from its main patch output you would get from "git format-patch --notes=..." for a singleton patch. * kh/format-patch-range-diff-notes: format-patch: handle range-diff on notes correctly for single patches revision: add rdiff_log_arg to rev_info range-diff: rename other_arg to log_arg
2025-10-14Merge branch 'pw/add-p-hunk-splitting-fix'Junio C Hamano1-0/+31
Marking a hunk 'selected' in "git add -p" and then splitting made all the split pieces 'selected'; this has been changed to make them all 'undecided', which gives better end-user experience. * pw/add-p-hunk-splitting-fix: add-patch: update hunk splitability after editing add -p: mark split hunks as undecided
2025-10-13Merge branch 'kn/reftable-consistency-checks'Junio C Hamano3-4/+79
The reftable backend learned to sanity check its on-disk data more carefully. * kn/reftable-consistency-checks: refs/reftable: add fsck check for checking the table name reftable: add code to facilitate consistency checks fsck: order 'fsck_msg_type' alphabetically Documentation/fsck-msgids: remove duplicate msg id reftable: check for trailing newline in 'tables.list' refs: move consistency check msg to generic layer refs: remove unused headers
2025-10-13fast-import: add '--signed-tags=<mode>' optionChristian Couder2-0/+81
Recently, eaaddf5791 (fast-import: add '--signed-commits=<mode>' option, 2025-09-17) added support for controlling how signed commits are handled by `git fast-import`, but there is no option yet to decide about signed tags. To remediate that, let's add a '--signed-tags=<mode>' option to `git fast-import` too. With this, both `git fast-export` and `git fast-import` have both a '--signed-tags=<mode>' and a '--signed-commits=<mode>' supporting the same <mode>s. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-13fast-export: handle all kinds of tag signaturesChristian Couder1-0/+36
Currently the handle_tag() function in "builtin/fast-export.c" searches only for "\n-----BEGIN PGP SIGNATURE-----\n" in the tag message to find a tag signature. This doesn't handle all kinds of OpenPGP signatures as some can start with "-----BEGIN PGP MESSAGE-----" too, and this doesn't handle SSH and X.509 signatures either as they use "-----BEGIN SSH SIGNATURE-----" and "-----BEGIN SIGNED MESSAGE-----" respectively. To handle all these kinds of tag signatures supported by Git, let's use the parse_signed_buffer() function to properly find signatures in tag messages. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-13t9350: properly count annotated tagsChristian Couder1-4/+8
In "t9350-fast-export.sh", these existing tests: - 'fast-export | fast-import when main is tagged' - 'cope with tagger-less tags' are checking the number of annotated tags in the test repo by comparing it with some hardcoded values. This could be an issue if some new tests that have some prerequisites add new annotated tags to the repo before these existing tests. When the prerequisites would be satisfied, the number of annotated tags would be different from when some prerequisites would not be satisfied. As we are going to add new tests that add new annotated tags in a following commit, let's properly count the number of annotated tag in the repo by incrementing a counter each time a new annotated tag is added, and then by comparing the number of annotated tags to the value of the counter when checking the number of annotated tags. This is a bit ugly, but it makes it explicit that some tests are interdependent. Alternative solutions, like moving the new tests to the end of the script, were considered, but were rejected because they would instead hide the technical debt and could confuse developers in the future. Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-13lib-gpg: allow tests with GPGSM or GPGSSH prereq firstChristian Couder1-4/+20
When the 'GPG' prereq is lazily tested, `mkdir "$GNUPGHOME"` could fail if the "$GNUPGHOME" directory already exists. This can happen if the 'GPGSM' or the 'GPGSSH' prereq has been lazily tested before as they already create "$GNUPGHOME". To allow the GPGSM or the GPGSSH prereq to appear before the GPG prereq in some test scripts, let's refactor the creation and setup of the "$GNUPGHOME"` directory in a new prepare_gnupghome() function that uses `mkdir -p "$GNUPGHOME"`. This will be useful in a following commit. Unfortunately the new prepare_gnupghome() function cannot be used when lazily testing the GPG2 prereq, because that would expose existing, hidden bugs in "t1016-compatObjectFormat.sh", so let's just document that with a NEEDSWORK comment. Helped-by: Todd Zullinger <tmz@pobox.com> Helped-by: Collin Funk <collin.funk1@gmail.com> Signed-off-by: Christian Couder <chriscool@tuxfamily.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-10t1016: make sure to use specified GPGJunio C Hamano1-1/+1
c348192a (t1016: clean up style, 2024-10-22) fixed a coding style violation that has an extra space between redirection operator ">" and the redirection target, but at the same time, replaced the use of "git config" to set a configuration variable to be used by the remainder of tests with "test_config". The pattern employed here is that the first set-up test prepares the environment to be used by subsequent tests, which then use the settings left by this set-up test to perform their tasks. Using test_config in the first set-up test means the config setting made by the set-up test is reverted at the end of the first set-up test, which totally misses the point. Go back to use "git config" to fix this. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-10Merge branch 'ps/gitlab-ci-windows-improvements'Junio C Hamano1-15/+19
GitLab CI improvements. * ps/gitlab-ci-windows-improvements: t8020: fix test failure due to indeterministic tag sorting gitlab-ci: upload Meson test logs as JUnit reports gitlab-ci: drop workaround for Python certificate store on Windows gitlab-ci: ignore failures to disable realtime monitoring gitlab-ci: dedup instructions to disable realtime monitoring
2025-10-09t/lib-gpg: call prepare_gnupghome() in GPG2 prereqTodd Zullinger1-0/+1
The GPG2 prereq added in 2f36339fa8 (t/lib-gpg: introduce new prereq GPG2, 2023-06-04) does not create the $GNUPGHOME directory. Tests which use the GPG2 prereq without previously using the GPG prereq fail because of the missing directory. This currently affects t1016-compatObjectFormat. Ensure $GNUPGHOME is created in the GPG2 prereq. Signed-off-by: Todd Zullinger <tmz@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-09t/lib-gpg: add prepare_gnupghome() to create GNUPGHOME dirTodd Zullinger1-4/+7
We create the $GNUPGHOME directory in both the GPG and GPGSSH prereqs. Replace the redundancy with a function. Use `mkdir -p` to ensure we do not fail if a test includes more than one of these prereqs. Signed-off-by: Todd Zullinger <tmz@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-09t1010: use BROKEN_OBJECTS prerequisitebrian m. carlson1-5/+8
When hash compatibility mode is enabled, we cannot write broken objects because they cannot be mapped into the other hash algorithm. Use the BROKEN_OBJECTS prerequisite to disable these tests and the writing of broken objects in this mode. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-09t: allow specifying compatibility hashbrian m. carlson2-2/+20
We want to specify a compatibility hash for testing interactions for SHA-256 repositories where we have SHA-1 compatibility enabled. Allow the user to specify this scenario in the test suite by setting GIT_TEST_DEFAULT_HASH to "sha256:sha1". Note that this will get passed into GIT_DEFAULT_HASH, which Git itself does not presently support. However, we will support this in a future commit. Since we'll now want to know the value for a specific version, let's add the ability to specify either the storage hash (in this case, SHA-256) or the compatibility hash (SHA-1). We use a different value for the compatibility hash that will be enabled for all repositories (test_repo_compat_hash_algo) versus the one that is used individually in some tests (test_compat_hash_algo), since we want to still run those individual tests without requiring that the testsuite be run fully in a compatibility mode. In some cases, we'll need to adjust our test suite to work in a proper way with a compatibility hash. For example, in such a case, we'll only use pack index v3, since v1 and v2 lack support for multiple algorithms. Since we won't want to write those older formats, we'll need to skip tests that do so. Let's add a COMPAT_HASH prerequisite for this purpose. Finally, in this scenario, we can no longer rely on having broken objects work since we lack compatibility mappings to rewrite objects in the repository. Add a prerequisite, BROKEN_OBJECTS, that we define in terms of COMPAT_HASH and checks to see if creating deliberately broken objects is possible, so that we can disable these tests if not. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-09fsck: consider gpgsig headers expected in tagsbrian m. carlson1-0/+54
When we're creating a tag, we want to make sure that gpgsig and gpgsig-sha256 headers are allowed for the commit. The default fsck behavior is to ignore the fact that they're left over, but some of our tests enable strict checking which flags them nonetheless. Add improved checking for these headers as well as documentation and several tests. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-09rev-parse: allow printing compatibility hashbrian m. carlson1-0/+34
Right now, we have a way to print the storage hash, the input hash, and the output hash, but we lack a way to print the compatibility hash. Add a new type to --show-object-format, compat, which prints this value. If no compatibility hash exists, simply print a newline. This is important to allow users to use multiple options at once while still getting unambiguous output. Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-08Merge branch 'mh/doc-credential-url-prefix'Junio C Hamano1-4/+15
Doc update to describe a feature that has already been implemented. * mh/doc-credential-url-prefix: docs/gitcredentials: describe URL prefix matching
2025-10-08Merge branch 'kn/ref-cache-seek-fix'Junio C Hamano1-0/+65
Handling of an empty subdirectory of .git/refs/ in the ref-files backend has been corrected. * kn/ref-cache-seek-fix: refs/ref-cache: fix SEGFAULT when seeking in empty directories
2025-10-08Merge branch 'ml/reflog-write-committer-info-fix'Junio C Hamano1-0/+36
"git reflog write" did not honor the configured user.name/email which has been corrected. * ml/reflog-write-committer-info-fix: builtin/reflog: respect user config in "write" subcommand
2025-10-07Merge branch 'ps/odb-clean-stale-wrappers'Junio C Hamano1-6/+4
Code clean-up. * ps/odb-clean-stale-wrappers: odb: drop deprecated wrapper functions
2025-10-07Merge branch 'ps/packfile-store'Junio C Hamano2-2/+2
Code clean-up around the in-core list of all the pack files and object database(s). * ps/packfile-store: packfile: refactor `get_packed_git_mru()` to work on packfile store packfile: refactor `get_all_packs()` to work on packfile store packfile: refactor `get_packed_git()` to work on packfile store packfile: move `get_multi_pack_index()` into "midx.c" packfile: introduce function to load and add packfiles packfile: refactor `install_packed_git()` to work on packfile store packfile: split up responsibilities of `reprepare_packed_git()` packfile: refactor `prepare_packed_git()` to work on packfile store packfile: reorder functions to avoid function declaration odb: move kept cache into `struct packfile_store` odb: move MRU list of packfiles into `struct packfile_store` odb: move packfile map into `struct packfile_store` odb: move initialization bit into `struct packfile_store` odb: move list of packfiles into `struct packfile_store` packfile: introduce a new `struct packfile_store`
2025-10-07parseopt: values of pathname type can be prefixed with :(optional)Junio C Hamano1-0/+10
In the previous step, we introduced an optional filename that can be given to a configuration variable, and nullify the fact that such a configuration setting even existed if the named path is missing or empty. Let's do the same for command line options that name a pathname. Signed-off-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-07config: values of pathname type can be prefixed with :(optional)Junio C Hamano1-0/+8
Sometimes people want to specify additional configuration data as "best effort" basis. Maybe commit.template configuration file points at somewhere in ~/template/ but on a particular system, the file may not exist and the user may be OK without using the template in such a case. When the value given to a configuration variable whose type is pathname wants to signal such an optional file, it can be marked by prepending ":(optional)" in front of it. Such a setting that is marked optional would avoid getting the command barf for a missing file, as an optional configuration setting that names a missing file is not even seen. cf. <xmqq5ywehb69.fsf@gitster.g> Signed-off-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-07t7500: fix GIT_EDITOR shell snippetJunio C Hamano1-2/+2
2140b140 (commit: error out for missing commit message template, 2011-02-25) defined GIT_EDITOR="echo hello >\"\$1\"" for these two tests, with the intention that 'hello' would be written in the given file, but as Phillip Wood points out, GIT_EDITOR is invoked by shell after getting expanded to sh -c 'echo hello >"$1" "$@"' 'echo hello >"$1"' path/to/file which is not what we want. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-07refs/reftable: add fsck check for checking the table nameKarthik Nayak2-0/+59
Add glue code in 'refs/reftable-backend.c' which calls the reftable library to perform the fsck checks. Here we also map the reftable errors to Git' fsck errors. Introduce a check to validate table names for a given reftable stack. Also add 'badReftableTableName' as a corresponding error within Git. The reftable specification mentions: It suggested to use ${min_update_index}-${max_update_index}-${random}.ref as a naming convention. So treat non-conformant file names as warnings. While adding the fsck header to 'refs/reftable-backend.c', modify the list to maintain lexicographical ordering. Signed-off-by: Karthik Nayak <karthik.188@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-07reftable: check for trailing newline in 'tables.list'Karthik Nayak1-4/+20
In the reftable format, the 'tables.list' file contains a newline separated list of tables. While we parse this file, we do not check or care about the last newline. Tighten the parser in `parse_names()` to return an appropriate error if the last newline is missing. This requires modification to `parse_names()` to now return the error while accepting the output as a third argument. Signed-off-by: Karthik Nayak <karthik.188@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-06add-patch: reset "permitted" at loop startRené Scharfe1-0/+14
Don't accumulate allowed options from any visited hunks, start fresh at the top of the loop instead and only record the allowed options for the current hunk. Reported-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-06add-patch: let options a and d roll over like y and nRené Scharfe1-6/+6
Options a and d stage and unstage all undecided hunks towards the bottom of the array of hunks, respectively, and then roll over to the very first hunk. The first part is similar to y and n if the current hunk is the last one in the array, but they roll over to the next undecided hunk if there is any. That's more useful; do it for a and d as well. Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-06add-patch: let options k and K roll over like j and JRené Scharfe1-20/+20
Options j and J roll over at the bottom and go to the first undecided hunk and hunk 1, respectively. Let options k and K do the same when they reach the top of the hunk array, so let them go to the last undecided hunk and the last hunk, respectively, for consistency. Also use the same direction-neutral error messages. Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-06add-patch: let options y, n, j, and e roll over to next undecidedRené Scharfe1-0/+22
The options y, n, and e mark the current hunk as decided. If there's another undecided hunk towards the bottom of the hunk array they go there. If there isn't, but there is another undecided hunk towards the top then they go to the very first hunk, no matter if it has already been decided on. The option j does basically the same move. Technically it is not allowed if there's no undecided hunk towards the bottom, but the variable "permitted" is never reset, so this permission is retained from the very first hunk. That may a bug, but this behavior is at least consistent with y, n, and e and arguably more useful than refusing to move. Improve the roll-over behavior of these four options by moving to the first undecided hunk instead of hunk 1, consistent with what they do when not rolling over. Also adjust the error message for j, as it will only be shown if there's no other undecided hunk in either direction. Reported-by: Windl, Ulrich <u.windl@ukr.de> Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-06add-patch: document that option J rolls overRené Scharfe1-4/+14
The variable "permitted" is not reset after moving to a different hunk, so it only accumulates permission and doesn't necessarily reflect those of the current hunk. This may be a bug, but is actually useful with the option J, which can be used at the last hunk to roll over to the first hunk. Make this particular behavior official. Also adjust the error message, as it will only be shown if there's just a single hunk. Suggested-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-02Merge branch 'kh/you-still-use-whatchanged-fix'Junio C Hamano1-0/+57
The "do you still use it?" message given by a command that is deeply deprecated and allow us to suggest alternatives has been updated. * kh/you-still-use-whatchanged-fix: BreakingChanges: remove claim about whatchanged reports whatchanged: remove not-even-shorter clause whatchanged: hint about git-log(1) and aliasing you-still-use-that??: help the user help themselves t0014: test shadowing of aliases for a sample of builtins git: allow alias-shadowing deprecated builtins git: move seen-alias bookkeeping into handle_alias(...) git: add `deprecated` category to --list-cmds Makefile: don’t add whatchanged after it has been removed
2025-10-02Merge branch 'ps/config-get-color-fixes'Junio C Hamano1-177/+172
The use of "git config get" command to learn how ANSI color sequence is for a particular type, e.g., "git config get --type=color --default=reset no.such.thing", isn't very ergonomic. * ps/config-get-color-fixes: builtin/config: do not spawn pager when printing color codes builtin/config: special-case retrieving colors without a key builtin/config: do not die in `get_color()` t1300: small style fixups t1300: write test expectations in the test's body
2025-10-02Merge branch 'cc/fast-import-strip-signed-commits'Junio C Hamano2-0/+107
"git fast-import" learned that "--signed-commits=<how>" option that corresponds to that of "git fast-export". * cc/fast-import-strip-signed-commits: fast-import: add '--signed-commits=<mode>' option gpg-interface: refactor 'enum sign_mode' parsing
2025-10-02Merge branch 'ms/refs-optimize'Junio C Hamano4-429/+450
"git refs optimize" is added for not very well explained reason despite it does the same thing as "git pack-refs"... * ms/refs-optimize: t: add test for git refs optimize subcommand t0601: refactor tests to be shareable builtin/refs: add optimize subcommand doc: pack-refs: factor out common options builtin/pack-refs: factor out core logic into a shared library builtin/pack-refs: convert to use the generic refs_optimize() API reftable-backend: implement 'optimize' action files-backend: implement 'optimize' action refs: add a generic 'optimize' API
2025-10-02t8020: fix test failure due to indeterministic tag sortingPatrick Steinhardt1-15/+19
In e6c06e87a2 (last-modified: fix bug when some paths remain unhandled, 2025-09-18), we have fixed a bug where under certain circumstances, git-last-modified(1) would BUG because there's still some unhandled paths. The fix claims that the root cause here is criss-cross merges, and it adds a test case that seemingly exercises this. Curiously, this test case fails on some systems because the actual output does not match our expectations: diff --git a/expect b/actual index 5271607..bdc620e 100644 --- a/expect --- b/actual @@ -1,3 +1,3 @@ km3 a -k2 k +km2 k 1 file error: last command exited with $?=1 not ok 15 - last-modified with subdir and criss-cross merge The output we see is git-name-rev(1) with `--annotate-stdin`. What it does is to take the output of git-last-modified(1), which contains object IDs of the blamed commits, and convert those object IDs into the names of the corresponding tags. Interestingly, we indeed have both "k2" and "km2" as tags, and even more interestingly both of these tags point to the same commit. So the output we get isn't _wrong_, as the tags are ambiguous. But why do both of these tags point to the same commit? "km2" really is supposed to be a merge, but due to the way the test is constructed the merge turns into a fast-forward merge. Which means that the resulting commit-graph does not even contain a criss-cross merge in the first place! A quick test though shows that the test indeed triggers the bug, so the initial analysis that the behaviour is triggered by such merges must be wrong. And it is: seemingly, the issue isn't with criss-cross merges, but rather with a graph where different files in the same directory were modified on both sides of a merge. Refactor the test so that we explicitly test for this specific situation instead of mentioning the "criss-cross merge" red herring. As the test is very specific to the actual layout of the repository we also adapt it to use its own standalone repository. Note that this requires us to drop the `test_when_finished` call in `check_last_modified` because it's not supported to execute that function in a subshell. This refactoring also fixes the original tag ambiguity that caused us to fail on some platforms. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-01docs/gitcredentials: describe URL prefix matchingM Hickford1-4/+15
Documentation was inaccurate since 9a121b0d226 (credential: handle `credential.<partial-URL>.<key>` again, 2020-04-24) Add tests for documented behaviour. Signed-off-by: M Hickford <mirth.hickford@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-01refs/ref-cache: fix SEGFAULT when seeking in empty directoriesKarthik Nayak1-0/+65
The 'cache_ref_iterator_seek()' function is used to seek the `ref_iterator` to the desired reference in the ref-cache mechanism. We use the seeking functionality to implement the '--start-after' flag in 'git-for-each-ref(1)'. When using the files-backend with packed-refs, it is possible that some of the refs directories are empty. For e.g. just after repacking, the 'refs/heads' directory would be empty. The ref-cache seek mechanism, doesn't take this into consideration when descending into a subdirectory, and makes an out of bounds access, causing SEGFAULT as we try to access entries within the directory. Fix this by breaking out of the loop when we enter an empty directory. Since we start with the base directory of 'refs/' which is never empty, it is okay to perform this check after the first iteration in the `do..while` clause. Add tests which simulate this behavior and also provide coverage over using the feature over packed-refs. Helped-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Karthik Nayak <karthik.188@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-10-01builtin/reflog: respect user config in "write" subcommandMichael Lohmann1-0/+36
The reflog write recognizes only GIT_COMMITTER_NAME and GIT_COMMITTER_EMAIL environment variables, but forgot to honor the user.name and user.email configuration variables, due to lack of repo_config() call to grab these values from the configuration files. The test suite sets these variables, so this behavior was unnoticed. Ensure that the reflog write also uses the values of user.name and user.email if set in the Git configuration. Co-authored-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Michael Lohmann <git@lohmann.sh> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-09-29Merge branch 'tc/last-modified-recursive-fix'Junio C Hamano1-0/+16
"git last-modified" operating in non-recursive mode used to trigger a BUG(), which has been corrected. * tc/last-modified-recursive-fix: last-modified: fix bug when some paths remain unhandled
2025-09-29Merge branch 'kn/refs-files-case-insensitive'Junio C Hamano2-1/+166
Deal more gracefully with directory / file conflicts when the files backend is used for ref storage, by failing only the ones that are involved in the conflict while allowing others. * kn/refs-files-case-insensitive: refs/files: handle D/F conflicts during locking refs/files: handle F/D conflicts in case-insensitive FS refs/files: use correct error type when lock exists refs/files: catch conflicts on case-insensitive file-systems
2025-09-29Merge branch 'dk/stash-apply-index'Junio C Hamano2-1/+40
The stash.index configuration variable can be set to make "git stash pop/apply" pretend that it was invoked with "--index". * dk/stash-apply-index: stash: honor stash.index in apply, pop modes stash: refactor private config globals t3905: remove unneeded blank line t3903: reduce dependencies on previous tests
2025-09-29Merge branch 'jk/setup-revisions-freefix'Junio C Hamano1-0/+9
There are double frees and leaks around setup_revisions() API used in "git stash show", which has been fixed, and setup_revisions() API gained a wrapper to make it more ergonomic when using it with strvec-manged argc/argv pairs. * jk/setup-revisions-freefix: revision: retain argv NULL invariant in setup_revisions() treewide: pass strvecs around for setup_revisions_from_strvec() treewide: use setup_revisions_from_strvec() when we have a strvec revision: add wrapper to setup_revisions() from a strvec revision: manage memory ownership of argv in setup_revisions() stash: tell setup_revisions() to free our allocated strings
2025-09-29Merge branch 'pw/rebase-i-cleanup-fix'Junio C Hamano1-6/+22
"git rebase -i" failed to clean-up the commit log message when the command commits the final one in a chain of "fixup" commands, which has been corrected. * pw/rebase-i-cleanup-fix: sequencer: remove VERBATIM_MSG flag rebase -i: respect commit.cleanup when picking fixups
2025-09-29Merge branch 'jc/3.0-default-initial-branch-to-main-addendum'Junio C Hamano2-4/+8
Keep giving hint about the default initial branch name for users who may be surprised after Git 3.0 switch-over. * jc/3.0-default-initial-branch-to-main-addendum: initial branch: give hints after switching the default name
2025-09-29Merge branch 'pw/3.0-default-initial-branch-to-main'Junio C Hamano101-232/+253
Declare that "git init" that is not otherwise configured uses 'main' as the initial branch, not 'master', starting Git 3.0. * pw/3.0-default-initial-branch-to-main: t0613: stop setting default initial branch t9902: switch default branch name to main t4013: switch default branch name to main breaking-changes: switch default branch to main
2025-09-29Merge branch 'ps/clar-updates'Junio C Hamano34-258/+1415
Import a newer version of the clar unit testing framework. * ps/clar-updates: t/unit-tests: update to 10e96bc t/unit-tests: update clar to fcbed04
2025-09-29Merge branch 'ps/packfile-store' into tb/incremental-midx-part-3.1Junio C Hamano2-2/+2
* ps/packfile-store: packfile: refactor `get_packed_git_mru()` to work on packfile store packfile: refactor `get_all_packs()` to work on packfile store packfile: refactor `get_packed_git()` to work on packfile store packfile: move `get_multi_pack_index()` into "midx.c" packfile: introduce function to load and add packfiles packfile: refactor `install_packed_git()` to work on packfile store packfile: split up responsibilities of `reprepare_packed_git()` packfile: refactor `prepare_packed_git()` to work on packfile store packfile: reorder functions to avoid function declaration odb: move kept cache into `struct packfile_store` odb: move MRU list of packfiles into `struct packfile_store` odb: move packfile map into `struct packfile_store` odb: move initialization bit into `struct packfile_store` odb: move list of packfiles into `struct packfile_store` packfile: introduce a new `struct packfile_store`