Skip to content

[2.35 regression] sequencer, stash: fix running from worktree subdir#1205

Closed
newren wants to merge 1 commit intogit:masterfrom
newren:fix-rebase-subdir
Closed

[2.35 regression] sequencer, stash: fix running from worktree subdir#1205
newren wants to merge 1 commit intogit:masterfrom
newren:fix-rebase-subdir

Conversation

@newren
Copy link
Copy Markdown
Contributor

@newren newren commented Jan 25, 2022

Sorry for the regression in Git 2.35; thanks for the report Glen (and Eric for feedback on earlier patches we've been bouncing back and forth that I've incorporated here)

Previous discussion thread starting over here: https://lore.kernel.org/git/kl6lilu71rzl.fsf@chooglen-macbookpro.roam.corp.google.com/ and https://lore.kernel.org/git/20220125233612.46831-1-chooglen@google.com/

cc: Glen Choo chooglen@google.com
cc: Eric Sunshine sunshine@sunshineco.com

@newren newren force-pushed the fix-rebase-subdir branch 3 times, most recently from ff7c4dd to 5847099 Compare January 26, 2022 00:31
@newren newren changed the title sequencer: fix rebase from worktree subdir sequencer, stash: fix running from worktree subdir Jan 26, 2022
@newren newren force-pushed the fix-rebase-subdir branch from 5847099 to e432cf9 Compare January 26, 2022 00:36
In commits bc3ae46 ("rebase: do not attempt to remove
startup_info->original_cwd", 2021-12-09) and 0fce211 ("stash: do not
attempt to remove startup_info->original_cwd", 2021-12-09), we wanted to
allow the subprocess to know which directory the parent process was
running from, so that the subprocess could protect it.  However...

When run from a non-main worktree, setup_git_directory() will note
that the discovered git directory
(/PATH/TO/.git/worktree/non-main-worktree) does not match
DEFAULT_GIT_DIR_ENVIRONMENT (see setup_discovered_git_dir()), and
decide to set GIT_DIR in the environment.  This matters because...

Whenever git is run with the GIT_DIR environment variable set, and
GIT_WORK_TREE not set, it presumes that '.' is the working tree.  So...

This combination results in the subcommand being very confused about
the working tree.  Fix it by also setting the GIT_WORK_TREE environment
variable along with setting cmd.dir.

A possibly more involved fix we could consider for later would be to
make setup.c set GIT_WORK_TREE whenever (a) it discovers both the git
directory and the working tree and (b) it decides to set GIT_DIR in the
environment.  I did not attempt that here as such would be too big of a
change for a 2.35.1 release.

Test-case-by: Glen Choo <chooglen@google.com>
Signed-off-by: Elijah Newren <newren@gmail.com>
@newren newren force-pushed the fix-rebase-subdir branch from e432cf9 to 09e1064 Compare January 26, 2022 00:49
@newren
Copy link
Copy Markdown
Contributor Author

newren commented Jan 26, 2022

/submit

@newren newren changed the title sequencer, stash: fix running from worktree subdir [2.35 regression] sequencer, stash: fix running from worktree subdir Jan 26, 2022
@gitgitgadget-git
Copy link
Copy Markdown

Submitted as pull.1205.git.git.1643161426138.gitgitgadget@gmail.com

To fetch this version into FETCH_HEAD:

git fetch https://github.com/gitgitgadget/git/ pr-git-1205/newren/fix-rebase-subdir-v1

To fetch this version to local tag pr-git-1205/newren/fix-rebase-subdir-v1:

git fetch --no-tags https://github.com/gitgitgadget/git/ tag pr-git-1205/newren/fix-rebase-subdir-v1

@gitgitgadget-git
Copy link
Copy Markdown

On the Git mailing list, Glen Choo wrote (reply to this):

"Elijah Newren via GitGitGadget" <gitgitgadget@gmail.com> writes:

> From: Elijah Newren <newren@gmail.com>
>
> In commits bc3ae46b42 ("rebase: do not attempt to remove
> startup_info->original_cwd", 2021-12-09) and 0fce211ccc ("stash: do not
> attempt to remove startup_info->original_cwd", 2021-12-09), we wanted to
> allow the subprocess to know which directory the parent process was
> running from, so that the subprocess could protect it.  However...
>
> When run from a non-main worktree, setup_git_directory() will note
> that the discovered git directory
> (/PATH/TO/.git/worktree/non-main-worktree) does not match
> DEFAULT_GIT_DIR_ENVIRONMENT (see setup_discovered_git_dir()), and
> decide to set GIT_DIR in the environment.  This matters because...
>
> Whenever git is run with the GIT_DIR environment variable set, and
> GIT_WORK_TREE not set, it presumes that '.' is the working tree.  So...
>
> This combination results in the subcommand being very confused about
> the working tree.  Fix it by also setting the GIT_WORK_TREE environment
> variable along with setting cmd.dir.
>
> A possibly more involved fix we could consider for later would be to
> make setup.c set GIT_WORK_TREE whenever (a) it discovers both the git
> directory and the working tree and (b) it decides to set GIT_DIR in the
> environment.  I did not attempt that here as such would be too big of a
> change for a 2.35.1 release.

As the commit message explains, GIT_DIR and GIT_WORK_TREE are closely
linked, and this interaction is subtle enough that we'd want to guard
against it instead of policing it manually. So, yes, setting them
together makes a lot of sense.

>  builtin/stash.c   |  6 +++++-
>  sequencer.c       |  5 ++++-
>  t/t3400-rebase.sh | 21 +++++++++++++++++++++
>  3 files changed, 30 insertions(+), 2 deletions(-)
>
> diff --git a/builtin/stash.c b/builtin/stash.c
> index 1ef2017c595..86cd0b456e7 100644
> --- a/builtin/stash.c
> +++ b/builtin/stash.c
> @@ -1539,8 +1539,12 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
>  			struct child_process cp = CHILD_PROCESS_INIT;
>  
>  			cp.git_cmd = 1;
> -			if (startup_info->original_cwd)
> +			if (startup_info->original_cwd) {
>  				cp.dir = startup_info->original_cwd;
> +				strvec_pushf(&cp.env_array, "%s=%s",
> +					     GIT_WORK_TREE_ENVIRONMENT,
> +					     the_repository->worktree);
> +			}
>  			strvec_pushl(&cp.args, "clean", "--force",
>  				     "--quiet", "-d", ":/", NULL);
>  			if (include_untracked == INCLUDE_ALL_FILES)
> diff --git a/sequencer.c b/sequencer.c
> index 6abd72160cc..5213d16e971 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -4223,8 +4223,11 @@ static int run_git_checkout(struct repository *r, struct replay_opts *opts,
>  
>  	cmd.git_cmd = 1;
>  
> -	if (startup_info->original_cwd)
> +	if (startup_info->original_cwd) {
>  		cmd.dir = startup_info->original_cwd;
> +		strvec_pushf(&cmd.env_array, "%s=%s",
> +			     GIT_WORK_TREE_ENVIRONMENT, r->worktree);
> +	}
>  	strvec_push(&cmd.args, "checkout");
>  	strvec_push(&cmd.args, commit);
>  	strvec_pushf(&cmd.env_array, GIT_REFLOG_ACTION "=%s", action);
> diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
> index 23dbd3c82ed..71b1735e1dd 100755
> --- a/t/t3400-rebase.sh
> +++ b/t/t3400-rebase.sh
> @@ -416,4 +416,25 @@ test_expect_success MINGW,SYMLINKS_WINDOWS 'rebase when .git/logs is a symlink'
>  	mv actual_logs .git/logs
>  '
>  
> +test_expect_success 'rebase when inside worktree subdirectory' '
> +	git init main-wt &&
> +	(
> +		cd main-wt &&
> +		git commit --allow-empty -m "initial" &&
> +		mkdir -p foo/bar &&
> +		test_commit foo/bar/baz &&
> +		mkdir -p a/b &&
> +		test_commit a/b/c &&
> +		# create another branch for our other worktree
> +		git branch other &&
> +		git worktree add ../other-wt other &&
> +		cd ../other-wt &&
> +		# create and cd into a subdirectory
> +		mkdir -p random/dir &&
> +		cd random/dir &&
> +		# now do the rebase
> +		git rebase --onto HEAD^^ HEAD^  # drops the HEAD^ commit
> +	)
> +'
> +
>  test_done

Looks good :)

Reviewed-by: Glen Choo <chooglen@google.com>

@gitgitgadget-git
Copy link
Copy Markdown

On the Git mailing list, Junio C Hamano wrote (reply to this):

"Elijah Newren via GitGitGadget" <gitgitgadget@gmail.com> writes:

> From: Elijah Newren <newren@gmail.com>
>
> In commits bc3ae46b42 ("rebase: do not attempt to remove
> startup_info->original_cwd", 2021-12-09) and 0fce211ccc ("stash: do not
> attempt to remove startup_info->original_cwd", 2021-12-09), we wanted to
> allow the subprocess to know which directory the parent process was
> running from, so that the subprocess could protect it.  However...
>
> When run from a non-main worktree, setup_git_directory() will note
> that the discovered git directory
> (/PATH/TO/.git/worktree/non-main-worktree) does not match
> DEFAULT_GIT_DIR_ENVIRONMENT (see setup_discovered_git_dir()), and
> decide to set GIT_DIR in the environment.  This matters because...
>
> Whenever git is run with the GIT_DIR environment variable set, and
> GIT_WORK_TREE not set, it presumes that '.' is the working tree.  So...
>
> This combination results in the subcommand being very confused about
> the working tree.  Fix it by also setting the GIT_WORK_TREE environment
> variable along with setting cmd.dir.
>
> A possibly more involved fix we could consider for later would be to
> make setup.c set GIT_WORK_TREE whenever (a) it discovers both the git
> directory and the working tree and (b) it decides to set GIT_DIR in the
> environment.  I did not attempt that here as such would be too big of a
> change for a 2.35.1 release.
>
> Test-case-by: Glen Choo <chooglen@google.com>
> Signed-off-by: Elijah Newren <newren@gmail.com>
> ---
>     [2.35 regression] sequencer, stash: fix running from worktree subdir

Thanks.  This is the kind of fix we all should be concentrating on
in the first week after the release.

Very much appreciated.

Will queue.

> diff --git a/builtin/stash.c b/builtin/stash.c
> index 1ef2017c595..86cd0b456e7 100644
> --- a/builtin/stash.c
> +++ b/builtin/stash.c
> @@ -1539,8 +1539,12 @@ static int do_push_stash(const struct pathspec *ps, const char *stash_msg, int q
>  			struct child_process cp = CHILD_PROCESS_INIT;
>  
>  			cp.git_cmd = 1;
> -			if (startup_info->original_cwd)
> +			if (startup_info->original_cwd) {
>  				cp.dir = startup_info->original_cwd;
> +				strvec_pushf(&cp.env_array, "%s=%s",
> +					     GIT_WORK_TREE_ENVIRONMENT,
> +					     the_repository->worktree);
> +			}
>  			strvec_pushl(&cp.args, "clean", "--force",
>  				     "--quiet", "-d", ":/", NULL);
>  			if (include_untracked == INCLUDE_ALL_FILES)
> diff --git a/sequencer.c b/sequencer.c
> index 6abd72160cc..5213d16e971 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -4223,8 +4223,11 @@ static int run_git_checkout(struct repository *r, struct replay_opts *opts,
>  
>  	cmd.git_cmd = 1;
>  
> -	if (startup_info->original_cwd)
> +	if (startup_info->original_cwd) {
>  		cmd.dir = startup_info->original_cwd;
> +		strvec_pushf(&cmd.env_array, "%s=%s",
> +			     GIT_WORK_TREE_ENVIRONMENT, r->worktree);
> +	}
>  	strvec_push(&cmd.args, "checkout");
>  	strvec_push(&cmd.args, commit);
>  	strvec_pushf(&cmd.env_array, GIT_REFLOG_ACTION "=%s", action);
> diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh
> index 23dbd3c82ed..71b1735e1dd 100755
> --- a/t/t3400-rebase.sh
> +++ b/t/t3400-rebase.sh
> @@ -416,4 +416,25 @@ test_expect_success MINGW,SYMLINKS_WINDOWS 'rebase when .git/logs is a symlink'
>  	mv actual_logs .git/logs
>  '
>  
> +test_expect_success 'rebase when inside worktree subdirectory' '
> +	git init main-wt &&
> +	(
> +		cd main-wt &&
> +		git commit --allow-empty -m "initial" &&
> +		mkdir -p foo/bar &&
> +		test_commit foo/bar/baz &&
> +		mkdir -p a/b &&
> +		test_commit a/b/c &&
> +		# create another branch for our other worktree
> +		git branch other &&
> +		git worktree add ../other-wt other &&
> +		cd ../other-wt &&
> +		# create and cd into a subdirectory
> +		mkdir -p random/dir &&
> +		cd random/dir &&
> +		# now do the rebase
> +		git rebase --onto HEAD^^ HEAD^  # drops the HEAD^ commit
> +	)
> +'
> +
>  test_done
>
> base-commit: 89bece5c8c96f0b962cfc89e63f82d603fd60bed

@gitgitgadget-git
Copy link
Copy Markdown

This branch is now known as en/keep-cwd.

@gitgitgadget-git
Copy link
Copy Markdown

This patch series was integrated into seen via 5331d2e.

@gitgitgadget-git
Copy link
Copy Markdown

This patch series was integrated into seen via ce12846.

@gitgitgadget-git
Copy link
Copy Markdown

This patch series was integrated into next via b2518a6.

@gitgitgadget-git
Copy link
Copy Markdown

This patch series was integrated into seen via b23dac9.

@gitgitgadget-git
Copy link
Copy Markdown

This patch series was integrated into next via b824226.

@gitgitgadget-git
Copy link
Copy Markdown

This patch series was integrated into master via b23dac9.

@gitgitgadget-git
Copy link
Copy Markdown

Closed via b23dac9.

@gitgitgadget-git gitgitgadget-git bot closed this Jan 27, 2022
@newren newren deleted the fix-rebase-subdir branch February 13, 2022 05:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant