merge: do not abort early if one strategy fails to handle the merge

builtin/merge is setup to allow multiple strategies to be specified, and it will find the "best" result and use it. This is defeated if some of the merge strategies abort early when they cannot handle the merge. Fix the logic that calls recursive and ort to not do such an early abort, but instead return "2" or "unhandled" so that the next strategy can try to handle the merge. Coming up with a testcase for this is somewhat difficult, since recursive and ort both handle nearly any two-headed merge (there is a separate code path that checks for non-two-headed merges and already returns "2" for them). So use a somewhat synthetic testcase of having the index not match HEAD before the merge starts, since all merge strategies will abort for that. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Jul 23, 2022 at 01:53 UTC 8f240b8bbb63591f15c10e43debaf564e63a66bd
4 files changed +22 -3
builtin/merge.c
+4 -2
@@ -754,8 +754,10 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
754 else
755 clean = merge_recursive(&o, head, remoteheads->item,
756 reversed, &result);
757 - if (clean < 0)
758 - exit(128);
757 + if (clean < 0) {
758 + rollback_lock_file(&lock);
759 + return 2;
760 + }
761 if (write_locked_index(&the_index, &lock,
762 COMMIT_LOCK | SKIP_IF_UNCHANGED))
763 die(_("unable to write %s"), get_index_file());
t/t6402-merge-rename.sh
+1 -1
@@ -210,7 +210,7 @@ test_expect_success 'updated working tree file should prevent the merge' '
210 echo >>M one line addition &&
211 cat M >M.saved &&
212 git update-index M &&
213 - test_expect_code 128 git pull --no-rebase . yellow &&
213 + test_expect_code 2 git pull --no-rebase . yellow &&
214 test_cmp M M.saved &&
215 rm -f M.saved
216 '
t/t6424-merge-unrelated-index-changes.sh
+16
@@ -275,4 +275,20 @@ test_expect_success 'subtree' '
275 test_path_is_missing .git/MERGE_HEAD
276 '
277
278 +test_expect_success 'with multiple strategies, recursive or ort failure do not early abort' '
279 + git reset --hard &&
280 + git checkout B^0 &&
281 +
282 + test_seq 0 10 >a &&
283 + git add a &&
284 +
285 + sane_unset GIT_TEST_MERGE_ALGORITHM &&
286 + test_must_fail git merge -s recursive -s ort -s octopus C^0 >output 2>&1 &&
287 +
288 + grep "Trying merge strategy recursive..." output &&
289 + grep "Trying merge strategy ort..." output &&
290 + grep "Trying merge strategy octopus..." output &&
291 + grep "No merge strategy handled the merge." output
292 +'
293 +
294 test_done
t/t6439-merge-co-error-msgs.sh
+1
@@ -47,6 +47,7 @@ test_expect_success 'untracked files overwritten by merge (fast and non-fast for
47 export GIT_MERGE_VERBOSITY &&
48 test_must_fail git merge branch 2>out2
49 ) &&
50 + echo "Merge with strategy ${GIT_TEST_MERGE_ALGORITHM:-ort} failed." >>expect &&
51 test_cmp out2 expect &&
52 git reset --hard HEAD^
53 '