summaryrefslogtreecommitdiff
AgeCommit message (Collapse)AuthorFilesLines
2026-02-20Merge branch 'lo/repo-info-keys' into lo/repo-leftover-bitsJunio C Hamano4-34/+97
* lo/repo-info-keys: repo: add new flag --keys to git-repo-info repo: rename the output format "keyvalue" to "lines"
2026-02-20ref-filter: clarify lstrip/rstrip component countingJeff King1-6/+7
When a strip option to the %(refname) placeholder is asked to leave N path components, we first count up the path components to know how many to remove. That happens with a loop like this: /* Find total no of '/' separated path-components */ for (i = 0; p[i]; p[i] == '/' ? i++ : *p++) ; which is a little hard to understand for two reasons. First, the dereference in "*p++" is seemingly useless, since nobody looks at the result. And static analyzers like Coverity will complain about that. But removing the "*" will cause gcc to complain with -Wint-conversion, since the two sides of the ternary do not match (one is a pointer and the other an int). Second, it is not clear what the meaning of "p" is at each iteration of the loop, as its position with respect to our walk over the string depends on how many slashes we've seen. The answer is that by itself, it doesn't really mean anything: "p + i" represents the current state of our walk, with "i" counting up slashes, and "p" by itself essentially meaningless. None of this behaves incorrectly, but ultimately the loop is just counting the slashes in the refname. We can do that much more simply with a for-loop iterating over the string and a separate slash counter. We can also drop the comment, which is somewhat misleading. We are counting slashes, not components (and a comment later in the function makes it clear that we must add one to compensate). In the new code it is obvious that we are counting slashes here. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-20mailmap: drop global config variablesBurak Kaan Karaçay3-29/+14
The 'mailmap.file' and 'mailmap.blob' configurations are currently parsed and stored in the global variables 'git_mailmap_file' and 'git_mailmap_blob'. Since these values are typically only needed once when initializing a mailmap, there is no need to keep them as global state throughout the lifetime of the Git process. To reduce global state, remove these global variables and instead use 'repo_config_get_*' functions to read the configuration on demand. Signed-off-by: Burak Kaan Karaçay <bkkaracay@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-20mailmap: stop using the_repositoryBurak Kaan Karaçay10-16/+19
The 'read_mailmap' and 'read_mailmap_blob' functions rely on the global 'the_repository' variable. Update both functions to accept a 'struct repository' parameter. Update all callers to pass 'the_repository' to retain the current behavior. Signed-off-by: Burak Kaan Karaçay <bkkaracay@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-20osxkeychain: define build targets in the top-level Makefile.Koji Nakamaru2-59/+27
The fix for git-credential-osxkeychain in 4580bcd235 (osxkeychain: avoid incorrectly skipping store operation, 2025-11-14) introduced linkage with libgit.a, and its Makefile was adjusted accordingly. However, the build fails as of 864f55e190 because several macOS-specific refinements were applied to the top-level Makefile and config.mak.uname, such as: - 363837afe7 (macOS: make Homebrew use configurable, 2025-12-24) - cee341e9dd (macOS: use iconv from Homebrew if needed and present, 2025-12-24) - d281241518 (utf8.c: enable workaround for iconv under macOS 14/15, 2026-01-12) Since libgit.a and its corresponding header files depend on many flags defined in the top-level Makefile, these flags must be consistently defined when building git-credential-osxkeychain. Continuing to manually adjust the git-credential-osxkeychain Makefile is cumbersome and fragile. Define the build targets for git-credential-osxkeychain in the top-level Makefile and modify its local Makefile to simply rely on those targets. Helped-by: Junio C Hamano <gitster@pobox.com> Reported-by: D. Ben Knoble <ben.knoble@gmail.com> Helped-by: Kristoffer Haugsbakk <kristofferhaugsbakk@fastmail.com> Signed-off-by: Koji Nakamaru <koji.nakamaru@gree.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-20t6006: don't use iconv(1) without ICONV prereqPatrick Steinhardt1-8/+21
Two tests in t6006 depend on the iconv(1) prerequisite to reencode a commit message. This executable may not even exist though in case the prereq is not set, which will cause the tests to fail. Fix this by using UTF-8 instead when the prereq is not set. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-20t5550: add ICONV prereq to tests that use "$HTTPD_URL/error"Patrick Steinhardt1-10/+10
We've got a bunch of tests in t5550 that connect to "$HTTPD_URL/error" to ensure that error messages are properly forwarded. This URL executes the "t/lib-httpd/error.sh" script, which in turn depends on the iconv(1) executable to reencode the message. This executable may not exist on platforms, which will make the tests fail. Guard them with the ICONV prereq to fix such failures. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-20t4205: improve handling of ICONV prerequisitePatrick Steinhardt1-22/+28
In t4205 we have a bunch of tests that depend on the iconv prereq. This is for most of the part because we format commit messages that have been encoded in an encoding different than UTF-8. Those tests fall into two classes though: - One class of tests outputs the data as-is without reencoding. - One class of tests outputs the data with "i18n.logOutputEncoding" to reencode it. Curiously enough, both of these classes are marked with the ICONV prereq, even though one might expect that the first class wouldn't need the prereq. This is because we unconditionally use ISO-8859-1 encoding for the initial commit message, and thus we depend on converting to UTF-8 indeed. This creates another problem though: when the iconv(1) executable does not exist the test setup fails, even in the case where the ICONV prereq has not been set. Fix these issues by making the test encoding conditional on ICONV: if it's available we use ISO-8859-1, otherwise we use UTF-8. This fixes the test setup on platforms without iconv(1), and it allows us to drop the ICONV prereq from a bunch of tests. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-20t40xx: don't use iconv(1) without ICONV prereqPatrick Steinhardt3-6/+18
We've got a couple of tests related to diffs in t40xx that use the iconv(1) executable to convert the encoding of a commit message. All of these tests are prepared to handle a missing ICONV prereq, in which case they will simply use UTF-8 encoding. But even if the ICONV prerequisite has failed we try to use the iconv(1) executable, even though it's not safe to assume that the executable exists in that case. And besides that, it's also unnecessary to use iconv(1) in the first place, as we would only use it to convert from UTF-8 to UTF-8, which should be equivalent to a no-op. Fix the issue and skip the call to iconv(1) in case the prerequisite is not set. This makes tests work on systems that don't have iconv at all. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-20t: don't set ICONV prereq when iconv(1) is missingPatrick Steinhardt1-1/+11
We've got a couple of tests that exercise Git with different encodings, typically around commit messages. All of these tests depend on the ICONV prerequisite, which is set when Git was built with support for iconv. Many of those tests also end up using the iconv(1) executable to reencode text. But while tests can rely on the fact that Git does have support for iconv, they cannot assume that the iconv(1) executable exists. The consequence is thus that tests will break in case Git is built with iconv, but the executable doesn't exist. In fact, some of the tests even use the iconv(1) executable unconditionally, regardless of whether or not the ICONV prerequisite is set. Git for Windows has recently (unintentionally) shipped a change where the iconv(1) binary is not getting installed anymore [1]. And as we use Git for Windows directly in MSVC+Meson jobs in GitLab CI this has caused such tests to break. The missing iconv(1) binary is considered a bug that will be fixed in Git for Windows. But regardless of that it makes sense to not assume the binary to always exist so that our test suite passes on platforms that don't have iconv at all. Extend the ICONV prerequisite so that we know to skip tests in case the iconv(1) binary doesn't exist. We'll adapt tests that are currently broken in subsequent commits. [1]: https://github.com/git-for-windows/git/issues/6083 Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19hook: add -z option to "git hook list"Adrian Ratiu3-5/+25
Add a NUL-terminate mode to git hook list, just in case hooks are configured with weird characters like newlines in their names. Suggested-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19hook: allow out-of-repo 'git hook' invocationsEmily Shaffer3-8/+40
Since hooks can now be supplied via the config, and a config can be present without a gitdir via the global and system configs, we can start to allow 'git hook run' to occur without a gitdir. This enables us to do things like run sendemail-validate hooks when running 'git send-email' from a nongit directory. It still doesn't make sense to look for hooks in the hookdir in nongit repos, though, as there is no hookdir. Signed-off-by: Emily Shaffer <emilyshaffer@google.com> Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19hook: allow event = "" to overwrite previous valuesAdrian Ratiu3-11/+34
Add the ability for empty events to clear previously set multivalue variables, so the newly added "hook.*.event" behave like the other multivalued keys. Suggested-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19hook: allow disabling config hooksAdrian Ratiu3-0/+59
Hooks specified via configs are always enabled, however users might want to disable them without removing from the config, like locally disabling a global hook. Add a hook.<name>.enabled config which defaults to true and can be optionally set for each configured hook. Suggested-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19hook: include hooks from the configAdrian Ratiu8-5/+513
Teach the hook.[hc] library to parse configs to populate the list of hooks to run for a given event. Multiple commands can be specified for a given hook by providing "hook.<friendly-name>.command = <path-to-hook>" and "hook.<friendly-name>.event = <hook-event>" lines. Hooks will be started in config order of the "hook.<name>.event" lines and will be run sequentially (.jobs == 1) like before. Running the hooks in parallel will be enabled in a future patch. The "traditional" hook from the hookdir is run last, if present. A strmap cache is added to struct repository to avoid re-reading the configs on each rook run. This is useful for hooks like the ref-transaction which gets executed multiple times per process. Examples: $ git config --get-regexp "^hook\." hook.bar.command=~/bar.sh hook.bar.event=pre-commit # Will run ~/bar.sh, then .git/hooks/pre-commit $ git hook run pre-commit Signed-off-by: Emily Shaffer <emilyshaffer@google.com> Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19hook: add "git hook list" commandEmily Shaffer5-16/+112
The previous commit introduced an ability to run multiple commands for hook events and next commit will introduce the ability to define hooks from configs, in addition to the "traditional" hooks from the hookdir. Introduce a new command "git hook list" to make inspecting hooks easier both for users and for the tests we will add. Further commits will expand on this, e.g. by adding a -z output mode. Signed-off-by: Emily Shaffer <emilyshaffer@google.com> Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19hook: run a list of hooks to prepare for multihook supportEmily Shaffer2-45/+153
Hooks are limited to run one command (the default from the hookdir) for each event. This limitation makes it impossible to run multiple commands via config files, which the next commits will add. Implement the ability to run a list of hooks in hook.[ch]. For now, the list contains only one entry representing the "default" hook from the hookdir, so there is no user-visible change in this commit. All hook commands still run sequentially like before. A separate patch series will enable running them in parallel. Signed-off-by: Emily Shaffer <emilyshaffer@google.com> Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19hook: add internal state alloc/free callbacksAdrian Ratiu5-20/+102
Some hooks use opaque structs to keep internal state between callbacks. Because hooks ran sequentially (jobs == 1) with one command per hook, these internal states could be allocated on the stack for each hook run. Next commits add the ability to run multiple commands for each hook, so the states cannot be shared or stored on the stack anymore, especially since down the line we will also enable parallel execution (jobs > 1). Add alloc/free helpers for each hook, doing a "deep" alloc/init & free of their internal opaque struct. The alloc callback takes a context pointer, to initialize the struct at at the time of resource acquisition. These callbacks must always be provided together: no alloc without free and no free without alloc, otherwise a BUG() is triggered. Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19path: remove repository argument from worktree_git_path()Phillip Wood7-22/+19
worktree_git_path() takes a struct repository and a struct worktree which also contains a struct repository. The repository argument was added by a973f60dc7c (path: stop relying on `the_repository` in `worktree_git_path()`, 2024-08-13) and exists because the worktree argument is optional. Having two ways of passing a repository is a potential foot-gun as if the the worktree argument is present the repository argument must match the worktree's repository member. Since the last commit there are no callers that pass a NULL worktree so lets remove the repository argument. This removes the potential confusion and lets us delete a number of uses of "the_repository". worktree_git_path() has the following callers: - builtin/worktree.c:validate_no_submodules() which is called from check_clean_worktree() and move_worktree(), both of which supply a non-NULL worktree. - builtin/fsck.c:cmd_fsck() which loops over all worktrees. - revision.c:add_index_objects_to_pending() which loops over all worktrees. - worktree.c:worktree_lock_reason() which dereferences wt before calling worktree_git_path(). - wt-status.c:wt_status_check_bisect() and wt_status_check_rebase() which are always called with a non-NULL worktree after the last commit. - wt-status.c:git_branch() which is only called by wt_status_check_bisect() and wt_status_check_rebase(). Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19wt-status: avoid passing NULL worktreePhillip Wood4-3/+47
In preparation for removing the repository argument from worktree_git_path() add a function to construct a "struct worktree" from a "struct repository" using its "gitdir" and "worktree" members. This function is then used to avoid passing a NULL worktree to wt_status_check_bisect() and wt_status_check_rebase(). In general the "struct worktree" returned may not correspond to the "current" worktree defined by is_current_worktree() as that function uses "the_repository" rather than "wt->repo" when deciding which worktree is "current". In practice the "struct repository" we pass corresponds to "the_repository" as we only ever operate on a single repository at the moment. wt_status_check_bisect() and wt_status_check_rebase() have the following callers: - branch.c:prepare_checked_out_branches() which loops over all worktrees. - worktree.c:is_worktree_being_rebased() which is called from builtin/branch.c:reject_rebase_or_bisect_branch() that loops over all worktrees and worktree.c:is_shared_symref() which dereferences wt earlier in the function. - wt-status:wt_status_get_state() which is updated to avoid passing a NULL worktree by this patch. This updates the only callers that pass a NULL worktree to worktree_git_path(). A new test is added to check that "git status" detects a rebase in a linked worktree. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19bisect: simplify string_list memory handlingJeff King1-6/+4
We declare the refs_for_removal string_list as NODUP, forcing us to manually allocate strings we insert. And then when it comes time to clean up, we set strdup_strings so that string_list_clear() will free them for us. This is a confusing pattern, and can be done much more simply by just declaring the list with the DUP initializer in the first place. It was written this way originally because one of the callsites generated the item using xstrfmt(). But that spot switched to a plain xstrdup() in the preceding commit. That means we can now just let the string_list code handle allocation itself. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19bisect: fix misuse of `refs_for_each_ref_in()`Patrick Steinhardt1-4/+4
All callers of `refs_for_each_ref_in()` pass in a string that is terminated with a trailing slash to indicate that they only want to see refs in that specific ref hierarchy. This is in fact a requirement if one wants to use this function, as the function trims the prefix from each yielded ref. So if there was a reference that was called "refs/bisect" as in our example, the result after trimming would be the empty string, and that's something we disallow. Fix this by adding the trailing slash. Furthermore, taking a closer look, we strip the prefix only to re-add it in `mark_for_removal()`. This is somewhat roundabout, as we can instead call `refs_for_each_fullref_in()` to not do any stripping at all. Do so to simplify the code a bit. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19pack-bitmap: fix bug with exact ref match in "pack.preferBitmapTips"Patrick Steinhardt4-5/+101
The "pack.preferBitmapTips" configuration allows the user to specify which references should be preferred when generating bitmaps. This option is typically expected to be set to a reference prefix, like for example "refs/heads/". It's not unreasonable though for a user to configure one specific reference as preferred. But if they do, they'll hit a `BUG()`: $ git -c pack.preferBitmapTips=refs/heads/main repack -adb BUG: ../refs/iterator.c:366: attempt to trim too many characters error: pack-objects died of signal 6 The root cause for this bug is how we enumerate these references. We call `refs_for_each_ref_in()`, which will: - Yield all references that have a user-specified prefix. - Trim each of these references so that the prefix is removed. Typically, this function is called with a trailing slash, like "refs/heads/", and in that case things work alright. But if the function is called with the name of an existing reference then we'll try to trim the full reference name, which would leave us with an empty name. And as this would not really leave us with anything sensible, we call `BUG()` instead of yielding this reference. One could argue that this is a bug in `refs_for_each_ref_in()`. But the question then becomes what the correct behaviour would be: - Do we want to skip exact matches? In our case we certainly don't want that, as the user has asked us to generate a bitmap for it. - Do we want to yield the reference with the empty refname? That would lead to a somewhat weird result. Neither of these feel like viable options, so calling `BUG()` feels like a sensible way out. The root cause ultimately is that we even try to trim the whole refname in the first place. There are two possible ways to fix this issue: - We can fix the bug by using `refs_for_each_fullref_in()` instead, which does not strip the prefix at all. Consequently, we would now start to accept all references that start with the configured prefix, including exact matches. So if we had "refs/heads/main", we would both match "refs/heads/main" and "refs/heads/main-branch". - Or we can fix the bug by appending a slash to the prefix if it doesn't already have one. This would mean that we only match ref hierarchies that start with this prefix. While the first fix leaves the user with strictly _more_ configuration options, we have already fixed a similar case in 10e8a9352b (refs.c: stop matching non-directory prefixes in exclude patterns, 2025-03-06) by using the second option. So for the sake of consistency, let's apply the same fix here. Clarify the documentation accordingly. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19pack-bitmap: deduplicate logic to iterate over preferred bitmap tipsPatrick Steinhardt4-30/+30
We have two locations that iterate over the preferred bitmap tips as configured by the user via "pack.preferBitmapTips". Both of these callsites are subtly wrong: when the preferred bitmap tips contain an exact refname match, then we will hit a `BUG()`. Prepare for the fix by unifying the two callsites into a new `for_each_preferred_bitmap_tip()` function. This removes the last callsite of `bitmap_preferred_tips()` outside of "pack-bitmap.c". As such, convert the function to be local to that file only. Note that the function is still used by a second caller, so we cannot just inline it. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19gitlab-ci: handle failed tests on MSVC+Meson jobPatrick Steinhardt1-1/+13
The MSVC+Meson job does not currently have any logic to print failing tests, nor does it upload the failed test artifacts. Backfill this logic to make help debugging efforts in case any of its jobs has failed. GitHub already knows to do this, so we don't need an equivalent change over there. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19gitlab-ci: use "run-test-slice-meson.sh"Patrick Steinhardt1-1/+2
While our GitHub workflow already uses "ci/run-test-slice-meson.sh", GitLab CI open-codes the parameters. Adapt the latter to also use the same script so that we always use the same Meson options across both CI systems. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19ci: make test slicing consistent across Meson/MakePatrick Steinhardt2-2/+2
In the preceding commit we have adjusted test slicing to be one-based when using the "ci/run-test-slice.sh" script. But we also have an equivalent script for Meson that is still zero-based, which is of course inconsistent. Adapt the script to be one-based, as well, and adapt the GitHub workflow accordingly. Note that GitLab doesn't yet use the script, so it does not need to be adapted. This will change in the next commit though. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19github: fix Meson tests not executing at allPatrick Steinhardt1-1/+1
While the win+Meson test jobs run in GitHub workflows, the shell script that is supposed to run the jobs is seemingly not running at all. All that the CI job prints is the following: Run ci/run-test-slice-meson.sh build 1 10 ci/run-test-slice-meson.sh build 1 10 shell: C:\Program Files\PowerShell\7\pwsh.EXE -command ". '{0}'" env: DEVELOPER: 1 The step is currently defined to use PowerShell, and of course it doesn't know how to execute POSIX shell scripts. What's surprising though is that this step doesn't even lead to a CI failure. Fix the issue by using Bash instead of PowerShell, as we do in other steps that execute shell scripts. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19meson: fix MERGE_TOOL_DIR with "--no-bin-wrappers"Patrick Steinhardt1-0/+1
On Windows, we execute tests with "--no-bin-wrappers". This has been introduced via a87e427e35 (ci: speed up Windows phase, 2019-01-29) to save some time: spawning processes is expensive on Windows, and shell scripts tend to spawn a bunch of them. So overall, the bin-wrappers led to a performance overhead of ~10-30%. This causes test failures when using Meson on Windows: failure: t7610.28 mergetool --tool-help shows recognized tools ++ git mergetool --tool-help /d/a/git/git/build/git-mergetool--lib: line 45: cd: D:/a/git/git/build/mergetools: No such file or directory The root cause here is that our bin-wrappers are usually responsible for setting up the `MERGE_TOOL_DIR` environment variable so that we can locate these scripts. But as we don't use the bin-wrappers, we'll instead use the default location for merge tools, which is derived from `GIT_EXEC_PATH`. And as `GIT_EXEC_PATH` points to our build directory, which won't ever contain any of the merge tools, we will fail to locate any of the merge tools. This issue has went unnoticed for a long time given that we only skip bin-wrappers on Windows, and because the CI jobs on Windows didn't execute due to a bug. Fix the issue by always setting the `MERGE_TOOL_DIR` environment variable to the correct directory. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19ci: don't skip smallest test slice in GitLabPatrick Steinhardt2-8/+14
The "ci/run-test-slice.sh" script can be used to slice up all of our tests into N pieces and then run each of them on a separate CI job. This is used by both GitLab and GitHub CI to speed up Windows tests, which would otherwise be painfully slow. The infra itself is fueled by `test-tool path-utils slice-tests`. This tool receives as input an "offset" and a "stride" that can be combined to slice up tests. This framing can be misleading though: you are expected to pass a zero-based index as "offset", and the complete number of slices to the "stride". The latter makes sense, but it is somewhat surprising that the offset needs to be zero-based. And this is in fact biting us: while GitHub passes zero-based indices, GitLab passes `$CI_NODE_INDEX`, which is a one-based indice. Ideally, we should have verification that the parameters make sense. And naturally, one would for example expect that it's an error to call the binary with an offset larger than the stride. But with the current framing as "offset" it's not even wrong to do so, as it is of course well-defined to start at a larger offset than the stride. This means that we get this wrong on GitLab's CI, as we pass a one based index there, and this causes us to skip one of the tests. Interestingly, it's not the lexicographically first test that we skip. Instead, as we sort tests by size before slicing them, we skip the _smallest_ test. Reframe the problem to instead talk about "slice number" and "total number of slices". For all of our use cases this is semantically equivalent, but it allows us to perform some verifications: - The total number of slices must be greater than 1. - The selected slice must be between 1 <= nr <= slices_total. As the indices are now one-based it means that GitLab's CI is fixed. The GitHub workflow is updated accordingly. Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19ci: handle failures of test-slice helperPatrick Steinhardt1-3/+3
The "run-test-slice.sh" script executes the test helper to slice up tests passed to it. As the execution is part of a pipe though, we end up ignoring any potential error code returned by the helper. Make the code more robust by storing the tests in a variable first so that we can split up the pipeline. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19completion: fix zsh alias listing for subsection aliasesJonatan Holmgren2-1/+14
The zsh completion function __git_zsh_cmd_alias() uses 'git config --get-regexp' to enumerate aliases and then strips the "alias." prefix from each key. For subsection-style aliases (alias.name.command), this leaves "name.command" as the completion candidate instead of just "name". The bash completion does not have this problem because it goes through 'git --list-cmds=alias', which calls list_aliases() in C and already handles both alias syntaxes correctly. However, zsh needs both the alias name and its value for descriptive completion, which --list-cmds=alias does not provide. Add a hidden --aliases-for-completion option to 'git help', following the existing --config-for-completion pattern. It outputs NUL-separated "name\nvalue" pairs using list_aliases(), which correctly resolves both the traditional (alias.name) and subsection (alias.name.command) formats. Update __git_zsh_cmd_alias() to use it. Signed-off-by: Jonatan Holmgren <jonatan@jontes.page> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19alias: support non-alphanumeric names via subsection syntaxJonatan Holmgren4-18/+145
Git alias names are limited to ASCII alphanumeric characters and dashes because aliases are implemented as config variable names. This prevents aliases being created in languages using characters outside that range. Add support for arbitrary alias names by using config subsections: [alias "förgrena"] command = branch The subsection name is matched as-is (case-sensitive byte comparison), while the existing definition without a subsection (e.g., "[alias] co = checkout") remains case-insensitive for backward compatibility. This uses existing config infrastructure since subsections already support arbitrary bytes, and avoids introducing Unicode normalization. Also teach the help subsystem about the new syntax so that "git help -a" properly lists subsection aliases and the autocorrect feature can suggest them. Use utf8_strwidth() instead of strlen() for column alignment so that non-ASCII alias names display correctly. Suggested-by: Jeff King <peff@peff.net> Signed-off-by: Jonatan Holmgren <jonatan@jontes.page> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19alias: prepare for subsection aliasesJonatan Holmgren1-3/+7
Switch git_unknown_cmd_config() from skip_prefix() to parse_config_key() for alias parsing. This properly handles the three-level config key structure and prepares for the new alias.*.command subsection syntax in the next commit. This is a compatibility break: the alias configuration parser used to be overly permissive and accepted "alias.<subsection>.<key>" as defining an alias "<subsection>.<key>". With this change, alias.<subsection>.<key> entries are silently ignored (unless <key> is "command", which will be given meaning in the next commit). This behavior was arguably a bug, since config subsections were never intended to work this way for aliases, and aliases with dots in their names have never been documented or intentionally supported. Signed-off-by: Jonatan Holmgren <jonatan@jontes.page> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19help: use list_aliases() for alias listingJonatan Holmgren3-16/+19
help.c has its own get_alias() config callback that duplicates the parsing logic in alias.c. Consolidate by teaching list_aliases() to also store the alias values (via the string_list util field), then use it in list_all_cmds_help_aliases() instead of the private callback. This preserves the existing error checking for value-less alias definitions by checking in alias.c rather than help.c. No functional change intended. Signed-off-by: Jonatan Holmgren <jonatan@jontes.page> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19object-file: use `container_of()` to convert from base typesJustin Tobler1-7/+16
To improve code hygiene, replace direct casts from `struct odb_transaction` and `struct odb_read_stream` to their concrete implementations with `container_of()`. Signed-off-by: Justin Tobler <jltobler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19doc: fetch: document `--jobs=0` behaviorDaniel D. Beck1-0/+2
In c39952b92 (fetch: choose a sensible default with --jobs=0 again, 2023-02-20), the `--jobs=0` behavior was (re)introduced, but it went undocumented. Since this is the same behavior as `git -c fetch.parallel=0 fetch`, which is documented, this change creates symmetry between the two documentation sections. Signed-off-by: Daniel D. Beck <daniel@ddbeck.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19commit: use commit graph in `lookup_commit_reference_gently()`Patrick Steinhardt1-4/+4
In the preceding commit we refactored `lookup_commit_reference_gently()` so that it doesn't parse non-commit objects anymore. This has led to a speedup when git-receive-pack(1) accepts a shallow push into a repo with lots of refs that point to blobs or trees. But while this case is now faster, we still have the issue that accepting pushes with lots of "normal" refs that point to commits are still slow. This is mostly because we look up the commits via the object database, and that is rather costly. Adapt the code to use `repo_parse_commit_gently()` instead of `parse_object()` to parse the resulting commit object. This function knows to use the commit-graph to fill in the object, which is way more cost efficient. This leads to another significant speedup when accepting shallow pushes. The following benchmark pushes a single objects from a shallow clone into a repository with 600,000 references that all point to commits: Benchmark 1: git-receive-pack (rev = HEAD~) Time (mean ± σ): 9.179 s ± 0.031 s [User: 8.858 s, System: 0.528 s] Range (min … max): 9.154 s … 9.213 s 3 runs Benchmark 2: git-receive-pack (rev = HEAD) Time (mean ± σ): 2.337 s ± 0.032 s [User: 2.331 s, System: 0.234 s] Range (min … max): 2.308 s … 2.371 s 3 runs Summary git-receive-pack . </tmp/input (rev = HEAD) ran 3.93 ± 0.05 times faster than git-receive-pack (rev = HEAD~) Also, this again leads to a significant reduction in memory allocations. Before this change: HEAP SUMMARY: in use at exit: 17,524,978 bytes in 22,393 blocks total heap usage: 33,313 allocs, 10,920 frees, 407,774,251 bytes allocated And after this change: HEAP SUMMARY: in use at exit: 11,534,036 bytes in 12,406 blocks total heap usage: 13,284 allocs, 878 frees, 15,521,451 bytes allocated Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19commit: make `repo_parse_commit_no_graph()` more robustPatrick Steinhardt2-3/+13
In the next commit we will start to parse more commits via the commit-graph. This change will lead to a segfault though because we try to access the tree of a commit via `repo_get_commit_tree()`, but: - The commit has been parsed via the commit-graph, and thus its `maybe_tree` field is not yet populated. - We cannot use the commit-graph to populate the commit's tree because we're in the process of writing the commit-graph. The consequence is that we'll get a `NULL` pointer for the tree in `write_graph_chunk_data()`. In theory we are already mindful of this situation, as we explicitly use `repo_parse_commit_no_graph()` to parse the commit without the help of the commit-graph. But that doesn't do the trick as the commit is already marked as parsed, so the function will not re-populate it. And as the commit-graph has been closed, neither will `get_commit_tree_oid()` be able to load the tree for us. It seems like this issue can only be hit under artificial circumstances: the error was hit via `git_test_write_commit_graph_or_die()`, which is run by git-commit(1) and git-merge(1) in case `GIT_TEST_COMMIT_GRAPH=1`: $ GIT_TEST_COMMIT_GRAPH=1 meson test t7507-commit-verbose \ --test-args=-ix -i ... ++ git -c commit.verbose=true commit --amend hint: Waiting for your editor to close the file... ./test-lib.sh: line 1012: 55895 Segmentation fault (core dumped) git -c commit.verbose=true commit --amend To the best of my knowledge, this is the only case where we end up writing a commit-graph in the same process that might have already consulted the commit-graph to look up arbitrary objects. But regardless of that, this feels like a bigger accident that is just waiting to happen. Make the code more robust by extending `repo_parse_commit_no_graph()` to unparse a commit first in case we detect it's coming from a graph. This ensures that we will re-read the object without it, and thus we will populate `maybe_tree` properly. This fix shouldn't have any performance consequences: the function is only ever called in the "commit-graph.c" code, and we'll only re-parse the commit at most once. Add an exclusion to our Coccinelle rules so that it doesn't complain about us accessing `maybe_tree` directly. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19commit: avoid parsing non-commits in `lookup_commit_reference_gently()`Patrick Steinhardt3-10/+50
The function `lookup_commit_reference_gently()` can be used to look up a committish by object ID. As such, the function knows to peel for example tag objects so that we eventually end up with the commit. The function is used quite a lot throughout our tree. One such user is "shallow.c" via `assign_shallow_commits_to_refs()`. The intent of this function is to figure out whether a shallow push is missing any objects that are required to satisfy the ref updates, and if so, which of the ref updates is missing objects. This is done by painting the tree with `UNINTERESTING`. We start painting by calling `refs_for_each_ref()` so that we can mark all existing referenced objects as the boundary of objects that we already have, and which are supposed to be fully connected. The reference tips are then parsed via `lookup_commit_reference_gently()`, and the commit is then marked as uninteresting. But references may not necessarily point to a committish, and if a lot of them aren't then this step takes a lot of time. This is mostly due to the way that `lookup_commit_reference_gently()` is implemented: before we learn about the type of the object we already call `parse_object()` on the object ID. This has two consequences: - We parse all objects, including trees and blobs, even though we don't even need the contents of them. - More importantly though, `parse_object()` will cause us to check whether the object ID matches its contents. Combined this means that we deflate and hash every non-committish object, and that of course ends up being both CPU- and memory-intensive. Improve the logic so that we first use `peel_object()`. This function won't parse the object for us, and thus it allows us to learn about the object's type before we parse and return it. The following benchmark pushes a single object from a shallow clone into a repository that has 100,000 refs. These refs were created by listing all objects via `git rev-list(1) --objects --all` and creating refs for a subset of them, so lots of those refs will cover non-commit objects. Benchmark 1: git-receive-pack (rev = HEAD~) Time (mean ± σ): 62.571 s ± 0.413 s [User: 58.331 s, System: 4.053 s] Range (min … max): 62.191 s … 63.010 s 3 runs Benchmark 2: git-receive-pack (rev = HEAD) Time (mean ± σ): 38.339 s ± 0.192 s [User: 36.220 s, System: 1.992 s] Range (min … max): 38.176 s … 38.551 s 3 runs Summary git-receive-pack . </tmp/input (rev = HEAD) ran 1.63 ± 0.01 times faster than git-receive-pack . </tmp/input (rev = HEAD~) This leads to a sizeable speedup as we now skip reading and parsing non-commit objects. Before this change we spent around 40% of the time in `assign_shallow_commits_to_refs()`, after the change we only spend around 1.2% of the time in there. Almost the entire remainder of the time is spent in git-rev-list(1) to perform the connectivity checks. Despite the speedup though, this also leads to a massive reduction in allocations. Before: HEAP SUMMARY: in use at exit: 352,480,441 bytes in 97,185 blocks total heap usage: 2,793,820 allocs, 2,696,635 frees, 67,271,456,983 bytes allocated And after: HEAP SUMMARY: in use at exit: 17,524,978 bytes in 22,393 blocks total heap usage: 33,313 allocs, 10,920 frees, 407,774,251 bytes allocated Note that when all references refer to commits performance stays roughly the same, as expected. The following benchmark was executed with 600k commits: Benchmark 1: git-receive-pack (rev = HEAD~) Time (mean ± σ): 9.101 s ± 0.006 s [User: 8.800 s, System: 0.520 s] Range (min … max): 9.095 s … 9.106 s 3 runs Benchmark 2: git-receive-pack (rev = HEAD) Time (mean ± σ): 9.128 s ± 0.094 s [User: 8.820 s, System: 0.522 s] Range (min … max): 9.019 s … 9.188 s 3 runs Summary git-receive-pack (rev = HEAD~) ran 1.00 ± 0.01 times faster than git-receive-pack (rev = HEAD) This will be improved in the next commit. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19t: use test_seq -f and pipes in a few more placesAaron Plattner6-34/+29
Several tests use a pattern that writes to a temporary file like this: printf "do something with %d\n" $(test_seq <count>) >tmpfile && git do-something --stdin <tmpfile Other tests use test_seq's -f parameter, but still write to a temporary file: test_seq -f "do something with %d" <count> >input && git do-something --stdin <input Simplify both of these patterns to test_seq -f "do something with %d" <count> | git do-something --stdin Signed-off-by: Aaron Plattner <aplattner@nvidia.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19wt-status: use hash_algo from local repository instead of global the_hash_algoShreyansh Paliwal1-3/+3
wt-status.c still uses the global the_hash_algo even though a repository instance is already available via struct wt_status. Replace uses of the_hash_algo with the hash algorithm stored in the associated repository (s->repo->hash_algo or r->hash_algo). This removes another dependency on global state and keeps wt-status consistent with local repository usage. Signed-off-by: Shreyansh Paliwal <shreyanshpaliwalcmsmn@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19wt-status: replace uses of the_repository with local repository instancesShreyansh Paliwal1-12/+12
wt-status.c uses the global the_repository in several places even when a repository instance is already available via struct wt_status *s or struct repository *r. Replace these uses of the_repository with the repository available in the local context (i.e. s->repo or r). The replacements of all the_repository with s->repo are mostly to cases where a repository instance is already available via struct wt_status *s and struct repository *r, all functions operating on struct wt_status *s are only used after s is initialized by wt_status_prepare(), which sets s->repo from the repository provided by the caller. As a result, s->repo is guaranteed to be available and consistent whenever these functions are invoked. This reduces reliance on global state and keeps wt-status consistent, though many functions operating on struct wt_status *s are called via commit.c and it still relies on the_repository, but within wt-status.c the local repository pointer refers to the same underlying repository object. Signed-off-by: Shreyansh Paliwal <shreyanshpaliwalcmsmn@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-19wt-status: pass struct repository through function parametersShreyansh Paliwal1-16/+16
Some functions in wt-status.c (count_stash_entries(), read_line_from_git_path(), abbrev_oid_in_line(), and read_rebase_todolist()) rely on the_repository as they do not have access to a local repository instance. Add a struct repository *r parameter to these functions and pass the local repository instance through the callers, which already have access to it either directly by struct repository *r or indirectly by struct wt_state *s (s->repo). Replace uses of the_repository in these functions with the passed parameter. Signed-off-by: Shreyansh Paliwal <shreyanshpaliwalcmsmn@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-18Merge branch 'pks-meson-fixes' of github.com:pks-gitlab/git-guiJohannes Sixt6-21/+38
* 'pks-meson-fixes' of github.com:pks-gitlab/git-gui: git-gui: wire up "git-gui--askyesno" with Meson git-gui: massage "git-gui--askyesno" with "generate-script.sh" git-gui: prefer shell at "/bin/sh" with Meson git-gui: fix use of GIT_CEILING_DIRECTORIES Signed-off-by: Johannes Sixt <j6t@kdbg.org>
2026-02-17format-patch: fix From header in cover letterMirko Faina3-8/+17
"git format-patch" takes "--from=<user ident>" command line option and uses the given ident for patch e-mails, but this is not applied to the cover letter, the option is ignored and the committer ident of the current user is used. This has been the case ever since "--from" was introduced in a9080475 (teach format-patch to place other authors into in-body "From", 2013-07-03). Teach the make_cover_letter() function to honor the option, instead of always using the current committer identity. Change variable name from "committer" to "from" to better reflect the purpose of the variable. Signed-off-by: Mirko Faina <mroik@delayed.space> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-17The 5th batchJunio C Hamano1-4/+21
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-02-17Merge branch 'jc/doc-rerere-update'Junio C Hamano1-2/+2
Doc update. * jc/doc-rerere-update: rerere: minor documantation update
2026-02-17Merge branch 'sd/t7003-test-path-is-helpers'Junio C Hamano1-6/+6
Test updates. * sd/t7003-test-path-is-helpers: t7003: modernize path existence checks using test helpers
2026-02-17Merge branch 'kh/doc-rerere-options-xref'Junio C Hamano1-2/+2
Doc update. * kh/doc-rerere-options-xref: doc: rerere-options.adoc: link to git-rerere(1)