]> git.ipfire.org Git - thirdparty/git.git/commitdiff
for-each-repo: work correctly in a worktree
authorDerrick Stolee <stolee@gmail.com>
Tue, 3 Mar 2026 17:31:53 +0000 (17:31 +0000)
committerJunio C Hamano <gitster@pobox.com>
Tue, 3 Mar 2026 18:20:00 +0000 (10:20 -0800)
When run in a worktree, the GIT_DIR directory is set in a different way
than in a typical repository. Show this by updating t0068 to include a
worktree and add a test that runs from that worktree. This requires
moving the repo.key config into a global config instead of the base test
repository's local config (demonstrating that it worked with
non-worktree Git repositories).

We need to be careful to unset the local Git environment variables and
let the child process rediscover them, while also reinstating those
variables in the parent process afterwards. Update run_command_on_repo()
to use the new sanitize_repo_env() helper method to erase these
environment variables.

During review of this bug fix, there were several incorrect patches
demonstrating different bad behaviors. Most of these are covered by
tests, when it is not too expensive to set it up. One case that would be
expensive to set up is the GIT_NO_REPLACE_OBJECTS environment variable,
but we trust that using sanitize_repo_env() will be sufficient to
capture these uncovered cases by using the common code for resetting
environment variables.

Reported-by: Matthew Gabeler-Lee <fastcat@gmail.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/for-each-repo.c
t/t0068-for-each-repo.sh

index 325a7925f1fdb577f4802466065ae4f05f48f449..82727c4aa2d0152acc609df7ac46743ee68a6656 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "builtin.h"
 #include "config.h"
+#include "environment.h"
 #include "gettext.h"
 #include "parse-options.h"
 #include "path.h"
@@ -19,6 +20,8 @@ static int run_command_on_repo(const char *path, int argc, const char ** argv)
        struct child_process child = CHILD_PROCESS_INIT;
        char *abspath = interpolate_path(path, 0);
 
+       sanitize_repo_env(&child.env);
+
        child.git_cmd = 1;
        strvec_pushl(&child.args, "-C", abspath, NULL);
 
index 512af34c82ecb8853a927c1691213555e0f5f533..80b163ea99bd757854f9f8bed2568e0490070072 100755 (executable)
@@ -8,10 +8,12 @@ TEST_NO_CREATE_REPO=1
 . ./test-lib.sh
 
 test_expect_success 'run based on configured value' '
-       git init one &&
-       git init two &&
-       git init three &&
-       git init ~/four &&
+       git init --initial-branch=one one &&
+       git init --initial-branch=two two &&
+       git -C two worktree add --orphan ../three &&
+       git -C three checkout -b three &&
+       git init --initial-branch=four ~/four &&
+
        git -C two commit --allow-empty -m "DID NOT RUN" &&
        git config --global run.key "$TRASH_DIRECTORY/one" &&
        git config --global --add run.key "$TRASH_DIRECTORY/three" &&
@@ -35,7 +37,43 @@ test_expect_success 'run based on configured value' '
        git -C three log -1 --pretty=format:%s >message &&
        grep again message &&
        git -C ~/four log -1 --pretty=format:%s >message &&
-       grep again message
+       grep again message &&
+
+       git -C three for-each-repo --config=run.key -- \
+               commit --allow-empty -m "ran from worktree" &&
+       git -C one log -1 --pretty=format:%s >message &&
+       test_grep "ran from worktree" message &&
+       git -C two log -1 --pretty=format:%s >message &&
+       test_grep ! "ran from worktree" message &&
+       git -C three log -1 --pretty=format:%s >message &&
+       test_grep "ran from worktree" message &&
+       git -C ~/four log -1 --pretty=format:%s >message &&
+       test_grep "ran from worktree" message &&
+
+       # Test running with config values set by environment
+       cat >expect <<-EOF &&
+       ran from worktree (HEAD -> refs/heads/one)
+       ran from worktree (HEAD -> refs/heads/three)
+       ran from worktree (HEAD -> refs/heads/four)
+       EOF
+
+       GIT_CONFIG_PARAMETERS="${SQ}log.decorate=full${SQ}" \
+               git -C three for-each-repo --config=run.key -- log --format="%s%d" -1 >out &&
+       test_cmp expect out &&
+
+       cat >test-config <<-EOF &&
+       [run]
+               key = $(pwd)/one
+               key = $(pwd)/three
+               key = $(pwd)/four
+
+       [log]
+               decorate = full
+       EOF
+
+       GIT_CONFIG_GLOBAL="$(pwd)/test-config" \
+               git -C three for-each-repo --config=run.key -- log --format="%s%d" -1 >out &&
+       test_cmp expect out
 '
 
 test_expect_success 'do nothing on empty config' '