sequencer: be more careful with external merge

If an external merge strategy cannot merge (for example because it would overwrite an untracked file) it exits with a non-zero exit code other than 1. This should be treated differently from a merge with conflicts, which is signaled by an exit code of 1, because, as the merge failed, we need to reschedule the last pick. The caller expects us to return -1 in this case. Also reschedule without trying to merge if the commit message cannot be written as that prevents us from successfully picking the commit. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Phillip Wood committed Jul 15, 2026 at 16:21 UTC 1da85922fddd6f693739385fa08c0d15ad066247
2 files changed +26 -4
sequencer.c
+15 -4
@@ -2453,14 +2453,25 @@ static int do_pick_commit(struct repository *r,
2453 struct commit_list *common = NULL;
2454 struct commit_list *remotes = NULL;
2455
2456 - res = write_message(ctx->message.buf, ctx->message.len,
2457 - git_path_merge_msg(r), 0);
2456 + if (write_message(ctx->message.buf, ctx->message.len,
2457 + git_path_merge_msg(r), 0)) {
2458 + res = -1;
2459 + goto leave;
2460 + }
2461
2462 commit_list_insert(base, &common);
2463 commit_list_insert(next, &remotes);
2461 - res |= try_merge_command(r, opts->strategy,
2462 - opts->xopts.nr, opts->xopts.v,
2464 + res = try_merge_command(r, opts->strategy,
2465 + opts->xopts.nr, opts->xopts.v,
2466 common, oid_to_hex(&head), remotes);
2467 + /*
2468 + * If there were conflicts, try_merge_command() returns 1,
2469 + * any other no-zero return code means that either the merge
2470 + * command could not be run, or it failed to merge.
2471 + */
2472 + if (res && res != 1)
2473 + res = -1;
2474 +
2475 commit_list_free(common);
2476 commit_list_free(remotes);
2477 }
t/t3404-rebase-interactive.sh
+11
@@ -1251,6 +1251,17 @@ test_expect_success 'interrupted rebase -i with --strategy and -X' '
1251 test $(cat file1) = Z
1252 '
1253
1254 +test_expect_success 'failing pick with --strategy is rescheduled' '
1255 + test_when_finished "rm -rf bin; test_might_fail git rebase --abort" &&
1256 + mkdir bin &&
1257 + echo exit 2 | write_script bin/git-merge-fail &&
1258 + git log -1 --format="pick %H # %s" HEAD >expect &&
1259 + test_must_fail env PATH="$PWD/bin:$PATH" \
1260 + git rebase --no-ff --strategy fail HEAD^ &&
1261 + test_cmp expect .git/rebase-merge/git-rebase-todo &&
1262 + test_cmp expect .git/rebase-merge/done
1263 +'
1264 +
1265 test_expect_success 'rebase -i error on commits with \ in message' '
1266 current_head=$(git rev-parse HEAD) &&
1267 test_when_finished "git rebase --abort; git reset --hard $current_head; rm -f error" &&