Skip to content

Commit df9a480

Browse files
committed
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. But... ...we also need to be careful to not un-set environment variables around -c config options or --no-replace-objects. A detailed comment includes the justification for these filters. Reported-by: Matthew Gabeler-Lee <fastcat@gmail.com> Signed-off-by: Derrick Stolee <stolee@gmail.com>
1 parent 6e9d4f3 commit df9a480

File tree

2 files changed

+33
-3
lines changed

2 files changed

+33
-3
lines changed

builtin/for-each-repo.c

Lines changed: 21 additions & 1 deletion
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,10 +16,29 @@ 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 i = 0;
1920
struct child_process child = CHILD_PROCESS_INIT;
2021
char *abspath = interpolate_path(path, 0);
2122

23+
while (local_repo_env[i]) {
24+
/*
25+
* Preserve pre-builtin options:
26+
* - CONFIG_ENVIRONMENT, CONFIG_DATA_ENVIRONMENT, and
27+
* CONFIG_COUNT_ENVIRONMENT persist -c <name>=<value>
28+
* and --config-env=<name>=<envvar> options.
29+
* - NO_REPLACE_OBJECTS_ENVIRONMENT persists the
30+
* --no-replace-objects option.
31+
*
32+
* Note that the following options are not in local_repo_env:
33+
* - EXEC_PATH_ENVIRONMENT persists --exec-path option.
34+
*/
35+
if (strncmp(local_repo_env[i], "CONFIG_", 7) &&
36+
strcmp(local_repo_env[i], NO_REPLACE_OBJECTS_ENVIRONMENT))
37+
strvec_push(&child.env, local_repo_env[i]);
38+
39+
i++;
40+
}
41+
2242
child.git_cmd = 1;
2343
strvec_pushl(&child.args, "-C", abspath, NULL);
2444

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)