Message ID | 88bdca72a780d70e156e22e1ab96dedd368c761b.1652977582.git.gitgitgadget@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Fix merge restore state | expand |
"Elijah Newren via GitGitGadget" <gitgitgadget@gmail.com> writes: > diff --git a/builtin/merge.c b/builtin/merge.c > index 00de224a2da..ae3ee3a996b 100644 > --- a/builtin/merge.c > +++ b/builtin/merge.c > @@ -377,11 +377,11 @@ static void restore_state(const struct object_id *head, > { > const char *args[] = { "stash", "apply", NULL, NULL }; > > - if (is_null_oid(stash)) > - return; > - > reset_hard(head, 1); when there is only one strategy to be tried, save_state() will never be called. Removing the above safety means the hard-reset is discarding a local change that is not saved anywhere. The reason why the merge stopped may be because such a local change has crashed with the change the merge wanted to bring in, no? > + if (is_null_oid(stash)) > + goto refresh_cache; > + > +test_description="Test that merge state is as expected after failed merge" > + > +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main > +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME > +. ./test-lib.sh > + > +test_expect_success 'set up custom strategy' ' > + test_commit --no-tag "Initial" base base && > +git show-ref && > + > + for b in branch1 branch2 branch3 > + do > + git checkout -b $b main && > + test_commit --no-tag "Change on $b" base $b > + done && > + > + git checkout branch1 && Here, perhaps we can make two additional test cases, that try with local change that (1) overlaps with the changes branch2 and branch3 bring in and that (2) does not overlap. I am worried about the case (2) losing the local change due to the call to reset_hard(). > + test_must_fail git merge branch2 branch3 && > + git diff --exit-code --name-status && > + test_path_is_missing .git/MERGE_HEAD > +' > + > +test_done
Junio C Hamano <gitster@pobox.com> writes: >> +test_expect_success 'set up custom strategy' ' >> + test_commit --no-tag "Initial" base base && >> +git show-ref && >> + >> + for b in branch1 branch2 branch3 >> + do >> + git checkout -b $b main && >> + test_commit --no-tag "Change on $b" base $b >> + done && >> + >> + git checkout branch1 && > > Here, perhaps we can make two additional test cases, that try with > local change that (1) overlaps with the changes branch2 and branch3 > bring in and that (2) does not overlap. I am worried about the case > (2) losing the local change due to the call to reset_hard(). We do not need a new test to demonstrate the breakage in the proposed patch, I think. Here is one place I found that we already test that merging in a dirty working tree fails. We only need to make sure that we do so without losing local changes. t/t6424-merge-unrelated-index-changes.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git c/t/t6424-merge-unrelated-index-changes.sh w/t/t6424-merge-unrelated-index-changes.sh index 89dd544f38..88e0b541a0 100755 --- c/t/t6424-merge-unrelated-index-changes.sh +++ w/t/t6424-merge-unrelated-index-changes.sh @@ -171,7 +171,8 @@ test_expect_success 'octopus, unrelated file touched' ' touch random_file && git add random_file && test_must_fail git merge C^0 D^0 && - test_path_is_missing .git/MERGE_HEAD + test_path_is_missing .git/MERGE_HEAD && + test_path_exists random_file ' test_expect_success 'octopus, related file removed' '
diff --git a/builtin/merge.c b/builtin/merge.c index 00de224a2da..ae3ee3a996b 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -377,11 +377,11 @@ static void restore_state(const struct object_id *head, { const char *args[] = { "stash", "apply", NULL, NULL }; - if (is_null_oid(stash)) - return; - reset_hard(head, 1); + if (is_null_oid(stash)) + goto refresh_cache; + args[2] = oid_to_hex(stash); /* @@ -390,7 +390,9 @@ static void restore_state(const struct object_id *head, */ run_command_v_opt(args, RUN_GIT_CMD); - refresh_cache(REFRESH_QUIET); +refresh_cache: + if (discard_cache() < 0 || read_cache() < 0) + die(_("could not read index")); } /* This is called when no merge was necessary. */ diff --git a/t/t7607-merge-state.sh b/t/t7607-merge-state.sh new file mode 100755 index 00000000000..655478cd0b3 --- /dev/null +++ b/t/t7607-merge-state.sh @@ -0,0 +1,25 @@ +#!/bin/sh + +test_description="Test that merge state is as expected after failed merge" + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME +. ./test-lib.sh + +test_expect_success 'set up custom strategy' ' + test_commit --no-tag "Initial" base base && +git show-ref && + + for b in branch1 branch2 branch3 + do + git checkout -b $b main && + test_commit --no-tag "Change on $b" base $b + done && + + git checkout branch1 && + test_must_fail git merge branch2 branch3 && + git diff --exit-code --name-status && + test_path_is_missing .git/MERGE_HEAD +' + +test_done