When rebasing in a subdirectory of a worktree, Git fails due to a dirty worktree: error: The following untracked working tree files would be overwritten by merge: a/b/c Please move or remove them before you merge. This occurs because "git rebase" invokes a "git checkout" without propagating the GIT_WORK_TREE environment variable, causing the worktree to be assumed to be ".". This was not an issue until bc3ae46b42 (rebase: do not attempt to remove startup_info->original_cwd, 2021-12-09), when the .dir of the "git checkout" child process was changed such that it no longer runs at the root of the worktree. Propagate GIT_WORK_TREE to the "git checkout" child process and test that rebase in a subdirectory of a worktree succeeds. Signed-off-by: Glen Choo <chooglen@xxxxxxxxxx> --- Here is a fix for the bug I found in [1]. I didn't look through the rest of the "preserve cwd" thread for other possible bugs pertaining to worktrees, but I didn't find any during a cursory glance at sequencer.c. I'm also not sure if this is the idiomatic way to do it since, I assume, we'd always want to propagate GIT_WORK_TREE, but this is identical to how do_exec() sets GIT_WORK_TREE in the same file (perhaps this is something that should be refactored). [1] https://lore.kernel.org/git/kl6lilu71rzl.fsf@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx sequencer.c | 2 ++ t/t3400-rebase.sh | 29 +++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/sequencer.c b/sequencer.c index 83f257e7fa..e193dcf846 100644 --- a/sequencer.c +++ b/sequencer.c @@ -4233,6 +4233,8 @@ static int run_git_checkout(struct repository *r, struct replay_opts *opts, strvec_push(&cmd.args, "checkout"); strvec_push(&cmd.args, commit); strvec_pushf(&cmd.env_array, GIT_REFLOG_ACTION "=%s", action); + strvec_pushf(&cmd.env_array, "GIT_WORK_TREE=%s", + absolute_path(get_git_work_tree())); if (opts->verbose) ret = run_command(&cmd); diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index 23dbd3c82e..8b8b66538b 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -416,4 +416,33 @@ 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" && + # create commit with foo/bar/baz + mkdir -p foo/bar && + touch foo/bar/baz && + git add foo/bar/baz && + git commit -m "add foo/bar/baz" && + # create commit with a/b/c + mkdir -p a/b && + touch a/b/c && + git add a/b/c && + git commit -m "add a/b/c" && + # create another branch for our other worktree + git branch other && + git worktree add ../other-wt other && + ( + cd ../other-wt && + mkdir -p random/dir && + ( + cd random/dir && + git rebase --onto HEAD^^ HEAD^ # drops the HEAD^ commit + ) + ) + ) +' + test_done base-commit: bc3ae46b420f58dfe2bfd87714dca096a043d554 -- 2.33.GIT