summaryrefslogtreecommitdiff
AgeCommit message (Collapse)AuthorFilesLines
2026-06-16Merge branch 'jd/unpack-trees-wo-the-repository'Junio C Hamano1-7/+7
A handful of inappropriate uses of the_repository have been rewritten to use the right repository structure instance in the unpack-trees.c codepath. * jd/unpack-trees-wo-the-repository: unpack-trees: use repository from index instead of global
2026-06-16Merge branch 'ps/t7527-fix-tap-output'Junio C Hamano7-19/+34
A recent regression in t7527 that broke TAP output has been fixed, some other test noise that also broke TAP output has been silenced, and 'prove' is now configured to fail on invalid TAP output to prevent future regressions. * ps/t7527-fix-tap-output: t: let prove fail when parsing invalid TAP output t/lib-git-p4: silence output when killing p4d and its watchdog t/test-lib: silence EBUSY errors on Windows during test cleanup t7810: turn MB_REGEX check into a lazy prereq t7527: fix broken TAP output ci: unify Linux images across GitLab and GitHub gitlab-ci: add missing Linux jobs gitlab-ci: rearrange Linux jobs to match GitHub's order
2026-06-16Merge branch 'jk/describe-contains-all-match-fix'Junio C Hamano2-3/+37
The 'git describe --contains --all' command has been fixed to properly honor the '--match' and '--exclude' options by passing them down to 'git name-rev' with the appropriate reference prefixes. * jk/describe-contains-all-match-fix: describe: fix --exclude, --match with --contains and --all
2026-06-16Merge branch 'kk/streaming-walk-pqueue'Junio C Hamano5-53/+88
Streaming revision walks have been optimized by using a priority queue for date-sorting commits, speeding up walks repositories with many merges. * kk/streaming-walk-pqueue: revision: use priority queue for non-limited streaming walks revision: introduce rev_walk_mode to clarify get_revision_1() pack-objects: call release_revisions() after cruft traversal
2026-06-16Merge branch 'mf/revision-max-count-oldest'Junio C Hamano5-5/+155
"git rev-list" (and "git log" family of commands) learned a new "--max-count-oldest" that picks oldest N commits in the range instead of the usual newest. * mf/revision-max-count-oldest: bash-completions: add --max-count-oldest revision.c: implement --max-count-oldest
2026-06-16Merge branch 'js/win-kill-child-more-gently'Junio C Hamano2-7/+194
Advanced emulation of kill() used on Windows in GfW has been upstreamed to improve the symptoms like left-behind .lock files and that fails to let the child clean-up itself when it gets killed. * js/win-kill-child-more-gently: mingw: really handle SIGINT mingw: kill child processes in a gentler way
2026-06-16read_gitfile(): simplify NOT_A_REPO error messageJeff King5-8/+9
If a .git file is well-formed but points to a directory that is not itself a valid repository, then we say: fatal: not a git repository: <pointed-to-repo> without mentioning the .git file that pointed us there in the first place. Doing so could better help the user understand the source of the problem. In theory the most helpful thing we could do is mention both paths, like: gitfile '<gitfile>' points to invalid repository: <pointed-to-repo> But there's another catch: when we generate the error, we don't always know the pointed-to repository! This leads to a potential segfault. The message comes from read_gitfile_error_die(). Originally we only called that function from inside read_gitfile_gently(), passing in both the gitfile path and the pointed-to path. But that changed in 1dd27bfbfd (setup: improve error diagnosis for invalid .git files, 2026-03-04). Since then, the caller in setup_git_directory_gently(), even if it wants to die on error, always passes in the "return_error_code" flag, asking the function to instead return a numeric error code. And then it calls read_gitfile_error_die() itself, passing NULL for the pointed-to path. If we get the READ_GITFILE_ERR_NOT_A_REPO code, we form a message using that NULL pointer, and either segfault or get garbage like "not a git repository: (null)", depending on the platform. We could fix this by having the function pass out both the numeric error code and the pointed-to path. But that creates a new headache: we have to allocate that string on the heap and pass ownership back to the caller. So now every caller has to be aware of it (and either free the result, or signal that they are not interested by using an extra parameter). Instead, let's just drop the pointed-to path from the error message entirely, and mention only the gitfile. This fixes the NULL dereference without introducing any more complexity. The user-facing error message is not as detailed as it could be, but is better than the original. Since it mentions the gitfile, a user investigating the situation can look there to find the pointed-to path (whereas you could not go the other way from the original message). There's an existing test in t0002 which triggers this case, but we didn't notice the problem because it checks only that we said "not a repository", and not the full string. So if we print "(null)" it is happy. It will probably crash on some non-glibc platforms, but nobody seems to have reported it yet (the breakage is recent-ish as of v2.54). I'm also somewhat surprised that building with ASan/UBSan doesn't catch this, but it doesn't seem to (and I found an open issue with somebody asking for NULL printf checks to be implemented in the sanitizers). We'll tweak the test to match the new error, but there's no need to beef it up further, since we're not showing the pointed-to path at all. We also racily trigger this in t7450. During parallel cloning we might see one of several errors, including this one. And so we must update that message, too (you can otherwise find the failure pretty quickly by running t7450 with --stress). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-15b4: introduce configuration for the Git projectPatrick Steinhardt2-0/+17
In the preceding commit we have extended our documentation to recommend b4 for sending patch series to the mailing list. Introduce configuration so that it knows to honor preferences of the Git project by default. For now, this configuration does two things: - It configures "send-same-thread = shallow", which tells b4 to always send subsequent versions of the same patch series as a reply to the cover letter of the first version. - It configures "prep-cover-template", which tells b4 to use a custom template for the cover letter. The most important change compared to the default template is that our custom template also includes a range-diff. There's potentially more things that we may want to configure going forward, like for example auto-configuration of folks to Cc on certain patches. But these two tweaks feel like a good place to start. Note that these values only serve as defaults, and users may want to tweak those defaults based on their own preference. Luckily, users can do that without having to touch `.b4-config` at all, as b4 allows them to override values via Git configuration: ``` $ git config set b4.prep-cover-template /does/not/exist $ b4 send --dry-run ERROR: prep-cover-template says to use x, but it does not exist ``` So this gives users an easy way to override our defaults without having to touch ".b4-config", which would dirty the tree. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-15MyFirstContribution: recommend the use of b4Patrick Steinhardt2-5/+93
The b4 tool originates from the Linux kernel community and is intended to help mailing-list based workflows. It automates a lot of the annoying bookkeeping tasks that contributors typically need to do: tracking the list of recipients, Message-IDs, range-diffs and the like. In addition to that, b4 also has many other subcommands that help the maintainer and reviewers. The Git project uses the same infrastructure as the kernel, so this tool is also a very good fit for us. Adapt "MyFirstContribution" to explicitly recommend its use. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-15MyFirstContribution: recommend shallow threading of cover lettersPatrick Steinhardt1-4/+4
The "MyFirstContribution" document recommends the use of deep threading of cover letters: every cover letter of subsequent iterations shall be linked to the cover letter of the preceding version. The result of this is that eventually, threads with many versions are getting nested so deep that it becomes hard to follow. Adapt the recommendation to instead propose shallow threading of cover letters: instead of linking the cover letter to the previous cover letter, the user is supposed to always link it to the first cover letter. This still makes it easy to follow the iterations, but has the benefit of nesting to a much shallower level. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-15gitattributes: fix eol attribute for Perl scriptsKoutian Wu1-1/+1
The *.pl pattern currently sets eof=lf, which is not a built-in attribute used for line-ending normalization. Use eol=lf instead, matching the neighboring *.perl and *.pm rules, so Perl scripts are checked out with LF line endings. Signed-off-by: Koutian Wu <ktwu01@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-15cat-file: speed up default formatRené Scharfe1-3/+6
eb54a3391b (cat-file: skip expanding default format, 2022-03-15) added special handling for the default batch format. In the meantime it has fallen behind the code path for handling arbitrary formats. Bring it up to speed by using the new and more efficient strbuf_add_oid_hex() and strbuf_add_uint() instead of strbuf_addf(): Benchmark 1: ./git_main cat-file --batch-all-objects --batch-check='%(objectname) %(objecttype) %(objectsize)' Time (mean ± σ): 1.051 s ± 0.003 s [User: 1.027 s, System: 0.023 s] Range (min … max): 1.049 s … 1.058 s 10 runs Benchmark 2: ./git_main cat-file --batch-all-objects --batch-check='%(objectname)-%(objecttype)-%(objectsize)' Time (mean ± σ): 1.012 s ± 0.002 s [User: 0.988 s, System: 0.023 s] Range (min … max): 1.010 s … 1.018 s 10 runs Benchmark 3: ./git cat-file --batch-all-objects --batch-check='%(objectname) %(objecttype) %(objectsize)' Time (mean ± σ): 979.0 ms ± 1.1 ms [User: 954.1 ms, System: 23.2 ms] Range (min … max): 977.7 ms … 980.8 ms 10 runs Summary ./git cat-file --batch-all-objects --batch-check='%(objectname) %(objecttype) %(objectsize)' ran 1.03 ± 0.00 times faster than ./git_main cat-file --batch-all-objects --batch-check='%(objectname)-%(objecttype)-%(objectsize)' 1.07 ± 0.00 times faster than ./git_main cat-file --batch-all-objects --batch-check='%(objectname) %(objecttype) %(objectsize)' Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-15Merge branch 'master' of github.com:alshopov/gitkJohannes Sixt1-12/+33
* 'master' of github.com:alshopov/gitk: gitk i18n: Update Bulgarian translation (329t) Signed-off-by: Johannes Sixt <j6t@kdbg.org>
2026-06-15Merge branch 'master' of github.com:alshopov/git-guiJohannes Sixt1-11/+26
* 'master' of github.com:alshopov/git-gui: git-gui i18n: Update Bulgarian translation (562t) Signed-off-by: Johannes Sixt <j6t@kdbg.org>
2026-06-15odb: use size_t for object_info.sizep and the size APIsJohannes Schindelin65-191/+209
When `js/objects-larger-than-4gb-on-windows` widened the streaming, index-pack and unpack-objects code paths, in the interest of keeping the patches somewhat reasonably-sized, it left the public ODB API still typed in `unsigned long`. In particular `struct object_info::sizep` and the four wrappers built on top of it (`odb_read_object`, `odb_read_object_peeled`, `odb_read_object_info`, `odb_pretend_object`) still return the unpacked size through `unsigned long *`, so on Windows `cat-file -s` and the `git add` / `git status` paths for a >4 GiB blob silently cap at 4 GiB. Widen the field and the four wrappers. The previous commits already widened the `unpack_entry()` cascade and pack-objects' in-core size accessors, so most of the cascade arrives here with no further work: the temporary shims in `packed_object_info_with_index_pos()` and in `unpack_entry()`'s delta-base recovery path go away, the two `SET_SIZE(entry, cast_size_t_to_ulong(canonical_size))` calls in `check_object()` and the matching one in `drop_reused_delta()` collapse to plain `SET_SIZE`, and `oe_get_size_slow()`'s tail `cast_size_t_to_ulong()` is gone too. What remains narrow are the boundaries this series does not intend to touch: the diff, blame, textconv and fast-import machinery. Even so, this patch is unfortunately quite large. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-15packfile,delta: drop the `cast_size_t_to_ulong()` wrappersJohannes Schindelin4-35/+13
When I started the transition from `unsigned long` to `size_t`, in the interest of keeping the patches reviewable, I introduced these calls to prevent data type narrowing from silently failing to handle large object sizes. I also introduced `*_sz()` variants that would allow most of the callers to keep using that `unsigned long` that the 90s kindly asked to be returned. After the preceding commits, the only places that called the narrow wrappers either no longer exist or already use the `_sz` form internally, so the wrappers just narrow values back through `cast_size_t_to_ulong()` for no reason. Drop them and rename the `_sz` variants back to the natural names. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-15pack-objects: use size_t for in-core object sizesJohannes Schindelin2-18/+19
`pack-objects` stores per-entry object sizes in either the 31-bit `size_` member of the `struct object_entry` or, when the value does not fit, the `pack->delta_size[]` spill array. The accessors (`oe_size`, `oe_delta_size`, `oe_get_size_slow`, `oe_size_*_than`) and the setters (`oe_set_size`, `oe_set_delta_size`) used `unsigned long` for the spill type, which on Windows means the spill silently caps at 4 GiB per entry. That is what made `upload-pack` die with "object too large to read on this platform" when serving the >4 GiB blob in `t5608` tests 5 and 6 when run with `GIT_TEST_CLONE_2GB`. Widen them all to `size_t` (including `pack->delta_size`) and drop the three `cast_size_t_to_ulong()` calls in `check_object()` that guarded `in_pack_size`. The two `SET_SIZE(entry, canonical_size)` calls in the same function stay cast-free as before, since `canonical_size` is still `unsigned long` until a later commit widens `object_info::sizep`. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-15packfile: widen unpack_entry()'s size out-parameter to size_tJohannes Schindelin4-16/+27
The topic `js/objects-larger-than-4gb-on-windows` widened the streaming, index-pack and unpack-objects paths to `size_t` but deliberately stopped at the in-memory `unpack_entry()` cascade, which still hands back the unpacked size through `unsigned long *`. On Windows that boundary truncates above 4 GiB because that data type is only 32 bits wide on that platform. Widen the code path. Except `packed_object_info_with_index_pos()`: It cannot yet pass `oi->sizep` directly because the field is still `unsigned long *`; bridge it with a `size_t` temporary that narrows back, and let a later commit drop the bridge once the field is wide too. `gfi_unpack_entry()` keeps its narrow signature because fast-import tracks sizes through `unsigned long` everywhere it crosses subsystem boundaries, keeping its signature allows the scope of this commit to be somewhat reasonable, still. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-15pack-objects(check_pack_inflate()): use size_t instead of unsigned longJohannes Schindelin1-3/+2
`write_reuse_object()` learned to track its packed-object size as `size_t` in 606c192380 (odb, packfile: use size_t for streaming object sizes, 2026-05-08), but the comparison sink it feeds, `check_pack_inflate()`, still takes the expected decompressed size as `unsigned long`. The call site bridges the mismatch with `cast_size_t_to_ulong()`, which on Windows turns a >4 GiB object into an immediate die(). That function only uses `expect` once: as the right-hand side of a `stream.total_out == expect` equality test against zlib's counter. zlib's own `total_out` counter is `uLong` and is therefore still 32-bit-bound on Windows. Widening `expect` to `size_t` cannot fix that, but it is a strict improvement nonetheless: instead of dying outright, an oversized object now simply makes the equality fail and lets `write_reuse_object()` fall back to `write_no_reuse_object()`, which decompresses and re-deflates the content (and which the larger pack-objects widening series targets separately). Drop the `cast_size_t_to_ulong()` shim at the call site now that the receiving parameter speaks the same type as `entry_size`. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-15patch-delta: use size_t for sizesJohannes Schindelin7-20/+20
`patch_delta()` takes the source and delta sizes by value and writes back the reconstructed target size through an `unsigned long *`. That datatype cannot represent a value that exceeds 4 GiB on systems where `unsigned long` is 32-bit (notably 64-bit Windows builds), though, even though the delta encoding itself, the on-disk layout, and the in-memory buffers happily carry such sizes. A `size_t` companion to `get_delta_hdr_size()`, `get_delta_hdr_size_sz()`, was introduced in 17fa077596 (delta, packfile: use size_t for delta header sizes, 2026-05-08) precisely so that `patch_delta()` could be widened without changing the on-the-wire decoding helper's signature. Widen `patch_delta()`'s three size parameters to `size_t` and switch its internal use of `get_delta_hdr_size()` to the `_sz` variant. Then propagate the wider type through the callers. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-15compat/msvc: use _chsize_s for ftruncateJohannes Schindelin1-1/+23
On Windows, `unsigned long` and `long` are 32 bits even on 64-bit builds. The MSVC compatibility header has shimmed `ftruncate()` with #define ftruncate _chsize ever since `compat/msvc-posix.h` was introduced. `_chsize()` takes a 32-bit `long` for the new length, which silently truncates files (and the requested size) to 2 GiB. That is enough to make t7508 test 126 "git add fails gracefully with 4 GiB and 8 GiB files" fail under MSVC: `test-tool truncate` creates a sparse 4 GiB or 8 GiB file via the shimmed `ftruncate()`, and the test never gets off the ground. `_chsize_s()` is the modern replacement, accepts a 64-bit `__int64` length, and is the only sensible target on Windows. The catch is that it does not follow the POSIX `-1` + `errno` convention: it returns `0` on success and an errno value (a small positive integer) on failure. A plain `#define ftruncate _chsize_s` would therefore silently break callers that test the return value as `< 0` or against `-1`, of which there are several: `http.c`, `parallel-checkout.c`, and `t/helper/test-truncate.c` among them. Introduce a `static inline` wrapper that calls `_chsize_s()`, copies its errno return into `errno`, and translates the result to the familiar `-1` / `0` convention, then point `ftruncate` at the wrapper. Place the wrapper after `#include "mingw-posix.h"` so the `off_t` parameter resolves to the already-widened `off64_t` rather than the 32-bit `_off_t` from `compat/vcbuild/include/unistd.h`. MinGW is unaffected: its `ftruncate()` already takes `off_t` and routes through `ftruncate64()` when `_FILE_OFFSET_BITS=64`, which is the default in our build. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-15topic flush before -rc1 (batch 1)Junio C Hamano1-0/+28
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-15Merge branch 'ak/typofixes'Junio C Hamano24-69/+69
Typofixes. * ak/typofixes: doc: fix typos via codespell
2026-06-15Merge branch 'ob/more-repo-config-values'Junio C Hamano20-88/+126
Many core configuration variables have been migrated from global variables into 'repo_config_values' to tie them to a specific repository instance, avoiding cross-repository state leakage. * ob/more-repo-config-values: environment: move "warn_on_object_refname_ambiguity" into `struct repo_config_values` environment: move "sparse_expect_files_outside_of_patterns" into `struct repo_config_values` environment: move "core_sparse_checkout_cone" into `struct repo_config_values` environment: move "precomposed_unicode" into `struct repo_config_values` environment: move "pack_compression_level" into `struct repo_config_values` environment: move `zlib_compression_level` into `struct repo_config_values` environment: move "check_stat" into `struct repo_config_values` environment: move "trust_ctime" into `struct repo_config_values`
2026-06-15Merge branch 'am/doc-tech-hash-typofix'Junio C Hamano1-1/+1
Typofix. * am/doc-tech-hash-typofix: doc: fix typo in GIT_ALTERNATE_OBJECT_DIRECTORIES
2026-06-15Merge branch 'lo/doc-format-patch-subject-prefix'Junio C Hamano1-4/+3
Wording used in "format-patch --subject-prefix" documentation has been improved. * lo/doc-format-patch-subject-prefix: Documentation: remove redundant 'instead' in --subject-prefix
2026-06-15Merge branch 'ps/setup-centralize-odb-creation'Junio C Hamano8-100/+118
The setup logic to discover and configure repositories has been refactored, and the initialization of the object database has been centralized. * ps/setup-centralize-odb-creation: setup: construct object database in `apply_repository_format()` repository: stop reading loose object map twice on repo init setup: stop initializing object database without repository setup: stop creating the object database in `setup_git_env()` repository: stop initializing the object database in `repo_set_gitdir()` setup: deduplicate logic to apply repository format setup: drop `setup_git_env()` t0001: plug test gaps for git-init(1) with GIT_OBJECT_DIRECTORY
2026-06-15Merge branch 'hn/config-typo-advice'Junio C Hamano4-10/+118
"git config foo.bar=baz" is not likely to be a request to read the value of such a variable with '=' in its name; rather it is plausible that the user meant "git config set foo.bar baz". Give advice when giving an error message. * hn/config-typo-advice: config: improve diagnostic for "set" with missing value config: add git_config_key_is_valid() for quiet validation
2026-06-15Merge branch 'ls/doc-raw-timestamp-prefix'Junio C Hamano2-0/+16
Documentation and tests have been added to clarify that Git's internal raw timestamp format requires a `@` prefix for values less than 100,000,000 to prevent ambiguity with other formats like YYYYMMDD. * ls/doc-raw-timestamp-prefix: doc: document and test `@` prefix for raw timestamps
2026-06-15Merge branch 'jc/submitting-patches-cover-letter'Junio C Hamano1-0/+25
Guidelines on how to write a cover letter for a multi-patch series have been added to SubmittingPatches, which also got a new marker to separate the section for typofixes. * jc/submitting-patches-cover-letter: SubmittingPatches: describe cover letter SubmittingPatches: separate typofixes section
2026-06-14git-gui i18n: Update Bulgarian translation (562t)Alexander Shopov1-11/+26
Signed-off-by: Alexander Shopov <ash@kambanaria.org>
2026-06-14gitk i18n: Update Bulgarian translation (329t)Alexander Shopov1-12/+33
Signed-off-by: Alexander Shopov <ash@kambanaria.org>
2026-06-14commit-graph: use timestamp_t for max parent generation accumulatorElijah Newren2-1/+10
compute_reachable_generation_numbers() computes each commit's generation as max(c->date, max(parent.generation)) + 1 by walking its parents and accumulating their generations into a local uint32_t max_gen = 0; while info->get_generation() returns timestamp_t and compute_generation_from_max() already takes its max_gen parameter as timestamp_t. For v1 (topological levels) the narrowing is harmless because GENERATION_NUMBER_V1_MAX is less than 2^30, but for v2 (corrected committer dates) it silently truncates any parent generation that does not fit in 32 bits, i.e. any parent whose committer timestamp is at or beyond 2106-02-07 UTC (>= 2^32). The truncated max then causes child commits to end up with a corrected committer date that matches the parent's instead of being at least 1 higher. The bad value gets written into the commit-graph and causes problems later, and can be noticed by running `git commit-graph verify`. Widen the accumulator to timestamp_t. This is solely an in-memory arithmetic fix with no on-disk format change: the on-disk format already encodes timestamp_t values and existing readers handle them unchanged. This merely allows the code to compute the correct value to write to disk. The narrowing was introduced in 80c928d947c2 (commit-graph: simplify compute_generation_numbers(), 2023-03-20), which rewired v2 to use the shared compute_reachable_generation_numbers() helper; the helper's local accumulator had been declared uint32_t in the immediately preceding 368d19b0b7fa (commit-graph: refactor compute_topological_levels(), 2023-03-20) when only v1 was using it, where it was harmless. Add a new test with a future-dated parent and a present-day child; without the above fix, `git commit-graph verify` reports the descendant's stored generation as below parent + 1. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-14cache-tree: fix verify_cache() to catch non-adjacent D/F conflictsElijah Newren4-11/+151
verify_cache() checks that the index does not contain both "path" and "path/file" before writing a tree. It does this by comparing only adjacent entries, relying on the assumption that "path/file" would immediately follow "path" in sorted order. Unfortunately, this assumption does not always hold. For example: docs <-- submodule entry docs-internal/README.md <-- intervening entry docs/requirements.txt <-- D/F conflict, NOT adjacent to "docs" When this happens, verify_cache() silently misses the D/F conflict and write-tree produces a corrupt tree object containing duplicate entries (one for the submodule "docs" and one for the tree "docs"). I could not find any caller in current git that both allows the index to get into this state and then tries to write it out without doing other checks beyond the verify_cache() call in cache_tree_update(), but verify_cache() is documented as a safety net for preventing corrupt trees and should actually provide that guarantee. A downstream consumer that relied solely on cache_tree_update()'s internal checking via verify_cache() to prevent duplicate tree entries was bitten by the gap. Add a test that constructs a corrupt index directly (bypassing the D/F checks in add_index_entry) and verifies that write-tree now rejects it. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-14merge-ort: abort merge when trees have duplicate entriesElijah Newren2-27/+88
Trees with duplicate entries are malformed; fsck reports "contains duplicate file entries" for them. merge-ort has from the beginning assumed that we would never hit such trees. It was written with the assumption that traverse_trees() calls collect_merge_info_callback() at most once per path. The "sanity checks" in that callback (added in d2bc1994f363 (merge-ort: implement a very basic collect_merge_info(), 2020-12-13)) verify properties of each individual call but not that invariant. The strmap_put() in setup_path_info() silently overwrites the entry from any prior call for the same path, because it assumed there would be no other path. Unfortunately, supplemental data structures for various optimizations could still be tweaked before the extra paths were overwritten, and those data structures not matching expected state could trip various assertions. Change the return type of setup_path_info() from void to int to allow us to detect this case, and abort the merge with a clear error message when it occurs. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-14merge-ort: free diff pairs queue in clear_or_reinit_internal_opts()Elijah Newren1-0/+2
clear_or_reinit_internal_opts() is responsible for cleaning up the various data structures in merge_options_internal. It already handles many renames-related structures (dirs_removed, dir_renames, relevant_sources, cached_pairs, deferred, etc.) but does not free renames->pairs[].queue. In the normal code path, resolve_and_process_renames() frees pairs[s].queue and reinitializes it with diff_queue_init() before clear_or_reinit_internal_opts() runs, so the omission is harmless. However, if collect_merge_info() encounters an error and returns early (before resolve_and_process_renames() is ever called), any diff pairs already queued by collect_rename_info()/add_pair() will have their backing array leaked. Fix this by freeing renames->pairs[].queue in the cleanup function. In the normal path the pointer is already NULL (from the earlier diff_queue_init() in resolve_and_process_renames()), so free(NULL) is a safe no-op. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-14merge-ort: drop unnecessary show_all_errors from collect_merge_info()Elijah Newren1-1/+0
collect_merge_info() has set info.show_all_errors = 1 since d2bc1994f363 (merge-ort: implement a very basic collect_merge_info(), 2020-12-13). This setting was copied from unpack-trees.c where it controls batching of error messages for porcelain display, but merge-ort has no such error-batching logic and never needed it. With show_all_errors set, traverse_trees() captures a negative callback return but continues processing remaining entries rather than stopping immediately. Removing the setting restores the default behavior where a negative return from collect_merge_info_callback() breaks out of the traversal loop right away, allowing a future commit to exit early when a corrupt tree is detected. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-14merge-ort: propagate callback errors from traverse_trees_wrapper()Elijah Newren1-6/+8
traverse_trees_wrapper() saves entries from a first pass through traverse_trees() and then replays them through the real callback (collect_merge_info_callback). However, the replay loop silently discards the callback return value. This is not a deferred error; it is an ignored error. Today the only originator of a negative return in this entire call graph is traverse_trees()'s "exceeded maximum allowed tree depth" check; everything else (collect_merge_info_callback, traverse_trees_wrapper, the inner traverse_trees recursion) only relays that. So in current Git, the visible effect of dropping the replay callback's return value is narrow but bad: a tree nested past core.maxTreeDepth has its -1 swallowed, the subtree below the limit is silently pruned, and the merge completes as if that were the correct result. A later patch in this series will teach collect_merge_info_callback() to return -1 on an additional path -- detecting duplicate entries in malformed trees -- which is similarly handled today by just ignoring the problem (resulting in mostly a "last one wins" rule, though the non-last entry can mutate various state flags). Capture the return value, stop the loop on negative returns, and propagate the error to the caller. The callback returns a positive mask value on success, so normalize non-negative returns to 0 for the caller. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-13compat/posix.h: simplify GIT_GNUC_PREREQ() comparisonDominik Loidolt1-2/+2
GIT_GNUC_PREREQ() uses a glibc-style bit-shift version comparison, which is harder to read than an explicit major/minor comparison. Use an explicit comparison, as in many BSD <sys/cdefs.h> headers, and drop the Linux header attribution comment because it no longer applies. Signed-off-by: Dominik Loidolt <dominik.loidolt@univie.ac.at> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-13compat/posix.h: clean up GIT_GNUC_PREREQ() and UNUSEDDominik Loidolt1-9/+8
Fix the preprocessor indentation of the GIT_GNUC_PREREQ() and UNUSED macros according to the CodingGuidelines, without changing their behavior. Adjust the spelling in the GIT_GNUC_PREREQ() comment block. Signed-off-by: Dominik Loidolt <dominik.loidolt@univie.ac.at> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-13compat/posix.h: enable UNUSED warning messages for ClangDominik Loidolt1-1/+13
Use a dedicated Clang version check for the UNUSED macro. Commit 7c07f36ad2 (git-compat-util.h: GCC deprecated message arg only in GCC 4.5+, 2022-10-05) restricted use of the deprecated attribute's message argument in the UNUSED macro to GCC 4.5 or newer. Clang identifies itself as GNUC 4.2.1 for compatibility, so GIT_GNUC_PREREQ(4, 5) does not detect whether Clang supports the deprecated("...") form. Add GIT_CLANG_PREREQ() macro and use it to enable the UNUSED warning message for Clang 2.9 and newer. Signed-off-by: Dominik Loidolt <dominik.loidolt@univie.ac.at> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-12commit-reach: die on contains walk errorsTamir Duberstein2-1/+29
Without generation numbers, repo_is_descendant_of() can return -1 when it cannot read commit ancestry. commit_contains() exposes that result through a Boolean interface, so ref-filter treats it as true. This can include a ref for --contains or exclude it for --no-contains without failing the command. Die when repo_is_descendant_of() reports an error. The memoized walk already dies when it cannot parse a commit, so callers of the non-memoized path no longer turn a failed walk into a match. Reported-by: Jeff King <peff@peff.net> Signed-off-by: Tamir Duberstein <tamird@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-12ref-filter: memoize --contains with generationsTamir Duberstein2-2/+29
git branch and git for-each-ref run a separate reachability walk for each ref considered by --contains and --no-contains. Refs with shared history therefore traverse the same commits repeatedly. git tag instead uses a depth-first walk that caches results across refs. That walk can perform poorly without generation numbers: a negative check may walk to the root instead of stopping at a nearby divergence. Generation numbers let it stop below the oldest target. Use the memoized walk for all ref-filter callers when generation numbers are available. Keep git tag on its existing path without generations. Caching still helps when many tags share deep history: ffc4b8012d (tag: speed up --contains calculation, 2011-06-11) reduced git tag --contains HEAD~200 in linux-2.6 from 15.417 to 5.329 seconds. The new shared-history perf test improves from 0.72 to 0.03 seconds. In a repository with 62,174 remote-tracking refs, running: git branch -r --contains c78ae85f3ce7e improves from 104.365 seconds to 468 milliseconds. Suggested-by: Jeff King <peff@peff.net> Signed-off-by: Tamir Duberstein <tamird@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-12commit-reach: reject cycles in contains walkTamir Duberstein3-4/+29
The memoized contains traversal used by git tag assumes that commit ancestry is acyclic. Replacement refs can violate that assumption, causing it to keep pushing an already active commit until memory is exhausted. Mark commits while they are active and die if the traversal encounters an active commit. Other failures in this walk already die through parse_commit_or_die(); using a second reachability walk would only add a separate policy for malformed history. Suggested-by: Kristofer Karlsson <krka@spotify.com> Signed-off-by: Tamir Duberstein <tamird@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-12ref-filter: restore prefix-scoped iterationTamir Duberstein2-8/+44
dabecb9db2 (for-each-ref: introduce a '--start-after' option, 2025-07-15) changed branch, remote-tracking branch, and tag enumeration from constructing an iterator with the namespace prefix to constructing an unscoped iterator and seeking to the prefix. Review of --start-after noted that the construction prefix and seek position represent different state and are easy to conflate [1]. It also noted that future branch or tag support would need to retain the namespace prefix while moving the cursor [2]. The files backend constructs its loose-ref iterator with cache priming enabled. cache_ref_iterator_begin() immediately applies the construction prefix through cache_ref_iterator_set_prefix(), reading loose refs beneath it before packed refs are opened. An empty prefix therefore reads every loose ref, and a later seek cannot undo that I/O. For the current single-kind filters, construct the iterator with the namespace prefix when start_after is not set. Leave the existing start_after path unchanged; no current command combines it with these filters, and future support must carry the prefix separately from the cursor. With 10,000 unrelated loose refs in the files backend, the p6300 tests improve as follows: before after branch 2.74 s 0.11 s branch --remotes 2.81 s 0.12 s tag 3.01 s 0.11 s [1] https://lore.kernel.org/r/aGZidwwlToWThkn8@pks.im/ [2] https://lore.kernel.org/r/xmqqikjq7s16.fsf@gitster.g/ Fixes: dabecb9db2b2 ("for-each-ref: introduce a '--start-after' option") Suggested-by: Karthik Nayak <karthik.188@gmail.com> Signed-off-by: Tamir Duberstein <tamird@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-12ls-files: filter pathspec before lstatTamir Duberstein4-0/+61
In --deleted and --modified modes, show_files() calls lstat() for each index entry before show_ce() applies the pathspec. prune_index() avoids most of these calls for pathspecs with a common directory prefix, but not for a top-level name or leading wildcard. Match before lstat() to avoid accessing the worktree for entries that cannot be shown. Treat this as a prefilter: do not update ps_matched, and retain the match in show_ce() so --error-unmatch is satisfied only by entries that the selected modes actually show. Prefilter only a single pathspec item, bounding the added work for each index entry. Applying match_pathspec() to multiple arguments can cost more than the lstat() calls it avoids. In a synthetic repository with 10,000 clean files, passing every path to ls-files --modified increased runtime from 112.5 ms to 494.1 ms when the prefilter was unconditional. With $parent and $this exported as paths to binaries built from the parent and this commit, on a repository with 881,290 index entries: hyperfine --warmup 0 --runs 3 \ --command-name parent \ '$parent -c core.fsmonitor=false ls-files --deleted -- README.md >/dev/null' \ --command-name this-commit \ '$this -c core.fsmonitor=false ls-files --deleted -- README.md >/dev/null' reported means of 65.790 seconds for the parent and 4.987 seconds for this commit. Link: https://lore.kernel.org/r/xmqqfr2tnfk0.fsf@gitster.g Helped-by: Jeff King <peff@peff.net> Signed-off-by: Tamir Duberstein <tamird@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-12environment: move 'protect_hfs' and 'protect_ntfs' into 'repo_config_values'Tian Yuchen5-19/+48
Move the global 'protect_hfs' and 'protect_ntfs' configurations into the repository-specific 'repo_config_values' struct. This will help with the elimination of 'the_repository' To ensure code readability, the getter functions 'repo_protect_hfs()' and 'repo_protect_ntfs()' have been introduced. For now, associated functions access this configuration by explicitly falling back to 'the_repository', which needs to be addressed in the future. Note: In 't/helper/test-path-utils.c', there is a function 'protect_ntfs_hfs_benchmark()' where these two global variables are used as loop iterators. New local variables have been created to replace them. Mentored-by: Christian Couder <christian.couder@gmail.com> Mentored-by: Ayush Chandekar <ayu.chandekar@gmail.com> Mentored-by: Olamide Caleb Bello <belkid98@gmail.com> Signed-off-by: Tian Yuchen <cat@malon.dev> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-06-12Merge branch 'master' of https://github.com/j6t/git-guiJunio C Hamano3-179/+224
* 'master' of https://github.com/j6t/git-gui: git-gui: silence install recipes under "make -s" git-gui: add gui and pick as explicit subcommands git-gui: check browser/blame arguments carefully git-gui: allow specifying path '.' to the browser git-gui: try harder to find worktree from gitdir git-gui: simplify [is_bare] to report if a worktree is known git-gui: use git rev-parse for worktree discovery git-gui: use rev-parse exclusively to find a repository git-gui: use --absolute-git-dir git-gui: do not change global vars in choose_repository::pick git-gui: guard set/unset of GIT_DIR and GIT_WORK_TREE git-gui: remove unnecessary 'cd $_gitworktree' from do_gitk git-gui: use HEAD as current branch when detached
2026-06-12Merge branch 'master' of https://github.com/j6t/gitkJunio C Hamano1-2/+5
* 'master' of https://github.com/j6t/gitk: gitk: add horizontal scrollbar to the commit list pane
2026-06-12Merge branch 'horizontal-scroll' of github.com:ramcdona/gitkJohannes Sixt1-2/+5
* 'horizontal-scroll' of github.com:ramcdona/gitk: gitk: add horizontal scrollbar to the commit list pane Signed-off-by: Johannes Sixt <j6t@kdbg.org>