summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhillip Wood <phillip.wood@dunelm.org.uk>2022-01-26 13:05:39 +0000
committerJunio C Hamano <gitster@pobox.com>2022-01-26 12:08:52 -0800
commitab2fba0868860e610619f885031217d9cc63097a (patch)
tree3fa8f9c53d7ee91aa027abdff8b6667284ec9ba0
parent69f4c23009ee30faeb61a831f4265791c945783e (diff)
downloadgit-ab2fba0868860e610619f885031217d9cc63097a.tar.gz
rebase: do not remove untracked files on checkout
If "git rebase [--apply|--merge] <upstream> <branch>" detects that <upstream> is an ancestor of <branch> then it will fast-forward and checkout <branch>. Normally a checkout or picking a commit during a rebase will refuse to overwrite untracked files, however rebase does overwrite untracked files when checking out <branch>. The fix is to only set reset in `unpack_tree_opts` if flags contains `RESET_HEAD_HARD`. t5403 may seem like an odd home for the new test but it will be extended in the next commit to check that the post-checkout hook is not run when the checkout fails. The test for `!detach_head` dates back to the original implementation of reset_head() in ac7f467fef ("builtin/rebase: support running "git rebase <upstream>"", 2018-08-07) and was correct until e65123a71d ("builtin rebase: support `git rebase <upstream> <switch-to>`", 2018-09-04) started using reset_head() to checkout <switch-to> when fast-forwarding. Note that 480d3d6bf9 ("Change unpack_trees' 'reset' flag into an enum", 2021-09-27) also fixes this bug as it changes reset_head() to never remove untracked files. I think this fix is still worthwhile as it makes it clear that the same settings are used for detached and non-detached checkouts. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--reset.c2
-rwxr-xr-xt/t5403-post-checkout-hook.sh10
2 files changed, 11 insertions, 1 deletions
diff --git a/reset.c b/reset.c
index 315fef91d3..3e7b9e2e13 100644
--- a/reset.c
+++ b/reset.c
@@ -59,7 +59,7 @@ int reset_head(struct repository *r, struct object_id *oid, const char *action,
unpack_tree_opts.merge = 1;
unpack_tree_opts.preserve_ignored = 0; /* FIXME: !overwrite_ignore */
init_checkout_metadata(&unpack_tree_opts.meta, switch_to_branch, oid, NULL);
- if (!detach_head)
+ if (reset_hard)
unpack_tree_opts.reset = UNPACK_RESET_PROTECT_UNTRACKED;
if (repo_read_index_unmerged(r) < 0) {
diff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh
index 17ab518f26..fd2817b406 100755
--- a/t/t5403-post-checkout-hook.sh
+++ b/t/t5403-post-checkout-hook.sh
@@ -85,6 +85,16 @@ test_rebase () {
test_cmp_rev three $new &&
test $flag = 1
'
+
+ test_expect_success "rebase $args checkout does not remove untracked files" '
+ test_when_finished "test_might_fail git rebase --abort" &&
+ git update-ref refs/heads/rebase-fast-forward three &&
+ git checkout two &&
+ echo untracked >three.t &&
+ test_when_finished "rm three.t" &&
+ test_must_fail git rebase $args HEAD rebase-fast-forward 2>err &&
+ grep "untracked working tree files would be overwritten by checkout" err
+'
}
test_rebase --apply &&