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" &&