Skip to content

Commit a1999f3

Browse files
derrickstoleegitster
authored andcommitted
for-each-repo: work correctly in a worktree
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 store, unset, then reset the non-NULL 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>
1 parent 68d37f2 commit a1999f3

2 files changed

Lines changed: 42 additions & 5 deletions

File tree

builtin/for-each-repo.c

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include "builtin.h"
44
#include "config.h"
5+
#include "environment.h"
56
#include "gettext.h"
67
#include "parse-options.h"
78
#include "path.h"
@@ -15,19 +16,45 @@ static const char * const for_each_repo_usage[] = {
1516

1617
static int run_command_on_repo(const char *path, int argc, const char ** argv)
1718
{
18-
int i;
19+
int res;
1920
struct child_process child = CHILD_PROCESS_INIT;
21+
char **envvars;
22+
size_t envvar_nr = 0;
2023
char *abspath = interpolate_path(path, 0);
2124

25+
while (local_repo_env[envvar_nr])
26+
envvar_nr++;
27+
28+
CALLOC_ARRAY(envvars, envvar_nr);
29+
30+
for (size_t i = 0; i < envvar_nr; i++) {
31+
envvars[i] = getenv(local_repo_env[i]);
32+
33+
if (envvars[i]) {
34+
unsetenv(local_repo_env[i]);
35+
envvars[i] = xstrdup(envvars[i]);
36+
}
37+
}
38+
2239
child.git_cmd = 1;
2340
strvec_pushl(&child.args, "-C", abspath, NULL);
2441

25-
for (i = 0; i < argc; i++)
42+
for (int i = 0; i < argc; i++)
2643
strvec_push(&child.args, argv[i]);
2744

2845
free(abspath);
2946

30-
return run_command(&child);
47+
res = run_command(&child);
48+
49+
for (size_t i = 0; i < envvar_nr; i++) {
50+
if (envvars[i]) {
51+
setenv(local_repo_env[i], envvars[i], 1);
52+
free(envvars[i]);
53+
}
54+
}
55+
56+
free(envvars);
57+
return res;
3158
}
3259

3360
int cmd_for_each_repo(int argc,

t/t0068-for-each-repo.sh

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ TEST_NO_CREATE_REPO=1
1010
test_expect_success 'run based on configured value' '
1111
git init one &&
1212
git init two &&
13-
git init three &&
13+
git -C two worktree add --orphan ../three &&
1414
git init ~/four &&
1515
git -C two commit --allow-empty -m "DID NOT RUN" &&
1616
git config --global run.key "$TRASH_DIRECTORY/one" &&
@@ -35,7 +35,17 @@ test_expect_success 'run based on configured value' '
3535
git -C three log -1 --pretty=format:%s >message &&
3636
grep again message &&
3737
git -C ~/four log -1 --pretty=format:%s >message &&
38-
grep again message
38+
grep again message &&
39+
40+
git -C three for-each-repo --config=run.key -- commit --allow-empty -m "ran from worktree" &&
41+
git -C one log -1 --pretty=format:%s >message &&
42+
grep worktree message &&
43+
git -C two log -1 --pretty=format:%s >message &&
44+
! grep worktree message &&
45+
git -C three log -1 --pretty=format:%s >message &&
46+
grep worktree message &&
47+
git -C ~/four log -1 --pretty=format:%s >message &&
48+
grep worktree message
3949
'
4050

4151
test_expect_success 'do nothing on empty config' '

0 commit comments

Comments
 (0)