summaryrefslogtreecommitdiff
AgeCommit message (Collapse)AuthorFilesLines
2025-03-26Merge branch 'ua/some-builtins-wo-the-repository'Junio C Hamano16-61/+116
A handful of built-in command implementations have been rewritten to use the repository instance supplied by git.c:run_builtin(), its caller. * ua/some-builtins-wo-the-repository: builtin/checkout-index: stop using `the_repository` builtin/for-each-ref: stop using `the_repository` builtin/ls-files: stop using `the_repository` builtin/pack-refs: stop using `the_repository` builtin/send-pack: stop using `the_repository` builtin/verify-commit: stop using `the_repository` builtin/verify-tag: stop using `the_repository` config: teach repo_config to allow `repo` to be NULL
2025-03-26Merge branch 'tb/refs-exclude-fixes'Junio C Hamano2-2/+44
The refname exclusion logic in the packed-ref backend has been broken for some time, which confused upload-pack to advertise different set of refs. This has been corrected. * tb/refs-exclude-fixes: refs.c: stop matching non-directory prefixes in exclude patterns refs.c: remove empty '--exclude' patterns
2025-03-26Merge branch 'sj/ref-consistency-checks-more'Junio C Hamano9-452/+1131
"git fsck" becomes more careful when checking the refs. * sj/ref-consistency-checks-more: builtin/fsck: add `git refs verify` child process packed-backend: check whether the "packed-refs" is sorted packed-backend: add "packed-refs" entry consistency check packed-backend: check whether the refname contains NUL characters packed-backend: add "packed-refs" header consistency check packed-backend: check if header starts with "# pack-refs with: " packed-backend: check whether the "packed-refs" is regular file builtin/refs: get worktrees without reading head information t0602: use subshell to ensure working directory unchanged
2025-03-26Merge branch 'jt/diff-pairs'Junio C Hamano13-21/+449
A post-processing filter for "diff --raw" output has been introduced. * jt/diff-pairs: builtin/diff-pairs: allow explicit diff queue flush builtin: introduce diff-pairs command diff: add option to skip resolving diff statuses diff: return diff_filepair from diff queue helpers
2025-03-25mergetools: vimdiff: add tests for layout with REMOTE as the targetFernando Ramos1-1/+10
Add some tests to make sure that now "REMOTE" can be used as a target (ie. can be used together with the "@" marker) inside "mergetool.vimdiff.layout" Signed-off-by: Fernando Ramos <greenfoo@u92.eu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-25mergetools: vimdiff: fix layout where REMOTE is the targetFernando Ramos1-0/+3
"mergetool.vimdiff.layout" is used to define the vim layout (ie. how windows, tabs and buffers are physically organized) when resolving conflicts. For example, if we set it to this: "(LOCAL,BASE,REMOTE)/MERGED" ...vim will open and show this layout: ------------------------------------------ | | | | | LOCAL | BASE | REMOTE | | | | | ------------------------------------------ | | | MERGED | | | ------------------------------------------ By default, whatever ends up been written to the "MERGED" window will become the file which conflict we are resolving. However, it is possible to use the "@" symbol to specify a different one. For example, if we use this slightly different version of the previously used string: "(LOCAL,BASE,@REMOTE)/MERGED" ...then the user should proceed to edit the contents of the top right window (instead of the bottom window) as *that* is what will become the conflicts free file once vim is closed. Before this commit, the "@" marker worked for all targets *except* for "REMOTE". In other words, these worked as expected: "(@LOCAL,BASE,REMOTE)/MERGED" "(LOCAL,@BASE,REMOTE)/MERGED" "(LOCAL,BASE,REMOTE)/@MERGED" ...but this didn't: "(LOCAL,BASE,@REMOTE)/MERGED" This commit fixes that. Reported-by: kawarimidoll <kawarimidoll+git@gmail.com> Suggested-by: D. Ben Knoble <ben.knoble@gmail.com> Signed-off-by: Fernando Ramos <greenfoo@u92.eu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-25meson: disable coccinelle configuration when building from a tarballEli Schwartz1-1/+6
Wiring up coccinelle in the build, depends on running git commands to get the list of files to operate on. Reasonable, for a feature mainly used by people developing on git. If building git itself from a tarball distribution of git's own source code, one likely does not need to run coccinelle. But running those git commands failed, and caused the build to error out, if `spatch` was installed -- because the build assumed that its presence indicated a desire to use it on this source tree. Instead, we can expand the conditional to check for both `spatch` and the `.git` file or directory. Meson's `opt.require()` method allows us to add a prerequisite for the feature option. If the prerequisite fails, then the option either: - converts autodetection to disabled - emits an informative error if the feature was set to enabled: ``` ERROR: Feature coccinelle cannot be enabled: coccinelle can only be run from a git checkout ``` Signed-off-by: Eli Schwartz <eschwartz@gentoo.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-25vimdiff: clarify the sigil used for marking the buffer to saveD. Ben Knoble1-1/+1
The original documentation from 7b5cf8be18 (vimdiff: add tool documentation, 2022-03-30) mistakenly described the marker as an asterisk, which is the character "*". The code and examples have always looked for an arobase ("@"). Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com> Acked-by: Fernando Ramos <greenfoo@u92.eu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-25advice: allow disabling default branch name adviceJustin Tobler4-1/+12
The default branch name advice message is displayed when `repo_default_branch_name()` is invoked and the `init.defaultBranch` config is not set. In this scenario, the advice message is always shown even if the `--no-advice` option is used. Adapt `repo_default_branch_name()` to allow the default branch name advice message to be disabled with the `--no-advice` option and corresponding configuration. Signed-off-by: Justin Tobler <jltobler@gmail.com> Acked-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-25builtin/clone: suppress unexpected default branch adviceJustin Tobler2-2/+17
In 199f44cb2ead (builtin/clone: allow remote helpers to detect repo, 2024-02-27), clones started partially initializing the refdb before executing the remote helpers by creating a HEAD file and "refs/" directory. This has resulted in some scenarios where git-clone(1) now prints the default branch name advice message where it previously did not. A side-effect of the HEAD file already existing, is that computation of the default branch name is handled later in execution. This matters because prior to 97abaab5f6 (refs: drop `git_default_branch_name()`, 2024-05-17), the default branch value would be computed during its first execution and cached. Subsequent invocations would simply return the cached value. Since the next `git_default_branch_name()` call site, which is invoked through `guess_remote_head()`, is not configured to suppress the advice message, computing the default branch name results in the advice message being printed. Configure `guess_remote_head()` to suppress the advice message, restoring the previous behavior. Signed-off-by: Justin Tobler <jltobler@gmail.com> Acked-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-25remote: allow `guess_remote_head()` to suppress adviceJustin Tobler4-10/+15
The `repo_default_branch_name()` invoked through `guess_remote_head()` is configured to always display the default branch advice message. Adapt `guess_remote_head()` to accept flags and convert the `all` parameter to a flag. Add the `REMOTE_GUESS_HEAD_QUIET` flag to to enable suppression of advice messages. Call sites are updated accordingly. Signed-off-by: Justin Tobler <jltobler@gmail.com> Acked-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-25bulk-checkin: fix sign compare warningsTuomas Ahola1-10/+6
In file bulk-checkin.c, three warnings are emitted by "-Wsign-compare", two of which are caused by trivial loop iterator type mismatches. For the third case, the type of `rsize` from ssize_t rsize = size < sizeof(ibuf) ? size : sizeof(ibuf); can be changed to size_t as both options of the ternary expression are unsigned and the signedness of the variable isn't really needed anywhere. To prevent `read_result != rsize` making a clash, it is to be noted that `read_result` is checked not to hold negative values. Therefore casting the variable to size_t is a safe operation and enough to remove the sign-compare warning. Fix issues accordingly, and remove `DISABLE_SIGN_COMPARE_WARNINGS` to enable "-Wsign-compare" for the file. Signed-off-by: Tuomas Ahola <taahol@utu.fi> Acked-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-25imap-send: explicitly verify the peer certificateJohannes Schindelin1-0/+2
It is a bug to obtain the peer certificate without verifying it. Having said that, from my reading of https://www.openssl.org/docs/man1.1.1/man3/SSL_set_verify.html, it would appear that Git is saved by the fact that it calls `SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL)` already early on. In other words, that `SSL_VERIFY_PEER` combined with the `NULL` parameter (i.e. no overridden callback) would _already_ verify the peer certificate. The fact that we later call `SSL_get_peer_certificate()` is mistaken by CodeQL to mean that that peer certificate still needs to be verified, but that had already happened at that point. Nevertheless, it is better to verify the peer certificate explicitly than to rely on some side effect that is really hard to reason about (and that took me more than one business day to analyze fully). It also makes it easier for static analyzers to validate the correctness of the code. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-25test-tool path-utils: support debugging "dubious ownership" issuesJohannes Schindelin1-0/+19
This adds a new sub-sub-command for `test-tool`, simply passing through the command-line arguments to the `is_path_owned_by_current_user()` function. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-25mingw: special-case administrators even moreJohannes Schindelin1-11/+28
The check for dubious ownership has one particular quirk on Windows: if running as an administrator, files owned by the Administrators _group_ are considered owned by the user. The rationale for that is: When running in elevated mode, Git creates files that aren't owned by the individual user but by the Administrators group. There is yet another quirk, though: The check I introduced to determine whether the current user is an administrator uses the `CheckTokenMembership()` function with the current process token. And that check only succeeds when running in elevated mode! Let's be a bit more lenient here and look harder whether the current user is an administrator. We do this by looking for a so-called "linked token". That token exists when administrators run in non-elevated mode, and can be used to create a new process in elevated mode. And feeding _that_ token to the `CheckTokenMembership()` function succeeds! Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-23maintenance: add loose-objects.batchSize configDerrick Stolee4-7/+54
The 'loose-objects' task of 'git maintenance run' first deletes loose objects that exit within packfiles and then collects loose objects into a packfile. This second step uses an implicit limit of fifty thousand that cannot be modified by users. Add a new config option that allows this limit to be adjusted or ignored entirely. While creating tests for this option, I noticed that actually there was an off-by-one error due to the strict comparison in the limit check. I considered making the limit check turn true on equality, but instead I thought to use INT_MAX as a "no limit" barrier which should mean it's never possible to hit the limit. Thus, a new decrement to the limit is provided if the value is positive. (The restriction to positive values is to avoid underflow if INT_MIN is configured.) Signed-off-by: Derrick Stolee <stolee@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-23maintenance: force progress/no-quiet to childrenDerrick Stolee1-0/+10
The --no-quiet option for 'git maintenance run' is supposed to indicate that progress should happen even while ignoring the value of isatty(2). However, Git implicitly asks child processes to check isatty(2) since these arguments are not passed through. The pass through of --no-quiet will be useful in a test in the next change. Signed-off-by: Derrick Stolee <stolee@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-23completion: fix bugs with slashes in remote namesDavid Mandelberg2-29/+189
Previously, some calls to for-each-ref passed fixed numbers of path components to strip from refs, assuming that remote names had no slashes in them. This made completions like: git push github/dseomn :com<Tab> Result in: git push github/dseomn :dseomn/completion-remote-slash With this patch, it instead results in: git push github/dseomn :completion-remote-slash Signed-off-by: David Mandelberg <david@mandelberg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-23completion: add helper to count path componentsDavid Mandelberg2-0/+37
A follow-up commit will use this with for-each-ref to strip the right number of path components from refnames. Signed-off-by: David Mandelberg <david@mandelberg.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-24commit: move clear_commit_marks_many() loop body to clear_commit_marks()René Scharfe1-9/+7
clear_commit_marks_many() clears multiple commits one by one. Move the code for handling a single commit to clear_commit_marks() and call it instead of the other way around, to simplify the code. Signed-off-by: René Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21midx: implement writing incremental MIDX bitmapsTaylor Blau5-37/+179
Now that the pack-bitmap machinery has learned how to read and interact with an incremental MIDX bitmap, teach the pack-bitmap-write.c machinery (and relevant callers from within the MIDX machinery) to write such bitmaps. The details for doing so are mostly straightforward. The main changes are as follows: - find_object_pos() now makes use of an extra MIDX parameter which is used to locate the bit positions of objects which are from previous layers (and thus do not exist in the current layer's pack_order field). (Note also that the pack_order field is moved into struct write_midx_context to further simplify the callers for write_midx_bitmap()). - bitmap_writer_build_type_index() first determines how many objects precede the current bitmap layer and offsets the bits it sets in each respective type-level bitmap by that amount so they can be OR'd together. Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21pack-bitmap.c: use `ewah_or_iterator` for type bitmap iteratorsTaylor Blau1-15/+27
Now that we have initialized arrays for each bitmap layer's type bitmaps in the previous commit, adjust existing callers to use them in preparation for multi-layered bitmaps. Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21pack-bitmap.c: keep track of each layer's type bitmapsTaylor Blau1-4/+53
Prepare for reading the type-level bitmaps from previous bitmap layers by maintaining an array for each type, where each element in that type's array corresponds to one layer's bitmap for that type. These fields will be used in a later commit to instantiate the 'struct ewah_or_iterator' for each type. Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21ewah: implement `struct ewah_or_iterator`Taylor Blau2-0/+45
While individual bitmap layers store different commit, type-level, and pseudo-merge bitmaps, only the top-most layer is used to compute reachability traversals. Many functions which implement the aforementioned traversal rely on enumerating the results according to the type-level bitmaps, and so would benefit from a conceptual type-level bitmap that spans multiple layers. Implement `struct ewah_or_iterator` which is capable of enumerating multiple EWAH bitmaps at once, and OR-ing the results together. When initialized with, for example, all of the commit type bitmaps from each layer, callers can pretend as if they are enumerating a large type-level bitmap which contains the commits from *all* bitmap layers. There are a couple of alternative approaches which were considered: - Decompress each EWAH bitmap and OR them together, enumerating a single (non-EWAH) bitmap. This would work, but has the disadvantage of decompressing a potentially large bitmap, which may not be necessary if the caller does not wish to read all of it. - Recursively call bitmap internal functions, reusing the "result" and "haves" bitmap from the top-most layer. This approach resembles the original implementation of this feature, but is inefficient in that it both (a) requires significant refactoring to implement, and (b) enumerates large sections of later bitmaps which are all zeros (as they pertain to objects in earlier layers). (b) is not so bad in and of itself, but can cause significant slow-downs when combined with expensive loop bodies. This approach (enumerating an OR'd together version of all of the type-level bitmaps from each layer) produces a significantly more straightforward implementation with significantly less refactoring required in order to make it work. Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21pack-bitmap.c: apply pseudo-merge commits with incremental MIDXsTaylor Blau1-3/+8
Prepare for using pseudo-merges with incremental MIDX bitmaps by attempting to apply pseudo-merges from each layer when encountering a given commit during a walk. Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21pack-bitmap.c: compute disk-usage with incremental MIDXsTaylor Blau1-2/+2
In a similar fashion as previous commits, use nth_midxed_pack() instead of accessing the MIDX's ->packs array directly to support incremental MIDXs. Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21pack-bitmap.c: teach `rev-list --test-bitmap` about incremental MIDXsTaylor Blau1-21/+86
Implement support for the special `--test-bitmap` mode of `git rev-list` when using incremental MIDXs. The bitmap_test_data structure is extended to contain a "base" pointer that mirrors the structure of the bitmap chain that it is being used to test. When we find a commit to test, we first chase down the ->base pointer to find the appropriate bitmap_test_data for the bitmap layer that the given commit is contained within, and then perform the test on that bitmap. In order to implement this, light modifications are made to bitmap_for_commit() to reimplement it in terms of a new function, find_bitmap_for_commit(), which fills out a pointer which indicates the bitmap layer which contains the given commit. Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21pack-bitmap.c: support bitmap pack-reuse with incremental MIDXsTaylor Blau1-3/+8
In a similar fashion as previous commits in the first phase of incremental MIDXs, enumerate not just the packs in the current incremental MIDX layer, but previous ones as well. Likewise, in reuse_partial_packfile_from_bitmap(), when reusing only a single pack from a MIDX, use the oldest layer's preferred pack as it is likely to contain the largest number of reusable sections. Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21pack-bitmap.c: teach `show_objects_for_type()` about incremental MIDXsTaylor Blau1-1/+1
Since we may ask for a pack_id that is in an earlier MIDX layer relative to the one corresponding to our bitmap, use nth_midxed_pack() instead of accessing the ->packs array directly. Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21pack-bitmap.c: teach `bitmap_for_commit()` about incremental MIDXsTaylor Blau1-4/+7
The pack-bitmap machinery uses `bitmap_for_commit()` to locate the EWAH-compressed bitmap corresponding to some given commit object. Teach this function about incremental MIDX bitmaps by teaching it to recur on earlier bitmap layers when it fails to find a given commit in the current layer. The changes to do so are as follows: - Avoid initializing hash_pos at its declaration, since bitmap_for_commit() is now a recursive function and may receive a NULL bitmap_index pointer as its first argument. - In cases where we would previously return NULL (to indicate that a lookup failed and the given bitmap_index does not contain an entry corresponding to the given commit), recursively call the function on the previous bitmap layer. Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21pack-bitmap.c: open and store incremental bitmap layersTaylor Blau1-14/+48
Prepare the pack-bitmap machinery to work with incremental MIDXs by adding a new "base" field to keep track of the bitmap index associated with the previous MIDX layer. The changes in this commit are mostly boilerplate to open the correct bitmap(s), add them to the chain of bitmap layers along the "base" pointer, ensure that the correct packs and their reverse indexes are loaded across MIDX layers, etc. While we're at it, keep track of a base_nr field to indicate how many bitmap layers (including the current bitmap) exist. This will be used in a future commit to allocate an array of 'struct ewah_bitmap' pointers to collect all of the respective type bitmaps among all layers to initialize a multi-EWAH iterator. Subsequent commits will teach the functions within the pack-bitmap machinery how to interact with these new fields. Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21pack-revindex: prepare for incremental MIDX bitmapsTaylor Blau2-21/+56
Prepare the reverse index machinery to handle object lookups in an incremental MIDX bitmap. These changes are broken out across a few functions: - load_midx_revindex() learns to use the appropriate MIDX filename depending on whether the given 'struct multi_pack_index *' is incremental or not. - pack_pos_to_midx() and midx_to_pack_pos() now both take in a global object position in the MIDX pseudo-pack order, and find the earliest containing MIDX (similar to midx.c::midx_for_object(). - midx_pack_order_cmp() adjusts its call to pack_pos_to_midx() by the number of objects in the base (since 'vb - midx->revindx_data' is relative to the containing MIDX, and pack_pos_to_midx() expects a global position). Likewise, this function adjusts its output by adding m->num_objects_in_base to return a global position out through the `*pos` pointer. Together, these changes are sufficient to use the multi-pack index's reverse index format for incremental multi-pack reachability bitmaps. Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21Documentation: describe incremental MIDX bitmapsTaylor Blau1-0/+72
Prepare to implement support for reachability bitmaps for the new incremental multi-pack index (MIDX) feature over the following commits. This commit begins by first describing the relevant format and usage details for incremental MIDX bitmaps. Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21Documentation: remove a "future work" item from the MIDX docsTaylor Blau1-10/+0
One of the items listed as "future work" in the MIDX's technical documentation is to extend the format to allow MIDXs to be written incrementally across multiple layers. This was suggested all the way back in ceab693d1f (multi-pack-index: add design document, 2018-07-12), and implemented in b9497848df (Merge branch 'tb/incremental-midx-part-1', 2024-08-19). Let's remove it accordingly. Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21compat/mingw: fix EACCESS when opening files with `O_CREAT | O_EXCL`Patrick Steinhardt1-0/+20
In our CI systems we can observe that t0610 fails rather frequently. This testcase races a bunch of git-update-ref(1) processes with one another which are all trying to update a unique reference, where we expect that all processes succeed and end up updating the reftable stack. The error message in this case looks like the following: fatal: update_ref failed for ref 'refs/heads/branch-88': reftable: transaction prepare: I/O error Instrumenting the code with a couple of calls to `BUG()` in relevant sites where we return `REFTABLE_IO_ERROR` quickly leads one to discover that this error is caused when calling `flock_acquire()`, which is a thin wrapper around our lockfile API. Curiously, the error code we get in such cases is `EACCESS`, indicating that we are not allowed to access the file. The root cause of this is an oddity of `CreateFileW()`, which is what `_wopen()` uses internally. Quoting its documentation [1]: If you call CreateFile on a file that is pending deletion as a result of a previous call to DeleteFile, the function fails. The operating system delays file deletion until all handles to the file are closed. GetLastError returns ERROR_ACCESS_DENIED. This behaviour is triggered quite often in the above testcase because all the processes race with one another trying to acquire the lock for the "tables.list" file. This is due to how locking works in the reftable library when compacting a stack: 1. Lock the "tables.list" file and reads its contents. 2. Decide which tables to compact. 3. Lock each of the individual tables that we are about to compact. 4. Unlock the "tables.list" file. 5. Compact the individual tables into one large table. 6. Re-lock the "tables.list" file. 7. Write the new list of tables into it. 8. Commit the "tables.list" file. The important step is (4): we don't commit the file directly by renaming it into place, but instead we delete the lockfile so that concurrent processes can continue to append to the reftable stack while we compact the tables. And because we use `DeleteFileW()` to do so, we may now race with another process that wants to acquire that lockfile. So if we are unlucky, we would now see `ERROR_ACCESS_DENIED` instead of the expected `ERROR_FILE_EXISTS`, which the lockfile subsystem isn't prepared to handle and thus it will bail out without retrying to acquire the lock. In theory, the issue is not limited to the reftable library and can be triggered by every other user of the lockfile subsystem, as well. My gut feeling tells me it's rather unlikely to surface elsewhere though. Fix the issue by translating the error to `EEXIST`. This makes the lockfile subsystem handle the error correctly: in case a timeout is set it will now retry acquiring the lockfile until the timeout has expired. With this, t0610 is now always passing on my machine whereas it was previously failing in around 20-30% of all test runs. [1]: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21meson: fix compat sources when compiling with MSVCPatrick Steinhardt1-1/+3
In our compat library we have both "msvc.c" and "mingw.c". The former is mostly a thin wrapper around the latter as it directly includes it, but it has a couple of extra headers that aren't included in "mingw.c" and is expected to be used with the Visual Studio compiler toolchain. While our Makefile knows to pick up the correct file depending on whether or not the Visual Studio toolchain is used, we don't do the same with Meson. Fix this. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21builtin/fetch: avoid aborting closed reference transactionJustin Tobler2-1/+21
As part of the reference transaction commit phase, the transaction is set to a closed state regardless of whether it was successful of not. Attempting to abort a closed transaction via `ref_transaction_abort()` results in a `BUG()`. In c92abe71df (builtin/fetch: fix leaking transaction with `--atomic`, 2024-08-22), logic to free a transaction after the commit phase is moved to the centralized exit path. In cases where the transaction commit failed, this results in a closed transaction being aborted and signaling a bug. Free the transaction and set it to NULL when the commit fails. This allows the exit path to correctly handle the error without attempting to abort the transaction. Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21repack: begin combining cruft packs with `--combine-cruft-below-size`Taylor Blau3-22/+47
The previous commit changed the behavior of repack's '--max-cruft-size' to specify a cruft pack-specific override for '--max-pack-size'. Introduce a new flag, '--combine-cruft-below-size' which is a replacement for the old behavior of '--max-cruft-size'. This new flag does explicitly what it says: it combines together cruft packs which are smaller than a given threshold, and leaves alone ones which are larger. This accomplishes the original intent of '--max-cruft-size', which was to avoid repacking cruft packs larger than the given threshold. The new behavior is slightly different. Instead of building up small packs together until the threshold is met, '--combine-cruft-below-size' packs up *all* cruft packs smaller than the threshold. This means that we may make a pack much larger than the given threshold (e.g., if you aggregate 5 packs which are each 99 MiB in size with a threshold of 100 MiB). But that's OK: the point isn't to restrict the size of the cruft packs we generate, it's to avoid working with ones that have already grown too large. If repositories still want to limit the size of the generated cruft pack(s), they may use '--max-cruft-size'. There's some minor test fallout as a result of the slight differences in behavior between the old meaning of '--max-cruft-size' and the behavior of '--combine-cruft-below-size'. In the test which is now called "--combine-cruft-below-size combines packs", we need to use the new flag over the old one to exercise that test's intended behavior. The remainder of the changes there are to improve the clarity of the comments. Suggested-by: Elijah Newren <newren@gmail.com> Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21repack: avoid combining cruft packs with `--max-cruft-size`Taylor Blau4-55/+67
In 37dc6d8104 (builtin/repack.c: implement support for `--max-cruft-size`, 2023-10-02), we exposed new functionality that allowed repositories to specify the behavior of when we should combine multiple cruft packs together. This feature was designed to ensure that we never repacked cruft packs which were larger than the given threshold in order to provide tighter I/O bounds for repositories that have many unreachable objects. In essence, specifying '--max-cruft-size=N' instructed 'repack' to aggregate cruft packs together (in order of ascending size) until the combine size grows past 'N', and then make a new cruft pack whose contents includes the packs we rolled up. But this isn't quite how it works in practice. Suppose for example that we have two cruft packs which are each 100MiB in size. One might expect specifying "--max-cruft-size=200M" would combine these two packs together, and then avoid repacking them until a pruning GC takes place. In reality, 'repack' would try and aggregate these together, but writing a pack that is strictly smaller than 200 MiB (since pack-objects' "--max-pack-size" provides a strict bound for packs containing more than one object). So instead we'll write out a pack that is, say, 199 MiB in size, and then another 1 MiB pack containing the balance. If we later repack the repository without adding any new unreachable objects, we'll repeat the same exercise again, making the same 199 MiB and 1 MiB packs each time. This happens because of a poor choice to bolt the '--max-cruft-size' functionality onto pack-objects' '--max-pack-size', forcing us to generate packs which are always smaller than the provided threshold and thus subject to repacking. The following commit will introduce a new flag that implements something similar to the behavior above. Let's prepare for that by making repack's '--max-cruft-size' flag behave as an cruft pack-specific override for '--max-pack-size'. Do so by temporarily repurposing the 'collapse_small_cruft_packs()' function to instead generate a cruft pack using the same instructions as if we didn't specify any maximum pack size. The calling code looks something like: if (args->max_pack_size && !cruft_expiration) { collapse_small_cruft_packs(in, args->max_pack_size, existing); } else { for_each_string_list_item(item, &existing->non_kept_packs) fprintf(in, "-%s.pack\n", item->string); for_each_string_list_item(item, &existing->cruft_packs) fprintf(in, "-%s.pack\n", item->string); } This patch makes collapse_small_cruft_packs() behave identically to the 'else' arm of the conditional above. This repurposing of 'collapse_small_cruft_packs()' is intentional, since it will set us up nicely to introduce the new behavior in the following commit. Naturally, there is some test fallout in the test which exercises the old meaning of '--max-cruft-size'. Mark that test as failing for now to be dealt with in the following commit. Likewise, add a new test which explicitly tests the behavior of '--max-cruft-size' to place a hard limit on the size of any generated cruft pack(s). Note that this is a breaking change, as it alters the user-visible behavior of '--max-cruft-size'. But I'm OK changing this behavior in this instance, since the behavior wasn't accurate to begin with. Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21t/t7704-repack-cruft.sh: consolidate `write_blob()`Taylor Blau1-7/+2
A previous commit moved a handful of tests from a different script into t7704, including one that relies on generating random blobs. Incidentally, the original home of this test defined its own helper "write_blob" for doing so, which is identical in function to our "generate_random_blob" (and is slightly inferior to the latter, which cleans up after itself). Rewrite the test that uses "write_blob" to no longer do so and then remove the function. Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21t/t7704-repack-cruft.sh: clarify wording in --max-cruft-size testsTaylor Blau1-10/+10
Now that a number of new tests have landed in t7704, make sure that they all make sense and are testing the things they say they are. Things are mostly OK, but a handful of tests needed tweaks. Those tweaks are as follows: - Use the terms "too large" or "too small" in tests that exercise the '--max-cruft-size' behavior. This has historically been treated as a threshold beneath which to combine cruft packs, but that will change in a subsequent commit. Prepare for that by using a more generic term. - Remove references to "--max-cruft-size" in the freshening tests. These tests provide coverage of our ability to record updated mtimes for objects already in cruft packs whose mtimes are upserted from various sources (loose objects, finding that object in a new pack, another cruft pack, etc.). These have nothing to do with the '--max-cruft-size' feature, and in fact none of the tests even *use* '--max-cruft-size'. Name them appropriately to make it clear that these tests exercise freshening behavior, not '--max-cruft-size' behavior. Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21t/t5329-pack-objects-cruft.sh: evict 'repack'-related testsTaylor Blau2-250/+250
The cruft pack feature has two primary test scripts which exercise various parts of it, which are: - t5329-pack-objects-cruft.sh - t7704-repack-cruft.sh The former is designed to test low-level pack generation mechanics at the 'git pack-objects --cruft'-level, which is plumbing. The latter, on the other hand, is designed to test the user-facing behavior through 'git repack --cruft', which is porcelain (under the "ancillary manipulators" sub-section). At some point a handful of tests which should have been added to the latter script were instead written to the former. This isn't a huge deal, but rectifying it is straightforward. Move a handful of 'repack'-related tests out of t5329 and into their rightful home in t7704. Signed-off-by: Taylor Blau <me@ttaylorr.com> Acked-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21rev-list: support NUL-delimited --missing optionJustin Tobler3-11/+56
The `--missing={print,print-info}` option for git-rev-list(1) prints missing objects found while performing the object walk in the form: $ git rev-list --missing=print-info <rev> ?<oid> [SP <token>=<value>]... LF Add support for printing missing objects in a NUL-delimited format when the `-z` option is enabled. $ git rev-list -z --missing=print-info <rev> <oid> NUL missing=yes NUL [<token>=<value> NUL]... In this mode, values containing special characters or spaces are printed as-is without being escaped or quoted. Instead of prefixing the missing OID with '?', a separate `missing=yes` token/value pair is appended. Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21rev-list: support NUL-delimited --boundary optionJustin Tobler3-7/+30
The `--boundary` option for git-rev-list(1) prints boundary objects found while performing the object walk in the form: $ git rev-list --boundary <rev> -<oid> LF Add support for printing boundary objects in a NUL-delimited format when the `-z` option is enabled. $ git rev-list -z --boundary <rev> <oid> NUL boundary=yes NUL In this mode, instead of prefixing the boundary OID with '-', a separate `boundary=yes` token/value pair is appended. Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21rev-list: support delimiting objects with NUL bytesJustin Tobler3-5/+86
When walking objects, git-rev-list(1) prints each object entry on a separate line. Some options, such as `--objects`, may print additional information about tree and blob object on the same line in the form: $ git rev-list --objects <rev> <tree/blob oid> SP [<path>] LF Note that in this form the SP is appended regardless of whether the tree or blob object has path information available. Paths containing a newline are also truncated at the newline. Introduce the `-z` option for git-rev-list(1) which reformats the output to use NUL-delimiters between objects and associated info in the following form: $ git rev-list -z --objects <rev> <oid> NUL [path=<path> NUL] In this form, the start of each record is signaled by an OID entry that is all hexidecimal and does not contain any '='. Additional path info from `--objects` is appended to the record as a token/value pair `path=<path>` as-is without any truncation. For now, the `--objects` flag is the only options that can be used in combination with `-z`. In a subsequent commit, NUL-delimited support for other options is added. Other options that do not make sense when used in combination with `-z` are rejected. Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21rev-list: refactor early option parsingJustin Tobler1-10/+7
Before invoking `setup_revisions()`, the `--missing` and `--exclude-promisor-objects` options are parsed early. In a subsequent commit, another option is added that must be parsed early. Refactor the code to parse both options in a single early pass. Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21rev-list: inline `show_object_with_name()` in `show_object()`Justin Tobler3-14/+9
The `show_object_with_name()` function only has a single call site. Inline call to `show_object_with_name()` in `show_object()` so the explicit function can be cleaned up and live closer to where it is used. While at it, factor out the code that prints the OID and newline for both objects with and without a name. In a subsequent commit, `show_object()` is modified to support printing object information in a NUL-delimited format. Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21treewide: replace assert() with ASSERT() in special casesElijah Newren7-9/+9
When the compiler/linker cannot verify that an assert() invocation is free of side effects for us (e.g. because the assertion includes some kind of function call), replace the use of assert() with ASSERT(). Signed-off-by: Elijah Newren <newren@gmail.com> Acked-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21ci: add build checking for side-effects in assert() callsElijah Newren4-0/+30
It is a big no-no to have side-effects in an assertion, because if the assert() is compiled out, you don't get that side-effect, leading to the code behaving differently. That can be a large headache to debug. We have roughly 566 assert() calls in our codebase (my grep might have picked up things that aren't actually assert() calls, but most appeared to be). All but 9 of them can be determined by gcc to be free of side effects with a clever redefine of assert() provided by Bruno De Fraine (from https://stackoverflow.com/questions/10593492/catching-assert-with-side-effects), who upon request has graciously placed his two-liner into the public domain without warranty of any kind. The current 9 assert() calls flagged by this clever redefinition of assert() appear to me to be free of side effects as well, but are too complicated for a compiler/linker to figure that since each assertion involves some kind of function call. Add a CI job which will find and report these possibly problematic assertions, and have the job suggest to the user that they replace these with ASSERT() calls. Example output from running: ``` ERROR: The compiler could not verify the following assert() calls are free of side-effects. Please replace with ASSERT() calls. /home/newren/floss/git/diffcore-rename.c:1409 assert(!dir_rename_count || strmap_empty(dir_rename_count)); /home/newren/floss/git/merge-ort.c:1645 assert(renames->deferred[side].trivial_merges_okay && !strset_contains(&renames->deferred[side].target_dirs, path)); /home/newren/floss/git/merge-ort.c:794 assert(omittable_hint == (!starts_with(type_short_descriptions[type], "CONFLICT") && !starts_with(type_short_descriptions[type], "ERROR")) || type == CONFLICT_DIR_RENAME_SUGGESTED); /home/newren/floss/git/merge-recursive.c:1200 assert(!merge_remote_util(commit)); /home/newren/floss/git/object-file.c:2709 assert(would_convert_to_git_filter_fd(istate, path)); /home/newren/floss/git/parallel-checkout.c:280 assert(is_eligible_for_parallel_checkout(pc_item->ce, &pc_item->ca)); /home/newren/floss/git/scalar.c:244 assert(have_fsmonitor_support()); /home/newren/floss/git/scalar.c:254 assert(have_fsmonitor_support()); /home/newren/floss/git/sequencer.c:4968 assert(!(opts->signoff || opts->no_commit || opts->record_origin || should_edit(opts) || opts->committer_date_is_author_date || opts->ignore_date)); ``` Note that if there are possibly problematic assertions, not necessarily all of them will be shown in a single run, because the compiler errors may include something like "ld: ... more undefined references to `not_supposed_to_survive' follow" instead of listing each individually. But in such cases, once you clean up a few that are shown in your first run, subsequent runs will show (some of) the ones that remain, allowing you to iteratively remove them all. Helped-by: Bruno De Fraine <defraine@gmail.com> Signed-off-by: Elijah Newren <newren@gmail.com> Acked-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2025-03-21git-compat-util: introduce ASSERT() macroElijah Newren1-0/+2
Create a ASSERT() macro which is similar to assert(), but will not be compiled out when NDEBUG is defined, and is thus safe to use even if its argument has side-effects. We will use this new macro in a subsequent commit to convert a few existing assert() invocations to ASSERT(). In particular, we'll convert the handful of invocations which cannot be proven to be free of side effects with a simple compiler/linker hack. Signed-off-by: Elijah Newren <newren@gmail.com> Acked-by: Taylor Blau <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>