git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH 2/2] for-each-repo: work correctly in a worktree

From
Derrick Stolee <stolee@gmail.com>
Date
Feb 24, 2026, 12:11 UTC
Message-ID
<fce7662f-d741-41e1-93dd-f82e65e04f41@gmail.com>
In-Reply-To
<20260224091806.GC986367@coredump.intra.peff.net>
On 2/24/26 4:18 AM, Jeff King wrote:
Show 64 quoted lines
> On Mon, Feb 23, 2026 at 10:34:30PM -0500, Eric Sunshine wrote:
> 
>>> diff --git a/builtin/for-each-repo.c b/builtin/for-each-repo.c
>>> @@ -60,6 +61,9 @@ int cmd_for_each_repo(int argc,
>>> +       /* Be sure to not pass GIT_DIR to children. */
>>> +       unsetenv(GIT_DIR_ENVIRONMENT);
>>
>> This only unsets GIT_DIR. Is that sufficient in the general case?
>> Elsewhere, we recommend[*] unsetting all of Git's local environment
>> variables.
>>
>> [*]: From the "githooks" man page: "Environment variables, such as
>> GIT_DIR, GIT_WORK_TREE, etc., are exported so that Git commands run by
>> the hook can correctly locate the repository. If your hook needs to
>> invoke Git commands in a foreign repository or in a different working
>> tree of the same repository, then it should clear these environment
>> variables so they do not interfere with Git operations at the foreign
>> location. For example: `unset $(git rev-parse --local-env-vars)`"
> 
> Yeah, agreed. There's another subtle issue, which is that this is
> unsetting GIT_DIR in the parent process. So any other code we call that
> is meant to run in the original repo might get confused. I can well
> believe there isn't any such code for a command like for-each-repo, but
> as a general principle, the change should be made in the sub-process.
> 
> You can stick the elements of local_repo_env into the "env" list of the
> child_process struct. If you grep around, you can find some instances of
> this.
> 
> There's an open question there of how to handle config in the
> environment, though. Depending on the sub-process, you may or may not
> want such config to pass down to it. For for-each-repo, I'd guess that
> you'd want:
> 
>    git -c foo.bar=baz for-each-repo ...
> 
> to pass that foo.bar value. We do have a helper to handle that in
> run-command.h:
> 
>    /**
>     * Convenience function which prepares env for a command to be run in a
>     * new repo. This adds all GIT_* environment variables to env with the
>     * exception of GIT_CONFIG_PARAMETERS and GIT_CONFIG_COUNT (which cause the
>     * corresponding environment variables to be unset in the subprocess) and adds
>     * an environment variable pointing to new_git_dir. See local_repo_env in
>     * environment.h for more information.
>     */
>    void prepare_other_repo_env(struct strvec *env, const char *new_git_dir);
> 
> Do be careful using it here, though. It expects to set GIT_DIR itself to
> point to the new repo (which is passed in). But I'm not sure that's 100%
> compatible with how for-each-repo works, which is using "git -C $repo"
> under the hood, and letting the usual discovery happen.
> 
> So for a bare repo, you'd want to pass the repo directory. But for a
> non-bare one, you'd want $repo/.git. And there are even more weird
> corner cases, like the fact that using "/my/repo/but/inside/a/subdir"
> with for-each-repo will find "/my/repo".
> 
> So you might need to refactor prepare_other_repo_env() to split out the
> "everything but the config" logic versus the "set GIT_DIR" logic. Or
> just inline the former in run_command_on_repo(), though it probably is
> better to keep the logic in one place (it's not many lines, but it has
> to know about all of the env variables that affect config).

Thanks for the recommendations. I'll come back with a more sophisticated v2 that handles these issues.

> Alternatively, for-each-repo could do repo discovery itself on the paths
> it is passed, before calling sub-programs. That's a bigger change, but
> possibly it could or should be flagging an error for some cases? I
> dunno.

I'm surprised that passing '-C <repo>' doesn't already overwrite these variables but I suppose environment variables override arguments in this case. (This is the root of the bug.)

Thanks, -Stolee

Previous: Jeff KingNext: Jeff King
Message 8 of 48 in “for-each-repo: work correctly in a worktree”
  1. 0/2 for-each-repo: work correctly in a worktreeDerrick Stolee via GitGitGadget, Feb 24, 2026
  2. 1/2 for-each-repo: stop using the_repositoryDerrick Stolee via GitGitGadget, Feb 24, 2026
  3. Patrick SteinhardtFeb 24, 2026
  4. Derrick StoleeFeb 24, 2026
  5. 2/2 for-each-repo: work correctly in a worktreeDerrick Stolee via GitGitGadget, Feb 24, 2026
  6. Eric SunshineFeb 24, 2026
  7. Jeff KingFeb 24, 2026
  8. Derrick StoleeFeb 24, 2026
  9. Jeff KingFeb 25, 2026
  10. Patrick SteinhardtFeb 24, 2026
  11. 0/2 for-each-repo: work correctly in a worktreeDerrick Stolee via GitGitGadget, Feb 24, 2026
  12. 1/2 for-each-repo: test outside of repo contextDerrick Stolee via GitGitGadget, Feb 24, 2026
  13. 2/2 for-each-repo: work correctly in a worktreeDerrick Stolee via GitGitGadget, Feb 24, 2026
  14. Junio C HamanoFeb 24, 2026
  15. Derrick StoleeFeb 25, 2026
  16. Jeff KingFeb 25, 2026
  17. Derrick StoleeFeb 26, 2026
  18. Junio C HamanoFeb 26, 2026
  19. Phillip WoodFeb 26, 2026
  20. Junio C HamanoFeb 27, 2026
  21. Derrick StoleeFeb 27, 2026
  22. Jeff KingFeb 27, 2026
  23. Jeff KingFeb 27, 2026
  24. Derrick StoleeMar 2, 2026
  25. Jeff KingMar 2, 2026
  26. 0/4 for-each-repo: work correctly in a worktreeDerrick Stolee via GitGitGadget, Mar 2, 2026
  27. 1/4 for-each-repo: test outside of repo contextDerrick Stolee via GitGitGadget, Mar 2, 2026
  28. Jeff KingMar 2, 2026
  29. Junio C HamanoMar 2, 2026
  30. Derrick StoleeMar 2, 2026
  31. 2/4 run-command: extract clear_local_repo_env helperDerrick Stolee via GitGitGadget, Mar 2, 2026
  32. Jeff KingMar 2, 2026
  33. Junio C HamanoMar 2, 2026
  34. Derrick StoleeMar 2, 2026
  35. 3/4 for-each-repo: work correctly in a worktreeDerrick Stolee via GitGitGadget, Mar 2, 2026
  36. Jeff KingMar 2, 2026
  37. Derrick StoleeMar 2, 2026
  38. Junio C HamanoMar 2, 2026
  39. 4/4 for-each-repo: simplify passing of parametersDerrick Stolee via GitGitGadget, Mar 2, 2026
  40. Jeff KingMar 2, 2026
  41. 0/4 for-each-repo: work correctly in a worktreeDerrick Stolee via GitGitGadget, Mar 3, 2026
  42. 1/4 for-each-repo: test outside of repo contextDerrick Stolee via GitGitGadget, Mar 3, 2026
  43. 2/4 run-command: extract sanitize_repo_env helperDerrick Stolee via GitGitGadget, Mar 3, 2026
  44. 3/4 for-each-repo: work correctly in a worktreeDerrick Stolee via GitGitGadget, Mar 3, 2026
  45. 4/4 for-each-repo: simplify passing of parametersDerrick Stolee via GitGitGadget, Mar 3, 2026
  46. Jeff KingMar 5, 2026
  47. Patrick SteinhardtMar 5, 2026
  48. Derrick StoleeMar 5, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.