sequencer: fix environment that 'exec' commands run under
PATCH 1/1 sequencer: fix environment that 'exec' commands run under
From: Elijah Newren <[email protected]>
Commands executed from git rebase --exec can give different behavior from within that environment than they would outside of it, due to the fact that sequencer.c exports both GIT_DIR and GIT_WORK_TREE. For example, if the relevant script calls something like
git -C ../otherdir log --format=%H --no-walk
the user may be surprised to find that the command above does not show a commit hash from ../otherdir, because $GIT_DIR prevents automatic gitdir detection and makes the -C option useless.
This is a regression in behavior from the original legacy implemented-in-shell rebase. It is perhaps rare for it to cause problems in practice, especially since most small problems that were caused by this area of bugs has been fixed-up in the past in a way that masked the particular bug observed without fixing the real underlying problem.
How we arrived at the current situation is perhaps merited. The setting of GIT_DIR and GIT_WORK_TREE done by sequencer.c arose from a sequence of historical accidents:
* When rebase was implemented as a shell command, it would call git-sh-setup, which among other things would set GIT_DIR -- but not export it. This meant that when rebase --exec commands were run via
/bin/sh -c "$COMMAND"
they would not inherit the GIT_DIR setting. The fact that GIT_DIR was not set in the run $COMMAND is the behavior we'd like to restore.
* When the rebase--helper builtin was introduced to allow incrementally replacing shell with C code, we were in an implementation that was half shell, half C. In particular, commit 18633e1a22 ("rebase -i: use the rebase--helper builtin", 2017-02-09) added calls to exec git rebase--helper ...
which caused rebase--helper to inherit the GIT_DIR environment variable from the shell. git's setup would change the environment variable from an absolute path to a relative one (".git"), but would leave it set. This meant that when rebase --exec commands were run via
run_command_v_opt(...)
they would inherit the GIT_DIR setting.
* In commit 09d7b6c6fa ("sequencer: pass absolute GIT_DIR to exec commands", 2017-10-31), it was noted that the GIT_DIR caused problems with some commands; e.g.
git rebase --exec 'cd subdir && git describe' ...
would have GIT_DIR=.git which was invalid due to the change to the
subdirectory. Instead of questioning why GIT_DIR was set, that commit
instead made sequencer change GIT_DIR to be an absolute path and
explicitly export it via
argv_array_pushf(&child_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
run_command_v_opt_cd_env(..., child_env.argv)* In commit ab5e67d751 ("sequencer: pass absolute GIT_WORK_TREE to exec commands", 2018-07-14), it was noted that when GIT_DIR is set but GIT_WORK_TREE is not, that we do not discover GIT_WORK_TREE but just assume it is '.'. That is incorrect if trying to run commands from a subdirectory. However, rather than question why GIT_DIR was set, that commit instead also added GIT_WORK_TREE to the list of things to export.
Each of the above problems would have been fixed automatically when git-rebase become a full builtin, had it not been for the fact that sequencer.c started exporting GIT_DIR and GIT_WORK_TREE in the interim. Stop exporting them now.
---
sequencer: fix environment that 'exec' commands run under
I'm not sure if the added regression tests make sense, or if t3409 is the best place to put them (taking over a recently removed t3409 that was used for the deprecated preserve merges option).
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1134%2Fnewren%2Ffix-rebase-exec-environ-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1134/newren/fix-rebase-exec-environ-v1
Pull-Request: https://github.com/git/git/pull/1134
sequencer.c | 9 +-------- t/t3409-rebase-environ.sh | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) create mode 100755 t/t3409-rebase-environ.sh
sequencer.c +1 -8
@@ -3495,17 +3495,12 @@ static int error_failed_squash(struct repository *r,static int do_exec (struct repository *r,const char *command_line) { -struct strvec child_env =STRVEC_INIT ;const char *child_argv[] = {NULL ,NULL };int dirty, status;fprintf (stderr,_ ("Executing: %s\n" ), command_line); child_argv[0 ] = command_line; -strvec_pushf (&child_env,"GIT_DIR=%s" ,absolute_path (get_git_dir ())); -strvec_pushf (&child_env,"GIT_WORK_TREE=%s" , -absolute_path (get_git_work_tree ())); - status =run_command_v_opt_cd_env (child_argv,RUN_USING_SHELL ,NULL , - child_env.v); + status =run_command_v_opt (child_argv,RUN_USING_SHELL );/* force re-reading of the cache */ if (discard_index (r->index) <0 ||repo_read_index (r) <0 )
@@ -3535,8 +3530,6 @@ static int do_exec(struct repository *r, const char *command_line) status =1 ; } -strvec_clear (&child_env); -return status; }
t/t3409-rebase-environ.sh new file +23 -0
@@ -0,0 +1,23 @@ +#!/bin/sh + +test_description='git rebase interactive environment' + +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit one && + test_commit two && + test_commit three +' + +test_expect_success 'rebase --exec does not muck with GIT_DIR' ' + git rebase --exec "printf %s \$GIT_DIR >environ" HEAD~1 && + test_must_be_empty environ +' + +test_expect_success 'rebase --exec does not muck with GIT_WORK_TREE' ' + git rebase --exec "printf %s \$GIT_WORK_TREE >environ" HEAD~1 && + test_must_be_empty environ +' + +test_done
base-commit: 88d915a634b449147855041d44875322de2b286d
Signature · 1 line
gitgitgadget
Quoted 7 lines · Elijah Newren via GitGitGadget
From: Elijah Newren <[email protected]>
Commands executed from
git rebase --execcan give different behavior from within that environment than they would outside of it, due to the fact thatsequencer.cexports bothGIT_DIRandGIT_WORK_TREE. For example, if the relevant script calls something like
Quoted 5 lines
git -C ../otherdir log --format=%H --no-walkthe user may be surprised to find that the command above does not show a commit hash from ../otherdir, because $GIT_DIR prevents automatic gitdir detection and makes the -C option useless.
Yep. I've had a case where "git rebase -x 'make test'" would fail because "make test" tries to run some Git commands in a temporary repo. The workaround was to unset all GIT_* environment variables, just like t/test-lib.sh does.
I had the same problem when testing shell completion because git prepends $(git --exec-path) to $PATH. I don't see a good reason why "git rebase -x cmd" passes a modified $PATH (and $GIT_EXEC_PATH) to cmd. The user is back in control, so I'd expect the same environment as for the parent rebase process.
AFAICT, the main purpose of changing $PATH is to ease (cross-language) implementation, I don't think the user is meant to notice.
Of course, exporting GIT_EXEC_PATH is desirable for some commands like gc that delegate to a bunch of git processes without user interaction, to make sure all children are from the same build. c90d565a46 (Propagate --exec-path setting to external commands via GIT_EXEC_PATH, 2009-03-21). But I don't think the same applies for rebase -x.
Quoted 7 lines
This is a regression in behavior from the original legacy implemented-in-shell rebase. It is perhaps rare for it to cause problems in practice, especially since most small problems that were caused by this area of bugs has been fixed-up in the past in a way that masked the particular bug observed without fixing the real underlying problem.
Really interesting that we added multiple workarounds, when we just needed to stop polluting the environment. The fact that our test suite unsets most GIT_* variables also masks potential problems.
Quoted 2 lines
How we arrived at the current situation is perhaps merited. The setting
This sounds weirdly penitent if read the wrong way. I guess "An explanation how we arrived ... "?
Quoted 6 lines
of
GIT_DIRandGIT_WORK_TREEdone bysequencer.carose from a sequence of historical accidents:* When rebase was implemented as a shell command, it would call git-sh-setup, which among other things would set
GIT_DIR-- but not export it. This meant that when rebase --exec commands were run via
Quoted 6 lines
/bin/sh -c "$COMMAND"they would not inherit the
GIT_DIRsetting. The fact thatGIT_DIRwas not set in the run $COMMAND is the behavior we'd like to restore.* When the rebase--helper builtin was introduced to allow incrementally replacing shell with C code, we were in an implementation that was
More correct to say "we were in an (implementation) state" or better:
"we had an implementation"?
Quoted 3 lines
half shell, half C. In particular, commit
18633e1a22("rebase -i: use the rebase--helper builtin", 2017-02-09) added calls to
exec git rebase--helper ...
Ok I guess this was a good reason for adding the exec-path to the environment of exec steps.
Quoted 27 lines
which caused rebase--helper to inherit the
GIT_DIRenvironment variable from the shell. git's setup would change the environment variable from an absolute path to a relative one (".git"), but would leave it set. This meant that when rebase --exec commands were run viarun_command_v_opt(...)they would inherit the
GIT_DIRsetting.* In commit
09d7b6c6fa("sequencer: pass absoluteGIT_DIRto exec commands", 2017-10-31), it was noted that theGIT_DIRcaused problems with some commands; e.g.git rebase --exec 'cd subdir && git describe' ... would have GIT_DIR=.git which was invalid due to the change to the subdirectory. Instead of questioning why GIT_DIR was set, that commit instead made sequencer change GIT_DIR to be an absolute path and explicitly export it via argv_array_pushf(&child_env, "GIT_DIR=%s", absolute_path(get_git_dir())); run_command_v_opt_cd_env(..., child_env.argv)* In commit
ab5e67d751("sequencer: pass absoluteGIT_WORK_TREEto exec commands", 2018-07-14), it was noted that whenGIT_DIRis set butGIT_WORK_TREEis not, that we do not discoverGIT_WORK_TREEbut just assume it is '.'. That is incorrect if trying to run commands from a subdirectory. However, rather than question whyGIT_DIRwas set, that commit instead also addedGIT_WORK_TREEto the list of things to export.
Quoted 2 lines
Each of the above problems would have been fixed automatically when git-rebase become a full builtin, had it not been for the fact that
s/become/became/
Quoted 7 lines
sequencer.cstarted exportingGIT_DIRandGIT_WORK_TREEin the interim. Stop exporting them now.Signed-off-by Elijah Newren <[email protected]>---
sequencer: fix environment that 'exec' commands run under
Maybe: sequencer: do not export GIT_DIR and GIT_WORK_TREE to exec (assuming that $PATH also needs fixing)
Quoted 2 lines
I'm not sure if the added regression tests make sense
They are simple and correct.
We still pass on values from --git-dir= and GIT_DIR=. git. Those are /probably/ right.
Quoted 2 lines
or if t3409 is the best place to put them (taking over a recently removed t3409 that was used for the deprecated preserve merges option).
Looks like there is no t/t34*-rebase-exec.sh yet. Most tests of --exec are in t/t3404-rebase-interactive.sh, but we don't need the interactive bit here.
Quoted 48 lines
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1134%2Fnewren%2Ffix-rebase-exec-environ-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1134/newren/fix-rebase-exec-environ-v1
Pull-Request: https://github.com/git/git/pull/1134sequencer.c | 9 +-------- t/t3409-rebase-environ.sh | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) create mode 100755 t/t3409-rebase-environ.shsequencer.c +1
-8@@ -3495,17 +3495,12 @@ static int error_failed_squash(struct repository *r,static int do_exec (struct repository *r,const char *command_line) { -struct strvec child_env =STRVEC_INIT ;const char *child_argv[] = {NULL ,NULL };int dirty, status;fprintf (stderr,_ ("Executing: %s\n" ), command_line); child_argv[0 ] = command_line; -strvec_pushf (&child_env,"GIT_DIR=%s" ,absolute_path (get_git_dir ())); -strvec_pushf (&child_env,"GIT_WORK_TREE=%s" , -absolute_path (get_git_work_tree ())); - status =run_command_v_opt_cd_env (child_argv,RUN_USING_SHELL ,NULL , - child_env.v); + status =run_command_v_opt (child_argv,RUN_USING_SHELL );/* force re-reading of the cache */ if (discard_index (r->index) <0 ||repo_read_index (r) <0 )@@ -3535,8 +3530,6 @@ static int do_exec(struct repository *r, const char *command_line) status =1 ; } -strvec_clear (&child_env); -return status; }t/t3409-rebase-environ.sh new file +0
-0
t/t3409-rebase-environ.sh line 3
Quoted 3 lines
t/t3409-rebase-environ.sh new file +3
-0@@ -0,0 +1,23 @@ +#!/bin/sh + +test_description='git rebase interactive environment'
maybe test_description='git rebase --exec environment'
Quoted 8 lines
t/t3409-rebase-environ.sh new file +8
-0+ +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit one && + test_commit two && + test_commit three +'
t/t3409-rebase-environ.sh line 21
Quoted 10 lines
t/t3409-rebase-environ.sh new file +10
-0+ +test_expect_success 'rebase --exec does not muck with GIT_DIR' ' + git rebase --exec "printf %s \$GIT_DIR >environ" HEAD~1 && + test_must_be_empty environ +' + +test_expect_success 'rebase --exec does not muck with GIT_WORK_TREE' ' + git rebase --exec "printf %s \$GIT_WORK_TREE >environ" HEAD~1 && + test_must_be_empty environ +'
I guess we could add a test for existing GIT_DIR in the environment, even if it's not affected
test_expect_success 'already exported GIT_DIR is passed on to rebase --exec commands' ' GIT_DIR=.git GIT_WORK_TREE=. git rebase HEAD~1 --exec \ "printf %s\\\\n \"\$GIT_DIR\" \"\$GIT_WORK_TREE\" >actual" && cat >expect <<-EOF && .git . EOF test_cmp expect actual && cat actual '
(I tried to use non-default values lik ./.git and ./. but the weird thing is that git canonicalizes the worktree but not the git dir, so meh)
I also wasn't sure about the behavior of --git-dir= Should it be the same as GIT_DIR=? I think it's also conceivable that --git-dir= does *not* cause GIT_DIR to be exported to exec commands, though that might break existing
scripts. Something like
git --work-tree=../other-worktree --git-dir=../other-worktree/.git \ rebase --exec "make generate-documentation && git commit -a --amend --no-edit"
(needless to say that in this case "git -C ../other-worktree" is probably what the user wants)
// Resending this email from 8 days ago; Dscho pointed that I accidentally // responded to the GitHub PR email instead of the original email, and // while Johannes already said he likes my V2, perhaps there are other // comments here that benefit other current or future reviewers
Hi Johannes,
Thanks for looking over the patch and commit message closely; very cool.
Quoted 24 lines · Johannes Altmanninger
Quoted 7 lines · Elijah Newren via GitGitGadget
From: Elijah Newren <[email protected]>
Commands executed from
git rebase --execcan give different behavior from within that environment than they would outside of it, due to the fact thatsequencer.cexports bothGIT_DIRandGIT_WORK_TREE. For example, if the relevant script calls something likeQuoted 5 lines
git -C ../otherdir log --format=%H --no-walkthe user may be surprised to find that the command above does not show a commit hash from ../otherdir, because $GIT_DIR prevents automatic gitdir detection and makes the -C option useless.
Yep. I've had a case where "git rebase -x 'make test'" would fail because "make test" tries to run some Git commands in a temporary repo. The workaround was to unset all GIT_* environment variables, just like
t/test-lib.shdoes.I had the same problem when testing shell completion because git prepends $(git --exec-path) to $PATH. I don't see a good reason why "git rebase -x cmd" passes a modified $PATH (and $GIT_EXEC_PATH) to cmd. The user is back in control, so I'd expect the same environment as for the parent rebase process.
Quoted 7 lines
AFAICT, the main purpose of changing $PATH is to ease (cross-language) implementation, I don't think the user is meant to notice.
Of course, exportingGIT_EXEC_PATHis desirable for some commands like gc that delegate to a bunch of git processes without user interaction, to make sure all children are from the same build.c90d565a46(Propagate --exec-path setting to external commands viaGIT_EXEC_PATH, 2009-03-21). But I don't think the same applies for rebase -x.
Well, rebase does actually delegate to other git processes -- git commit (in some cases), git stash (if --autostash is specified), git merge (when a non-default, non-built-in strategy is selected), running the post-rewrite hook (if it exists), and indirectly through git commit all the various hooks it might call, and when calling git-stash the huge pile of subcommands it invokes.
Some of those should definitely be replaced with library calls instead of forking a subprocess. And I'm sure the PATH/EXEC_PATH could be made specific to the places that really need it, but it's so much easier to just make one global replacement and it avoids people forgetting to do so before calling subcommands that then might run the wrong git version in a different setup. So, I'm a bit conflicted about fixing PATH/EXEC_PATH right away. Perhaps if we just modified those back to their original value just the for --exec'd command?
That probably deserves a series all of its own, but might be interesting for someone else to look at.
Quoted 12 lines
Quoted 6 lines
This is a regression in behavior from the original legacy implemented-in-shell rebase. It is perhaps rare for it to cause problems in practice, especially since most small problems that were caused by this area of bugs has been fixed-up in the past in a way that masked the particular bug observed without fixing the real underlying problem.
Really interesting that we added multiple workarounds, when we just needed to stop polluting the environment. The fact that our test suite unsets most GIT_* variables also masks potential problems.
Quoted 1 line
Quoted 4 lines
Quoted 1 line
How we arrived at the current situation is perhaps merited. The setting
This sounds weirdly penitent if read the wrong way. I guess "An explanation how we arrived ... "?
Indeed, thanks for catching.
Quoted 10 lines
Quoted 10 lines
of
GIT_DIRandGIT_WORK_TREEdone bysequencer.carose from a sequence of historical accidents:* When rebase was implemented as a shell command, it would call git-sh-setup, which among other things would set
GIT_DIR-- but not export it. This meant that when rebase --exec commands were run via/bin/sh -c "$COMMAND"they would not inherit the
GIT_DIRsetting. The fact thatGIT_DIRwas not set in the run $COMMAND is the behavior we'd like to restore.
Quoted 5 lines
Quoted 2 lines
* When the rebase--helper builtin was introduced to allow incrementally replacing shell with C code, we were in an implementation that was
More correct to say "we were in an (implementation) state" or better:
"we had an implementation"?
Yes, that'd be better.
Quoted 34 lines
Quoted 3 lines
half shell, half C. In particular, commit
18633e1a22("rebase -i: use the rebase--helper builtin", 2017-02-09) added calls to
exec git rebase--helper ...Ok I guess this was a good reason for adding the exec-path to the environment of exec steps.
Quoted 27 lines
which caused rebase--helper to inherit the
GIT_DIRenvironment variable from the shell. git's setup would change the environment variable from an absolute path to a relative one (".git"), but would leave it set. This meant that when rebase --exec commands were run viarun_command_v_opt(...)they would inherit the
GIT_DIRsetting.* In commit
09d7b6c6fa("sequencer: pass absoluteGIT_DIRto exec commands", 2017-10-31), it was noted that theGIT_DIRcaused problems with some commands; e.g.git rebase --exec 'cd subdir && git describe' ... would have GIT_DIR=.git which was invalid due to the change to the subdirectory. Instead of questioning why GIT_DIR was set, that commit instead made sequencer change GIT_DIR to be an absolute path and explicitly export it via argv_array_pushf(&child_env, "GIT_DIR=%s", absolute_path(get_git_dir())); run_command_v_opt_cd_env(..., child_env.argv)* In commit
ab5e67d751("sequencer: pass absoluteGIT_WORK_TREEto exec commands", 2018-07-14), it was noted that whenGIT_DIRis set butGIT_WORK_TREEis not, that we do not discoverGIT_WORK_TREEbut just assume it is '.'. That is incorrect if trying to run commands from a subdirectory. However, rather than question whyGIT_DIRwas set, that commit instead also addedGIT_WORK_TREEto the list of things to export.
Quoted 4 lines
Quoted 2 lines
Each of the above problems would have been fixed automatically when git-rebase become a full builtin, had it not been for the fact that
s/become/became/
Yep; will fix.
Quoted 9 lines
Quoted 7 lines
sequencer.cstarted exportingGIT_DIRandGIT_WORK_TREEin the interim. Stop exporting them now.Signed-off-by Elijah Newren <[email protected]>---
sequencer: fix environment that 'exec' commands run underMaybe: sequencer: do not export
GIT_DIRandGIT_WORK_TREEto exec
Works for me.
Quoted 1 line
(assuming that $PATH also needs fixing)
I'll leave that to someone else. :-)
Quoted 7 lines
Quoted 2 lines
I'm not sure if the added regression tests make sense
They are simple and correct.
We still pass on values from --git-dir= and GIT_DIR=. git. Those are /probably/ right.
Quoted 5 lines
Quoted 2 lines
or if t3409 is the best place to put them (taking over a recently removed t3409 that was used for the deprecated preserve merges option).
Looks like there is no
t/t34*-rebase-exec.shyet. Most tests of --exec are int/t3404-rebase-interactive.sh, but we don't need the interactive bit here.
Yeah, I didn't want to add to t3404, because (a) there's a comment at the top of the file saying all files are about a certain type of test setup that just isn't applicable to my new test, (b) t3404 is already one of the slowest tests.
Also, I considered naming it rebase-exec.sh, but (1) there are more tests of that in t3404 already and (2) I thought folks might have reason to add additional environment related tests and this would be a good place for all those tests. The fact that you brought up additional environment variables suggests that might indeed be a good track.
Quoted 41 lines
Quoted 41 lines
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1134%2Fnewren%2Ffix-rebase-exec-environ-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1134/newren/fix-rebase-exec-environ-v1
Pull-Request: https://github.com/git/git/pull/1134sequencer.c | 9 +-------- t/t3409-rebase-environ.sh | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) create mode 100755 t/t3409-rebase-environ.shsequencer.c +1
-8@@ -3495,17 +3495,12 @@ static int error_failed_squash(struct repository *r,static int do_exec (struct repository *r,const char *command_line) { -struct strvec child_env =STRVEC_INIT ;const char *child_argv[] = {NULL ,NULL };int dirty, status;fprintf (stderr,_ ("Executing: %s\n" ), command_line); child_argv[0 ] = command_line; -strvec_pushf (&child_env,"GIT_DIR=%s" ,absolute_path (get_git_dir ())); -strvec_pushf (&child_env,"GIT_WORK_TREE=%s" , -absolute_path (get_git_work_tree ())); - status =run_command_v_opt_cd_env (child_argv,RUN_USING_SHELL ,NULL , - child_env.v); + status =run_command_v_opt (child_argv,RUN_USING_SHELL );/* force re-reading of the cache */ if (discard_index (r->index) <0 ||repo_read_index (r) <0 )@@ -3535,8 +3530,6 @@ static int do_exec(struct repository *r, const char *command_line) status =1 ; } -strvec_clear (&child_env); -return status; }
Quoted 11 lines
t/t3409-rebase-environ.sh line 3
Quoted 9 lines
t/t3409-rebase-environ.sh new file +3
-0@@ -0,0 +1,23 @@ +#!/bin/sh + +test_description='git rebase interactive environment'maybe test_description='git rebase --exec environment'
Yep, I need to remove 'interactive' here and it probably makes sense to mention --exec unless someone adds a test to it for environment variables with some other part of rebase.
Quoted 33 lines
Quoted 8 lines
t/t3409-rebase-environ.sh new file +8
-0+ +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit one && + test_commit two && + test_commit three +'t/t3409-rebase-environ.sh line 21
Quoted 10 lines
t/t3409-rebase-environ.sh new file +10
-0+ +test_expect_success 'rebase --exec does not muck with GIT_DIR' ' + git rebase --exec "printf %s \$GIT_DIR >environ" HEAD~1 && + test_must_be_empty environ +' + +test_expect_success 'rebase --exec does not muck with GIT_WORK_TREE' ' + git rebase --exec "printf %s \$GIT_WORK_TREE >environ" HEAD~1 && + test_must_be_empty environ +'I guess we could add a test for existing
GIT_DIRin the environment, even if it's not affectedtest_expect_success 'already exported GIT_DIR is passed on to rebase --exec commands' ' GIT_DIR=.git GIT_WORK_TREE=. git rebase HEAD~1 --exec \ "printf %s\\\\n \"\$GIT_DIR\" \"\$GIT_WORK_TREE\" >actual" && cat >expect <<-EOF && .git . EOF test_cmp expect actual && cat actual '
Quoted 2 lines
(I tried to use non-default values lik ./.git and ./. but the weird thing is that git canonicalizes the worktree but not the git dir, so meh)
It also changes the current working directory to the specified work tree, which makes the test start testing stuff other than I was expecting; the following passes:
test_expect_success 'setup alternate GIT_DIR and GIT_WORK_TREE' '
git clone . other-copy &&
git worktree add other-worktree
'
test_expect_success 'already exported GIT_DIR is passed on to rebase --exec commands' '
test_when_finished "rm other-worktree/actual" &&
GIT_DIR=other-copy/.git GIT_WORK_TREE=other-worktree \
git rebase HEAD~1 --exec \
"printf %s\\\\n \"\$GIT_DIR\" \"\$GIT_WORK_TREE\" \"\$PWD\" >actual" &&
cat >expect <<-EOF &&
$(cd other-copy && pwd -P)/.git
.
$(cd other-worktree && pwd -P)
EOF
test_cmp expect other-worktree/actual'
I don't know if that's correct or buggy, but it's starting to stray from what I was intending to test so I might leave it out.
Quoted 10 lines
I also wasn't sure about the behavior of --git-dir= Should it be the same as GIT_DIR=? I think it's also conceivable that --git-dir= does *not* cause
GIT_DIRto be exported to exec commands, though that might break existing
scripts. Something likegit --work-tree=../other-worktree --git-dir=../other-worktree/.git \ rebase --exec "make generate-documentation && git commit -a --amend --no-edit"(needless to say that in this case "git -C ../other-worktree" is probably what the user wants)
It sets the variables; the following passes (which differs from above only in using --git-dir and --work-tree rather than GIT_DIR and GIT_WORK_TREE):
test_expect_success 'specialized --git-dir/--work-tree and rebase --exec commands' '
test_when_finished "rm other-worktree/actual" &&
git --git-dir=other-copy/.git --work-tree=other-worktree \
rebase HEAD~1 --exec \
"printf %s\\\n \"\$GIT_DIR\" \"\$GIT_WORK_TREE\" \"\$PWD\" >actual" &&
cat >expect <<-EOF &&
$(cd other-copy && pwd -P)/.git
.
$(cd other-worktree && pwd -P)
EOF
test_cmp expect other-worktree/actual'
Quoted 50 lines · Elijah Newren
// Resending this email from 8 days ago; Dscho pointed that I accidentally // responded to the GitHub PR email instead of the original email, and // while Johannes already said he likes my V2, perhaps there are other // comments here that benefit other current or future reviewers
Hi Johannes,
Thanks for looking over the patch and commit message closely; very cool.
Quoted 24 lines · Johannes Altmanninger
Quoted 7 lines · Elijah Newren via GitGitGadget
From: Elijah Newren <[email protected]>
Commands executed from
git rebase --execcan give different behavior from within that environment than they would outside of it, due to the fact thatsequencer.cexports bothGIT_DIRandGIT_WORK_TREE. For example, if the relevant script calls something likeQuoted 5 lines
git -C ../otherdir log --format=%H --no-walkthe user may be surprised to find that the command above does not show a commit hash from ../otherdir, because $GIT_DIR prevents automatic gitdir detection and makes the -C option useless.
Yep. I've had a case where "git rebase -x 'make test'" would fail because "make test" tries to run some Git commands in a temporary repo. The workaround was to unset all GIT_* environment variables, just like
t/test-lib.shdoes.I had the same problem when testing shell completion because git prepends $(git --exec-path) to $PATH. I don't see a good reason why "git rebase -x cmd" passes a modified $PATH (and $GIT_EXEC_PATH) to cmd. The user is back in control, so I'd expect the same environment as for the parent rebase process.
Quoted 7 lines
AFAICT, the main purpose of changing $PATH is to ease (cross-language) implementation, I don't think the user is meant to notice.
Of course, exportingGIT_EXEC_PATHis desirable for some commands like gc that delegate to a bunch of git processes without user interaction, to make sure all children are from the same build.c90d565a46(Propagate --exec-path setting to external commands viaGIT_EXEC_PATH, 2009-03-21). But I don't think the same applies for rebase -x.Well, rebase does actually delegate to other git processes -- git commit (in some cases), git stash (if --autostash is specified), git merge (when a non-default, non-built-in strategy is selected), running the post-rewrite hook (if it exists), and indirectly through git commit all the various hooks it might call, and when calling git-stash the huge pile of subcommands it invokes.
Quoted 8 lines
Some of those should definitely be replaced with library calls instead of forking a subprocess. And I'm sure the PATH/EXEC_PATH could be made specific to the places that really need it, but it's so much easier to just make one global replacement and it avoids people forgetting to do so before calling subcommands that then might run the wrong git version in a different setup. So, I'm a bit conflicted about fixing PATH/EXEC_PATH right away. Perhaps if we just modified those back to their original value just the for --exec'd command?
Yeah that sounds like a good approach, and it seems like a reasonable cleanup.
Quoted 25 lines
That probably deserves a series all of its own, but might be interesting for someone else to look at.
...
the following passes:
test_expect_success'setup alternateGIT_DIRandGIT_WORK_TREE' '
git clone . other-copy &&
git worktree add other-worktree
'
test_expect_success'already exportedGIT_DIRis passed on to rebase --exec commands' 'test_when_finished "rm other-worktree/actual" && GIT_DIR=other-copy/.git GIT_WORK_TREE=other-worktree \ git rebase HEAD~1 --exec \ "printf %s\\\\n \"\$GIT_DIR\" \"\$GIT_WORK_TREE\" \"\$PWD\" >actual" && cat >expect <<-EOF && $(cd other-copy && pwd -P)/.git . $(cd other-worktree && pwd -P) EOF test_cmp expect other-worktree/actual
Quoted 3 lines
'
I don't know if that's correct or buggy
Me neither. I feel like the current behavior (exporting GIT_WORK_TREE=.) is a bit better than dropping GIT_WORK_TREE from the environment of exec runs.
Quoted 11 lines
but it's starting to stray
from what I was intending to test so I might leave it out.Quoted 8 lines
I also wasn't sure about the behavior of --git-dir= Should it be the same as GIT_DIR=? I think it's also conceivable that --git-dir= does *not* cause
GIT_DIRto be exported to exec commands, though that might break existing
scripts. Something likegit --work-tree=../other-worktree --git-dir=../other-worktree/.git \ rebase --exec "make generate-documentation && git commit -a --amend --no-edit"
Quoted 6 lines
Quoted 2 lines
(needless to say that in this case "git -C ../other-worktree" is probably what the user wants)
It sets the variables; the following passes (which differs from above only in using --git-dir and --work-tree rather than
GIT_DIRandGIT_WORK_TREE):
Looking at this again, --git-dir is meant to be able to dominate $GIT_DIR, so the current behavior where --git-dir exports that variable seems logical.
PATCH v2 1/1 sequencer: do not export GIT_DIR and GIT_WORK_TREE for 'exec'
In reply to Elijah Newren via GitGitGadgetFrom: Elijah Newren <[email protected]>
Commands executed from git rebase --exec can give different behavior from within that environment than they would outside of it, due to the fact that sequencer.c exports both GIT_DIR and GIT_WORK_TREE. For example, if the relevant script calls something like
git -C ../otherdir log --format=%H --no-walk
the user may be surprised to find that the command above does not show a commit hash from ../otherdir, because $GIT_DIR prevents automatic gitdir detection and makes the -C option useless.
This is a regression in behavior from the original legacy implemented-in-shell rebase. It is perhaps rare for it to cause problems in practice, especially since most small problems that were caused by this area of bugs has been fixed-up in the past in a way that masked the particular bug observed without fixing the real underlying problem.
An explanation of how we arrived at the current situation is perhaps merited. The setting of GIT_DIR and GIT_WORK_TREE done by sequencer.c arose from a sequence of historical accidents:
* When rebase was implemented as a shell command, it would call git-sh-setup, which among other things would set GIT_DIR -- but not export it. This meant that when rebase --exec commands were run via
/bin/sh -c "$COMMAND"
they would not inherit the GIT_DIR setting. The fact that GIT_DIR was not set in the run $COMMAND is the behavior we'd like to restore.
* When the rebase--helper builtin was introduced to allow incrementally replacing shell with C code, we had an implementation that was half shell, half C. In particular, commit 18633e1a22 ("rebase -i: use the rebase--helper builtin", 2017-02-09) added calls to
exec git rebase--helper ...
which caused rebase--helper to inherit the GIT_DIR environment variable from the shell. git's setup would change the environment variable from an absolute path to a relative one (".git"), but would leave it set. This meant that when rebase --exec commands were run via
run_command_v_opt(...)
they would inherit the GIT_DIR setting.
* In commit 09d7b6c6fa ("sequencer: pass absolute GIT_DIR to exec commands", 2017-10-31), it was noted that the GIT_DIR caused problems with some commands; e.g.
git rebase --exec 'cd subdir && git describe' ...
would have GIT_DIR=.git which was invalid due to the change to the
subdirectory. Instead of questioning why GIT_DIR was set, that commit
instead made sequencer change GIT_DIR to be an absolute path and
explicitly export it via
argv_array_pushf(&child_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
run_command_v_opt_cd_env(..., child_env.argv)* In commit ab5e67d751 ("sequencer: pass absolute GIT_WORK_TREE to exec commands", 2018-07-14), it was noted that when GIT_DIR is set but GIT_WORK_TREE is not, that we do not discover GIT_WORK_TREE but just assume it is '.'. That is incorrect if trying to run commands from a subdirectory. However, rather than question why GIT_DIR was set, that commit instead also added GIT_WORK_TREE to the list of things to export.
Each of the above problems would have been fixed automatically when git-rebase became a full builtin, had it not been for the fact that sequencer.c started exporting GIT_DIR and GIT_WORK_TREE in the interim. Stop exporting them now.
---
sequencer: fix environment that 'exec' commands run under
Changes since v1:
* Fix wording in multiple locations pointed out by Johannes Altmanninger
Note that Johaness Altmanninger also suggested some additional GIT_DIR/GIT_WORK_TREE and --git-dir/--work-tree testcases, but since those change the current working directory to the work tree so that GIT_WORK_TREE ends up being '.' in every case, I think it's straying a bit from the point of the test. If other feel strongly, I can add them in.
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1134%2Fnewren%2Ffix-rebase-exec-environ-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1134/newren/fix-rebase-exec-environ-v2
Pull-Request: https://github.com/git/git/pull/1134
Range-diff vs v1:
1: 12713c83705 ! 1: c647c45375a sequencer: fix environment that 'exec' commands run under
@@ Metadata
Author: Elijah Newren <[email protected]>
## Commit message ##
- sequencer: fix environment that 'exec' commands run under
+ sequencer: do not export GIT_DIR and GIT_WORK_TREE for 'exec'
Commands executed from git rebase --exec can give different behavior from within that environment than they would outside of it, due to the
@@ Commit message
masked the particular bug observed without fixing the real underlying problem.
- How we arrived at the current situation is perhaps merited. The setting
- of GIT_DIR and GIT_WORK_TREE done by sequencer.c arose from a sequence
- of historical accidents:
+ An explanation of how we arrived at the current situation is perhaps
+ merited. The setting of GIT_DIR and GIT_WORK_TREE done by sequencer.c
+ arose from a sequence of historical accidents:
* When rebase was implemented as a shell command, it would call git-sh-setup, which among other things would set GIT_DIR -- but not
@@ Commit message
was not set in the run $COMMAND is the behavior we'd like to restore.
* When the rebase--helper builtin was introduced to allow incrementally
- replacing shell with C code, we were in an implementation that was
- half shell, half C. In particular, commit 18633e1a22 ("rebase -i: use
- the rebase--helper builtin", 2017-02-09) added calls to
+ replacing shell with C code, we had an implementation that was half
+ shell, half C. In particular, commit 18633e1a22 ("rebase -i: use the
+ rebase--helper builtin", 2017-02-09) added calls to
exec git rebase--helper ...
which caused rebase--helper to inherit the GIT_DIR environment variable from the shell. git's setup would change the environment
@@ Commit message
export.
Each of the above problems would have been fixed automatically when
- git-rebase become a full builtin, had it not been for the fact that
+ git-rebase became a full builtin, had it not been for the fact that
sequencer.c started exporting GIT_DIR and GIT_WORK_TREE in the interim. Stop exporting them now.
sequencer.c | 9 +-------- t/t3409-rebase-environ.sh | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) create mode 100755 t/t3409-rebase-environ.sh
sequencer.c +1 -8
@@ -3495,17 +3495,12 @@ static int error_failed_squash(struct repository *r,static int do_exec (struct repository *r,const char *command_line) { -struct strvec child_env =STRVEC_INIT ;const char *child_argv[] = {NULL ,NULL };int dirty, status;fprintf (stderr,_ ("Executing: %s\n" ), command_line); child_argv[0 ] = command_line; -strvec_pushf (&child_env,"GIT_DIR=%s" ,absolute_path (get_git_dir ())); -strvec_pushf (&child_env,"GIT_WORK_TREE=%s" , -absolute_path (get_git_work_tree ())); - status =run_command_v_opt_cd_env (child_argv,RUN_USING_SHELL ,NULL , - child_env.v); + status =run_command_v_opt (child_argv,RUN_USING_SHELL );/* force re-reading of the cache */ if (discard_index (r->index) <0 ||repo_read_index (r) <0 )
@@ -3535,8 +3530,6 @@ static int do_exec(struct repository *r, const char *command_line) status =1 ; } -strvec_clear (&child_env); -return status; }
t/t3409-rebase-environ.sh new file +23 -0
@@ -0,0 +1,23 @@ +#!/bin/sh + +test_description='git rebase interactive environment' + +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit one && + test_commit two && + test_commit three +' + +test_expect_success 'rebase --exec does not muck with GIT_DIR' ' + git rebase --exec "printf %s \$GIT_DIR >environ" HEAD~1 && + test_must_be_empty environ +' + +test_expect_success 'rebase --exec does not muck with GIT_WORK_TREE' ' + git rebase --exec "printf %s \$GIT_WORK_TREE >environ" HEAD~1 && + test_must_be_empty environ +' + +test_done
base-commit: 88d915a634b449147855041d44875322de2b286d
Signature · 1 line
gitgitgadget
Re: [PATCH v2] sequencer: do not export GIT_DIR and GIT_WORK_TREE for 'exec'
Quoted 7 lines · Elijah Newren via GitGitGadget
sequencer: fix environment that 'exec' commands run under
Changes since v1:
* Fix wording in multiple locations pointed out by Johannes Altmanninger
Quoted 6 lines
Note that Johaness Altmanninger also suggested some additional GIT_DIR/GIT_WORK_TREE and --git-dir/--work-tree testcases, but since those change the current working directory to the work tree so that
GIT_WORK_TREEends up being '.' in every case, I think it's straying a bit from the point of the test. If other feel strongly, I can add them in.
Yeah I also think it's better to leave them out for now. For one, the GIT_DIR/GIT_WORK_TREE test is not really interesting. Next, things are not so
obivous: I'm not sure if --git-dir/--work-tree should export those variables to exec but that can be investigated later.
This patch looks great.
Re: [PATCH v2] sequencer: do not export GIT_DIR and GIT_WORK_TREE for 'exec'
In reply to Elijah Newren via GitGitGadgetHi Elijah
Quoted 63 lines · Elijah Newren via GitGitGadget
From: Elijah Newren <[email protected]>
Commands executed from
git rebase --execcan give different behavior from within that environment than they would outside of it, due to the fact thatsequencer.cexports bothGIT_DIRandGIT_WORK_TREE. For example, if the relevant script calls something likegit -C ../otherdir log --format=%H --no-walkthe user may be surprised to find that the command above does not show a commit hash from ../otherdir, because $GIT_DIR prevents automatic gitdir detection and makes the -C option useless.
This is a regression in behavior from the original legacy implemented-in-shell rebase. It is perhaps rare for it to cause problems in practice, especially since most small problems that were caused by this area of bugs has been fixed-up in the past in a way that masked the particular bug observed without fixing the real underlying problem.
An explanation of how we arrived at the current situation is perhaps merited. The setting of
GIT_DIRandGIT_WORK_TREEdone bysequencer.carose from a sequence of historical accidents:* When rebase was implemented as a shell command, it would call git-sh-setup, which among other things would set
GIT_DIR-- but not export it. This meant that when rebase --exec commands were run via/bin/sh -c "$COMMAND"they would not inherit the
GIT_DIRsetting. The fact thatGIT_DIRwas not set in the run $COMMAND is the behavior we'd like to restore.* When the rebase--helper builtin was introduced to allow incrementally replacing shell with C code, we had an implementation that was half shell, half C. In particular, commit
18633e1a22("rebase -i: use the rebase--helper builtin", 2017-02-09) added calls to
exec git rebase--helper ...
which caused rebase--helper to inherit theGIT_DIRenvironment variable from the shell. git's setup would change the environment variable from an absolute path to a relative one (".git"), but would leave it set. This meant that when rebase --exec commands were run viarun_command_v_opt(...)they would inherit the
GIT_DIRsetting.* In commit
09d7b6c6fa("sequencer: pass absoluteGIT_DIRto exec commands", 2017-10-31), it was noted that theGIT_DIRcaused problems with some commands; e.g.git rebase --exec 'cd subdir && git describe' ... would have GIT_DIR=.git which was invalid due to the change to the subdirectory. Instead of questioning why GIT_DIR was set, that commit instead made sequencer change GIT_DIR to be an absolute path and explicitly export it via argv_array_pushf(&child_env, "GIT_DIR=%s", absolute_path(get_git_dir())); run_command_v_opt_cd_env(..., child_env.argv)* In commit
ab5e67d751("sequencer: pass absoluteGIT_WORK_TREEto exec commands", 2018-07-14), it was noted that whenGIT_DIRis set butGIT_WORK_TREEis not, that we do not discoverGIT_WORK_TREEbut just assume it is '.'. That is incorrect if trying to run commands from a subdirectory. However, rather than question whyGIT_DIRwas set, that commit instead also addedGIT_WORK_TREEto the list of things to export.
Quoted 4 lines
Each of the above problems would have been fixed automatically when git-rebase became a full builtin, had it not been for the fact that
sequencer.cstarted exportingGIT_DIRandGIT_WORK_TREEin the interim. Stop exporting them now.
Thanks for fixing this. The commit message does a great job of explaining the problem and how we got there. The patch looks fine to me though I think all the exec tests live in t3404 (interactive and non interactive) so it feels a bit strange to add a new test file just for this. There are plenty of uses of --exec in other test files but I think they are just using the exec command as part of the test rather than testing the --exec functionality (with the exception of t3418 which tests --reschedule-failed-exec)
Best Wishes
Phillip
Quoted 139 lines
Signed-off-by Elijah Newren <[email protected]>---
sequencer: fix environment that 'exec' commands run underChanges since v1:
* Fix wording in multiple locations pointed out by Johannes Altmanninger
Note that Johaness Altmanninger also suggested some additional GIT_DIR/GIT_WORK_TREE and --git-dir/--work-tree testcases, but since those change the current working directory to the work tree so that
GIT_WORK_TREEends up being '.' in every case, I think it's straying a bit from the point of the test. If other feel strongly, I can add them in.Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1134%2Fnewren%2Ffix-rebase-exec-environ-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1134/newren/fix-rebase-exec-environ-v2
Pull-Request: https://github.com/git/git/pull/1134Range-diff vs v1:
1:
12713c83705! 1:c647c45375asequencer: fix environment that 'exec' commands run under
@@ Metadata
Author: Elijah Newren <[email protected]>## Commit message ##
- sequencer: fix environment that 'exec' commands run under
+ sequencer: do not exportGIT_DIRandGIT_WORK_TREEfor 'exec'Commands executed from
git rebase --execcan give different behavior from within that environment than they would outside of it, due to the
@@ Commit message
masked the particular bug observed without fixing the real underlying problem.- How we arrived at the current situation is perhaps merited. The setting
- ofGIT_DIRandGIT_WORK_TREEdone bysequencer.carose from a sequence
- of historical accidents:
+ An explanation of how we arrived at the current situation is perhaps
+ merited. The setting ofGIT_DIRandGIT_WORK_TREEdone bysequencer.c
+ arose from a sequence of historical accidents:* When rebase was implemented as a shell command, it would call git-sh-setup, which among other things would set
GIT_DIR-- but not
@@ Commit message
was not set in the run $COMMAND is the behavior we'd like to restore.* When the rebase--helper builtin was introduced to allow incrementally
- replacing shell with C code, we were in an implementation that was
- half shell, half C. In particular, commit18633e1a22("rebase -i: use
- the rebase--helper builtin", 2017-02-09) added calls to
+ replacing shell with C code, we had an implementation that was half
+ shell, half C. In particular, commit18633e1a22("rebase -i: use the
+ rebase--helper builtin", 2017-02-09) added calls to
exec git rebase--helper ...
which caused rebase--helper to inherit theGIT_DIRenvironment variable from the shell. git's setup would change the environment
@@ Commit message
export.Each of the above problems would have been fixed automatically when
- git-rebase become a full builtin, had it not been for the fact that
+ git-rebase became a full builtin, had it not been for the fact that
sequencer.cstarted exportingGIT_DIRandGIT_WORK_TREEin the interim. Stop exporting them now.sequencer.c | 9 +-------- t/t3409-rebase-environ.sh | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 8 deletions(-)create mode 100755
t/t3409-rebase-environ.shsequencer.c +1
-8@@ -3495,17 +3495,12 @@ static int error_failed_squash(struct repository *r,static int do_exec (struct repository *r,const char *command_line) { -struct strvec child_env =STRVEC_INIT ;const char *child_argv[] = {NULL ,NULL };int dirty, status;fprintf (stderr,_ ("Executing: %s\n" ), command_line); child_argv[0 ] = command_line; -strvec_pushf (&child_env,"GIT_DIR=%s" ,absolute_path (get_git_dir ())); -strvec_pushf (&child_env,"GIT_WORK_TREE=%s" , -absolute_path (get_git_work_tree ())); - status =run_command_v_opt_cd_env (child_argv,RUN_USING_SHELL ,NULL , - child_env.v); + status =run_command_v_opt (child_argv,RUN_USING_SHELL );/* force re-reading of the cache */ if (discard_index (r->index) <0 ||repo_read_index (r) <0 )@@ -3535,8 +3530,6 @@ static int do_exec(struct repository *r, const char *command_line) status =1 ; } -strvec_clear (&child_env); -return status; }t/t3409-rebase-environ.sh new file +23
-0@@ -0,0 +1,23 @@ +#!/bin/sh + +test_description='git rebase interactive environment' + +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit one && + test_commit two && + test_commit three +' + +test_expect_success 'rebase --exec does not muck with GIT_DIR' ' + git rebase --exec "printf %s \$GIT_DIR >environ" HEAD~1 && + test_must_be_empty environ +' + +test_expect_success 'rebase --exec does not muck with GIT_WORK_TREE' ' + git rebase --exec "printf %s \$GIT_WORK_TREE >environ" HEAD~1 && + test_must_be_empty environ +' + +test_donebase-commit:
88d915a634b449147855041d44875322de2b286d
PATCH v3 1/1 sequencer: do not export GIT_DIR and GIT_WORK_TREE for 'exec'
In reply to Elijah Newren via GitGitGadgetFrom: Elijah Newren <[email protected]>
Commands executed from git rebase --exec can give different behavior from within that environment than they would outside of it, due to the fact that sequencer.c exports both GIT_DIR and GIT_WORK_TREE. For example, if the relevant script calls something like
git -C ../otherdir log --format=%H --no-walk
the user may be surprised to find that the command above does not show a commit hash from ../otherdir, because $GIT_DIR prevents automatic gitdir detection and makes the -C option useless.
This is a regression in behavior from the original legacy implemented-in-shell rebase. It is perhaps rare for it to cause problems in practice, especially since most small problems that were caused by this area of bugs has been fixed-up in the past in a way that masked the particular bug observed without fixing the real underlying problem.
An explanation of how we arrived at the current situation is perhaps merited. The setting of GIT_DIR and GIT_WORK_TREE done by sequencer.c arose from a sequence of historical accidents:
* When rebase was implemented as a shell command, it would call git-sh-setup, which among other things would set GIT_DIR -- but not export it. This meant that when rebase --exec commands were run via
/bin/sh -c "$COMMAND"
they would not inherit the GIT_DIR setting. The fact that GIT_DIR was not set in the run $COMMAND is the behavior we'd like to restore.
* When the rebase--helper builtin was introduced to allow incrementally replacing shell with C code, we had an implementation that was half shell, half C. In particular, commit 18633e1a22 ("rebase -i: use the rebase--helper builtin", 2017-02-09) added calls to
exec git rebase--helper ...
which caused rebase--helper to inherit the GIT_DIR environment variable from the shell. git's setup would change the environment variable from an absolute path to a relative one (".git"), but would leave it set. This meant that when rebase --exec commands were run via
run_command_v_opt(...)
they would inherit the GIT_DIR setting.
* In commit 09d7b6c6fa ("sequencer: pass absolute GIT_DIR to exec commands", 2017-10-31), it was noted that the GIT_DIR caused problems with some commands; e.g.
git rebase --exec 'cd subdir && git describe' ...
would have GIT_DIR=.git which was invalid due to the change to the
subdirectory. Instead of questioning why GIT_DIR was set, that commit
instead made sequencer change GIT_DIR to be an absolute path and
explicitly export it via
argv_array_pushf(&child_env, "GIT_DIR=%s", absolute_path(get_git_dir()));
run_command_v_opt_cd_env(..., child_env.argv)* In commit ab5e67d751 ("sequencer: pass absolute GIT_WORK_TREE to exec commands", 2018-07-14), it was noted that when GIT_DIR is set but GIT_WORK_TREE is not, that we do not discover GIT_WORK_TREE but just assume it is '.'. That is incorrect if trying to run commands from a subdirectory. However, rather than question why GIT_DIR was set, that commit instead also added GIT_WORK_TREE to the list of things to export.
Each of the above problems would have been fixed automatically when git-rebase became a full builtin, had it not been for the fact that sequencer.c started exporting GIT_DIR and GIT_WORK_TREE in the interim. Stop exporting them now.
---
sequencer: fix environment that 'exec' commands run under
Changes since v2:
* Make sure I've included all 3 Acked-by's.
* The 2.35 cycle has started and it's been weeks since I sent v2, so it's time to resend. :-)
Changes since v1:
* Fix wording in multiple locations pointed out by Johannes Altmanninger
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1134%2Fnewren%2Ffix-rebase-exec-environ-v3
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1134/newren/fix-rebase-exec-environ-v3
Pull-Request: https://github.com/git/git/pull/1134
Range-diff vs v2:
1: c647c45375a ! 1: 4f5862c212f sequencer: do not export GIT_DIR and GIT_WORK_TREE for 'exec'
@@ Commit message
+ Acked-by: Johannes Altmanninger <[email protected]>
+ Acked-by: Phillip Wood <[email protected]>
## sequencer.c ##
@@ sequencer.c: static int error_failed_squash(struct repository *r,
sequencer.c | 9 +-------- t/t3409-rebase-environ.sh | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) create mode 100755 t/t3409-rebase-environ.sh
sequencer.c +1 -8
@@ -3495,17 +3495,12 @@ static int error_failed_squash(struct repository *r,static int do_exec (struct repository *r,const char *command_line) { -struct strvec child_env =STRVEC_INIT ;const char *child_argv[] = {NULL ,NULL };int dirty, status;fprintf (stderr,_ ("Executing: %s\n" ), command_line); child_argv[0 ] = command_line; -strvec_pushf (&child_env,"GIT_DIR=%s" ,absolute_path (get_git_dir ())); -strvec_pushf (&child_env,"GIT_WORK_TREE=%s" , -absolute_path (get_git_work_tree ())); - status =run_command_v_opt_cd_env (child_argv,RUN_USING_SHELL ,NULL , - child_env.v); + status =run_command_v_opt (child_argv,RUN_USING_SHELL );/* force re-reading of the cache */ if (discard_index (r->index) <0 ||repo_read_index (r) <0 )
@@ -3535,8 +3530,6 @@ static int do_exec(struct repository *r, const char *command_line) status =1 ; } -strvec_clear (&child_env); -return status; }
t/t3409-rebase-environ.sh new file +23 -0
@@ -0,0 +1,23 @@ +#!/bin/sh + +test_description='git rebase interactive environment' + +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit one && + test_commit two && + test_commit three +' + +test_expect_success 'rebase --exec does not muck with GIT_DIR' ' + git rebase --exec "printf %s \$GIT_DIR >environ" HEAD~1 && + test_must_be_empty environ +' + +test_expect_success 'rebase --exec does not muck with GIT_WORK_TREE' ' + git rebase --exec "printf %s \$GIT_WORK_TREE >environ" HEAD~1 && + test_must_be_empty environ +' + +test_done
base-commit: 88d915a634b449147855041d44875322de2b286d
Signature · 1 line
gitgitgadget