Re: [PATCH v2 2/2] for-each-repo: work correctly in a worktree
- From
Junio C Hamano <gitster@pobox.com>
- Date
- Feb 24, 2026, 21:47 UTC
- Message-ID
- <xmqqv7flervq.fsf@gitster.g>
- In-Reply-To
- <4e3f4aa6cd36f779c6c1d6b4f30bb68ed807b9da.1771968924.git.gitgitgadget@gmail.com>
"Derrick Stolee via GitGitGadget" <gitgitgadget@gmail.com> writes:
Show 45 quoted lines
> static int run_command_on_repo(const char *path, int argc, const char ** argv)
> {
> - int i;
> + int res;
> struct child_process child = CHILD_PROCESS_INIT;
> + char **envvars;
> + size_t envvar_nr = 0;
> char *abspath = interpolate_path(path, 0);
>
> + while (local_repo_env[envvar_nr])
> + envvar_nr++;
> +
> + CALLOC_ARRAY(envvars, envvar_nr);
> +
> + for (size_t i = 0; i < envvar_nr; i++) {
> + envvars[i] = getenv(local_repo_env[i]);
> +
> + if (envvars[i]) {
> + unsetenv(local_repo_env[i]);
> + envvars[i] = xstrdup(envvars[i]);
> + }
> + }
>
> child.git_cmd = 1;
> strvec_pushl(&child.args, "-C", abspath, NULL);
>
> - for (i = 0; i < argc; i++)
> + for (int i = 0; i < argc; i++)
> strvec_push(&child.args, argv[i]);
>
> free(abspath);
>
> - return run_command(&child);
> + res = run_command(&child);
> +
> + for (size_t i = 0; i < envvar_nr; i++) {
> + if (envvars[i]) {
> + setenv(local_repo_env[i], envvars[i], 1);
> + free(envvars[i]);
> + }
> + }
> +
> + free(envvars);
> + return res;
> }Doesn't run_command() let you unsetenv in the child without affecting the parent process?
Looking at run-command.c:prep_childenv(), it seems that you can pass "VAR=VAL" to "export VAR=VAL" in the child, and pass "VAR" to "unset VAR" in the child.
Or is it essential to unset in both parent and child while the child is working and that is why we unset in the parent and then restore later? I find this highly confusing.
Show 33 quoted lines
> int cmd_for_each_repo(int argc, > diff --git a/t/t0068-for-each-repo.sh b/t/t0068-for-each-repo.sh > index 512af34c82..d55557a934 100755 > --- a/t/t0068-for-each-repo.sh > +++ b/t/t0068-for-each-repo.sh > @@ -10,7 +10,7 @@ TEST_NO_CREATE_REPO=1 > test_expect_success 'run based on configured value' ' > git init one && > git init two && > - git init three && > + git -C two worktree add --orphan ../three && > git init ~/four && > git -C two commit --allow-empty -m "DID NOT RUN" && > git config --global run.key "$TRASH_DIRECTORY/one" && > @@ -35,7 +35,17 @@ 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 && > + grep worktree message && > + git -C two log -1 --pretty=format:%s >message && > + ! grep worktree message && > + git -C three log -1 --pretty=format:%s >message && > + grep worktree message && > + git -C ~/four log -1 --pretty=format:%s >message && > + grep worktree message > ' > > test_expect_success 'do nothing on empty config' '