From fade29b56515d1529823e1cf99f1de19d930ff5d Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Tue, 30 Jun 2026 16:28:51 +0100 Subject: [PATCH 01/15] t3400: restore coverage for note copying with apply backend Now that the merge backend is the default we have lost coverage for "git rebase --apply" copying notes. Fix this by replacing "-m" with "--apply" as the previous test which uses the default backend now checks the merge backend. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- t/t3400-rebase.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index c0c00fbb7b..f0e7fcf649 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -270,9 +270,9 @@ test_expect_success 'rebase can copy notes' ' test "a note" = "$(git notes show HEAD)" ' -test_expect_success 'rebase -m can copy notes' ' +test_expect_success 'rebase --apply can copy notes' ' git reset --hard n3 && - git rebase -m --onto n1 n2 && + git rebase --apply --onto n1 n2 && test "a note" = "$(git notes show HEAD)" ' From fe6610fcc013f1ff1a77174b28ea1d5900ae7c59 Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Tue, 30 Jun 2026 16:28:52 +0100 Subject: [PATCH 02/15] sequencer: move definition of is_final_fixup() Move this function earlier in the file in preparation for adding a new caller in a later commit. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- sequencer.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/sequencer.c b/sequencer.c index 57855b0066..32a09b6e87 100644 --- a/sequencer.c +++ b/sequencer.c @@ -4629,21 +4629,6 @@ static int do_update_refs(struct repository *r, int quiet) return res; } -static int is_final_fixup(struct todo_list *todo_list) -{ - int i = todo_list->current; - - if (!is_fixup(todo_list->items[i].command)) - return 0; - - while (++i < todo_list->nr) - if (is_fixup(todo_list->items[i].command)) - return 0; - else if (!is_noop(todo_list->items[i].command)) - break; - return 1; -} - static enum todo_command peek_command(struct todo_list *todo_list, int offset) { int i; @@ -4927,6 +4912,21 @@ static int reread_todo_if_changed(struct repository *r, return 0; } +static int is_final_fixup(struct todo_list *todo_list) +{ + int i = todo_list->current; + + if (!is_fixup(todo_list->items[i].command)) + return 0; + + while (++i < todo_list->nr) + if (is_fixup(todo_list->items[i].command)) + return 0; + else if (!is_noop(todo_list->items[i].command)) + break; + return 1; +} + static const char rescheduled_advice[] = N_("Could not execute the todo command\n" "\n" From a24c41eeebb2bc8031bf3fdfcff57cb0410f90c8 Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Tue, 30 Jun 2026 16:28:53 +0100 Subject: [PATCH 03/15] 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 to a merge with conflicts which is signalled 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 Signed-off-by: Junio C Hamano --- sequencer.c | 19 +++++++++++++++---- t/t3404-rebase-interactive.sh | 11 +++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/sequencer.c b/sequencer.c index 32a09b6e87..e6626c4db4 100644 --- a/sequencer.c +++ b/sequencer.c @@ -2453,14 +2453,25 @@ static int do_pick_commit(struct repository *r, struct commit_list *common = NULL; struct commit_list *remotes = NULL; - res = write_message(ctx->message.buf, ctx->message.len, - git_path_merge_msg(r), 0); + if (write_message(ctx->message.buf, ctx->message.len, + git_path_merge_msg(r), 0)) { + res = -1; + goto leave; + } commit_list_insert(base, &common); commit_list_insert(next, &remotes); - res |= try_merge_command(r, opts->strategy, - opts->xopts.nr, opts->xopts.v, + res = try_merge_command(r, opts->strategy, + opts->xopts.nr, opts->xopts.v, common, oid_to_hex(&head), remotes); + /* + * If the there were conflicts, try_merge_command() returns 1, + * any other no-zero return code means that either the merge + * command could not be run, or it failed to merge. + */ + if (res && res != 1) + res = -1; + commit_list_free(common); commit_list_free(remotes); } diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 58b3bb0c27..297b84e60d 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -1251,6 +1251,17 @@ test_expect_success 'interrupted rebase -i with --strategy and -X' ' test $(cat file1) = Z ' +test_expect_success 'failing pick with --strategy is rescheduled' ' + test_when_finished "rm -rf bin; test_might_fail git rebase --abort" && + mkdir bin && + echo exit 2 | write_script bin/git-merge-fail && + git log -1 --format="pick %H # %s" HEAD >expect && + test_must_fail env PATH="$PWD/bin:$PATH" \ + git rebase --no-ff --strategy fail HEAD^ && + test_cmp expect .git/rebase-merge/git-rebase-todo && + test_cmp expect .git/rebase-merge/done +' + test_expect_success 'rebase -i error on commits with \ in message' ' current_head=$(git rev-parse HEAD) && test_when_finished "git rebase --abort; git reset --hard $current_head; rm -f error" && From 8b7330ca47261e414dd72e6ee6233dbb355ce7cf Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Tue, 30 Jun 2026 16:28:54 +0100 Subject: [PATCH 04/15] sequencer: never reschedule on failed commit If "git commit" fails to run then run_git_commit() returns -1 which causes the current command to be rescheduled. This is incorrect as we have successfully picked the commit and have written all the state files we need to successfully commit when the user continues. Fix this by converting -1 to 1 which matches what do_merge() does. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- sequencer.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sequencer.c b/sequencer.c index e6626c4db4..d7e439b1fe 100644 --- a/sequencer.c +++ b/sequencer.c @@ -2542,6 +2542,12 @@ fast_forward_edit: res = run_git_commit(NULL, reflog_action, opts, flags); *check_todo = 1; } + /* + * If "git commit" failed to run than res == -1 but we dont + * want reschedule the last command because the picking the + * commit was successful. + */ + res = !!res; } From 3195ba71ab3bb45b5ca95cffdd887102ea469c7f Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Tue, 30 Jun 2026 16:28:55 +0100 Subject: [PATCH 05/15] sequencer: remove unnecessary "or" in pick_one_commit() If error_with_patch(..., res, ...) succeeds then it returns "res", if it fails then it returns -1. This means that or-ing the return value with "res" is pointless the result is the same as the return value. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- sequencer.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/sequencer.c b/sequencer.c index d7e439b1fe..39cbb7b6e3 100644 --- a/sequencer.c +++ b/sequencer.c @@ -5007,9 +5007,8 @@ static int pick_one_commit(struct repository *r, oideq(&opts->squash_onto, &oid)))) to_amend = 1; - return res | error_with_patch(r, item->commit, - arg, item->arg_len, opts, - res, to_amend); + return error_with_patch(r, item->commit, arg, item->arg_len, + opts, res, to_amend); } return res; } From ab853e67e6be4f8a8ef9cb4d4e85011c27c00593 Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Tue, 30 Jun 2026 16:28:56 +0100 Subject: [PATCH 06/15] sequencer: simplify handing of fixup with conflicts Commit e032abd5a0 (rebase: fix rewritten list for failed pick, 2023-09-06) introduced an early return when res == -1, so if we enter this conditional block then res is positive. After the last couple of commits the only possible positive value is 1 so we can simplify the code by removing the conditional call to intend_to_amend() and call it error_with_patch() instead. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- sequencer.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sequencer.c b/sequencer.c index 39cbb7b6e3..bcfbda018a 100644 --- a/sequencer.c +++ b/sequencer.c @@ -3874,7 +3874,7 @@ static int error_failed_squash(struct repository *r, return error(_("could not copy '%s' to '%s'"), rebase_path_message(), git_path_merge_msg(r)); - return error_with_patch(r, commit, subject, subject_len, opts, 1, 0); + return error_with_patch(r, commit, subject, subject_len, opts, 1, 1); } static int do_exec(struct repository *r, const char *command_line, int quiet) @@ -4986,8 +4986,6 @@ static int pick_one_commit(struct repository *r, record_in_rewritten(&item->commit->object.oid, peek_command(todo_list, 1)); if (res && is_fixup(item->command)) { - if (res == 1) - intend_to_amend(); return error_failed_squash(r, item->commit, opts, item->arg_len, arg); } else if (res && is_rebase_i(opts) && item->commit) { From cb57007513dd753ba4be3224fd565c3b5387c34e Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Tue, 30 Jun 2026 16:28:57 +0100 Subject: [PATCH 07/15] sequencer: remove unnecessary condition in pick_one_commit() item->commit holds the commit to be picked and so it must be non-NULL otherwise pick_one_commit() would not know which commit to pick. It is also unconditionally dereferenced in do_pick_commit() which is called at the top of this function. Therefore the check to see if it is non-NULL is superfluous. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- sequencer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sequencer.c b/sequencer.c index bcfbda018a..ff28873d21 100644 --- a/sequencer.c +++ b/sequencer.c @@ -4988,7 +4988,7 @@ static int pick_one_commit(struct repository *r, if (res && is_fixup(item->command)) { return error_failed_squash(r, item->commit, opts, item->arg_len, arg); - } else if (res && is_rebase_i(opts) && item->commit) { + } else if (res && is_rebase_i(opts)) { int to_amend = 0; struct object_id oid; From 225582efc8f81ba02449f5f14d1448ff19153ffa Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Tue, 30 Jun 2026 16:28:58 +0100 Subject: [PATCH 08/15] sequencer: simplify pick_one_commit() Unless we're rebasing all we do in pick_one_commit() is call do_pick_commit() and return its result. Simplify the code by returing early if we're not rebasing so that we don't have to continually call is_rebase_i() in the rest of the function. Note that there are a couple of conditions that do not call is_rebase_i() but they check for either an "edit" or a "fixup" command, both of which imply we're rebasing. As the conditional blocks are all mutually exclusive (either the conditions are mutually exclusive, or an earlier conditional block that would match a later one contains a "return" statement) chain them together with "else if" to make that clear. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- sequencer.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/sequencer.c b/sequencer.c index ff28873d21..416729f30a 100644 --- a/sequencer.c +++ b/sequencer.c @@ -4966,12 +4966,14 @@ static int pick_one_commit(struct repository *r, res = do_pick_commit(r, item, opts, is_final_fixup(todo_list), check_todo); - if (is_rebase_i(opts) && res < 0) { + if (!is_rebase_i(opts)) + return res; + + if (res < 0) { /* Reschedule */ *reschedule = 1; return -1; - } - if (item->command == TODO_EDIT) { + } else if (item->command == TODO_EDIT) { struct commit *commit = item->commit; if (!res) { if (!opts->verbose) @@ -4981,14 +4983,13 @@ static int pick_one_commit(struct repository *r, } return error_with_patch(r, commit, arg, item->arg_len, opts, res, !res); - } - if (is_rebase_i(opts) && !res) + } else if (!res) { record_in_rewritten(&item->commit->object.oid, peek_command(todo_list, 1)); - if (res && is_fixup(item->command)) { + } else if (res && is_fixup(item->command)) { return error_failed_squash(r, item->commit, opts, item->arg_len, arg); - } else if (res && is_rebase_i(opts)) { + } else if (res) { int to_amend = 0; struct object_id oid; From 92d436adddad31b804aef3a9efc971c48d93ab2b Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Tue, 30 Jun 2026 16:28:59 +0100 Subject: [PATCH 09/15] sequencer: return early from pick_one_commit() on success The only block that does not return early is the one guarded by "!res". Move the return into that block to make it clear that after recording the commit as rewritten all we do is return from the function. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- sequencer.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sequencer.c b/sequencer.c index 416729f30a..655a2e84be 100644 --- a/sequencer.c +++ b/sequencer.c @@ -4986,6 +4986,7 @@ static int pick_one_commit(struct repository *r, } else if (!res) { record_in_rewritten(&item->commit->object.oid, peek_command(todo_list, 1)); + return 0; } else if (res && is_fixup(item->command)) { return error_failed_squash(r, item->commit, opts, item->arg_len, arg); @@ -5009,7 +5010,8 @@ static int pick_one_commit(struct repository *r, return error_with_patch(r, item->commit, arg, item->arg_len, opts, res, to_amend); } - return res; + + BUG("Unhandled return value from do_pick_commit()"); } static int pick_commits(struct repository *r, From 853f67b34a53b7269cde19e7f8c86981405ce5da Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Tue, 30 Jun 2026 16:29:00 +0100 Subject: [PATCH 10/15] sequencer: use an enum to represent result of picking a commit Rather than using an integer where -1 is an error, 0 is success and 1 means there were conflicts use an enum. This is clearer and lets us add a separate return value for commits that are dropped because they become empty in the next commit. Note we continue to use "return error(...)" to return errors and take advantage of C's lax typing of enums Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- sequencer.c | 61 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/sequencer.c b/sequencer.c index 655a2e84be..ca005b969c 100644 --- a/sequencer.c +++ b/sequencer.c @@ -2260,10 +2260,16 @@ static const char *reflog_message(struct replay_opts *opts, return buf.buf; } -static int do_pick_commit(struct repository *r, - struct todo_item *item, - struct replay_opts *opts, - int final_fixup, int *check_todo) +enum pick_result { + PICK_RESULT_ERROR = -1, + PICK_RESULT_OK, + PICK_RESULT_CONFLICTS, +}; + +static enum pick_result do_pick_commit(struct repository *r, + struct todo_item *item, + struct replay_opts *opts, + int final_fixup, int *check_todo) { struct replay_ctx *ctx = opts->ctx; unsigned int flags = should_edit(opts) ? EDIT_MSG : 0; @@ -2564,7 +2570,12 @@ leave: free(author); update_abort_safety_file(); - return res; + if (res < 0) + return PICK_RESULT_ERROR; + else if (res > 0) + return PICK_RESULT_CONFLICTS; + else + return PICK_RESULT_OK; } static int prepare_revs(struct replay_opts *opts) @@ -4960,22 +4971,31 @@ static int pick_one_commit(struct repository *r, struct replay_opts *opts, int *check_todo, int* reschedule) { - int res; + enum pick_result pick_res; struct todo_item *item = todo_list->items + todo_list->current; const char *arg = todo_item_get_arg(todo_list, item); - res = do_pick_commit(r, item, opts, is_final_fixup(todo_list), - check_todo); + pick_res = do_pick_commit(r, item, opts, is_final_fixup(todo_list), + check_todo); if (!is_rebase_i(opts)) - return res; + switch (pick_res) { + case PICK_RESULT_ERROR: + return -1; + case PICK_RESULT_CONFLICTS: + return 1; + default: + return 0; + } - if (res < 0) { + if (pick_res == PICK_RESULT_ERROR) { /* Reschedule */ *reschedule = 1; return -1; } else if (item->command == TODO_EDIT) { struct commit *commit = item->commit; - if (!res) { + int res = pick_res == PICK_RESULT_CONFLICTS; + + if (pick_res == PICK_RESULT_OK) { if (!opts->verbose) term_clear_line(); fprintf(stderr, _("Stopped at %s... %.*s\n"), @@ -4983,14 +5003,15 @@ static int pick_one_commit(struct repository *r, } return error_with_patch(r, commit, arg, item->arg_len, opts, res, !res); - } else if (!res) { + } else if (pick_res == PICK_RESULT_OK) { record_in_rewritten(&item->commit->object.oid, peek_command(todo_list, 1)); return 0; - } else if (res && is_fixup(item->command)) { + } else if (pick_res == PICK_RESULT_CONFLICTS && + is_fixup(item->command)) { return error_failed_squash(r, item->commit, opts, item->arg_len, arg); - } else if (res) { + } else if (pick_res == PICK_RESULT_CONFLICTS) { int to_amend = 0; struct object_id oid; @@ -5008,7 +5029,7 @@ static int pick_one_commit(struct repository *r, to_amend = 1; return error_with_patch(r, item->commit, arg, item->arg_len, - opts, res, to_amend); + opts, 1, to_amend); } BUG("Unhandled return value from do_pick_commit()"); @@ -5547,7 +5568,15 @@ static int single_pick(struct repository *r, TODO_PICK : TODO_REVERT; item.commit = cmit; - return do_pick_commit(r, &item, opts, 0, &check_todo); + switch (do_pick_commit(r, &item, opts, 0, &check_todo)) { + case PICK_RESULT_ERROR: + return -1; + case PICK_RESULT_CONFLICTS: + return 1; + default: + return 0; + } + } int sequencer_pick_revisions(struct repository *r, From 5f504e6fa9c98fc9052d16f8b5049001612ac302 Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Tue, 30 Jun 2026 16:29:01 +0100 Subject: [PATCH 11/15] sequencer: do not record dropped commits as rewritten MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a commit gets dropped because its changes are already upstream then we should not record it as rewritten. As well as confusing any post-rewrite hooks this means we end up copying the notes from the dropped commit to the commit that was picked immediately before the one that was dropped. While we do not want to record the dropped commit is rewritten, if it is the final commit in a chain of fixups then we need to flush the list of rewritten commits. The behavior of an "edit" command where the commit is dropped is changed so that "rebase --continue" will not amend the previous pick. However, as the code comment notes it will still be erroneously recorded as rewritten when the rebase continues. That will need to be addressed separately along with not recording skipped commits as rewritten. The initialization of "drop_commit" is moved to ensure it is initialized when rewording a fast-forwarded commit. Reported-by: Uwe Kleine-König Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- sequencer.c | 24 +++++++++++++++++++----- t/t3400-rebase.sh | 12 ++++++++++++ t/t5407-post-rewrite-hook.sh | 23 +++++++++++++++++++++++ 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/sequencer.c b/sequencer.c index ca005b969c..a85f9e8b77 100644 --- a/sequencer.c +++ b/sequencer.c @@ -2264,6 +2264,7 @@ enum pick_result { PICK_RESULT_ERROR = -1, PICK_RESULT_OK, PICK_RESULT_CONFLICTS, + PICK_RESULT_DROPPED, }; static enum pick_result do_pick_commit(struct repository *r, @@ -2279,7 +2280,7 @@ static enum pick_result do_pick_commit(struct repository *r, const char *base_label, *next_label, *reflog_action; char *author = NULL; struct commit_message msg = { NULL, NULL, NULL, NULL }; - int res, unborn = 0, reword = 0, allow, drop_commit; + int res, unborn = 0, reword = 0, allow, drop_commit = 0; enum todo_command command = item->command; struct commit *commit = item->commit; @@ -2509,7 +2510,6 @@ static enum pick_result do_pick_commit(struct repository *r, goto leave; } - drop_commit = 0; allow = allow_empty(r, opts, commit); if (allow < 0) { res = allow; @@ -2574,6 +2574,8 @@ leave: return PICK_RESULT_ERROR; else if (res > 0) return PICK_RESULT_CONFLICTS; + else if (drop_commit) + return PICK_RESULT_DROPPED; else return PICK_RESULT_OK; } @@ -4994,19 +4996,31 @@ static int pick_one_commit(struct repository *r, } else if (item->command == TODO_EDIT) { struct commit *commit = item->commit; int res = pick_res == PICK_RESULT_CONFLICTS; + int to_amend = pick_res != PICK_RESULT_CONFLICTS && + pick_res != PICK_RESULT_DROPPED; - if (pick_res == PICK_RESULT_OK) { + /* + * NEEDSWORK: Do not record the commit as rewritten when + * continuing if it was dropped. Does it even make sense + * to stop if the commit was dropped? + */ + if (pick_res == PICK_RESULT_OK || + pick_res == PICK_RESULT_DROPPED) { if (!opts->verbose) term_clear_line(); fprintf(stderr, _("Stopped at %s... %.*s\n"), short_commit_name(r, commit), item->arg_len, arg); } - return error_with_patch(r, commit, - arg, item->arg_len, opts, res, !res); + return error_with_patch(r, commit, arg, item->arg_len, opts, + res, to_amend); } else if (pick_res == PICK_RESULT_OK) { record_in_rewritten(&item->commit->object.oid, peek_command(todo_list, 1)); return 0; + } else if (pick_res == PICK_RESULT_DROPPED) { + if (is_final_fixup(todo_list)) + flush_rewritten_pending(); + return 0; } else if (pick_res == PICK_RESULT_CONFLICTS && is_fixup(item->command)) { return error_failed_squash(r, item->commit, opts, diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index f0e7fcf649..1d09886ea3 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -276,6 +276,18 @@ test_expect_success 'rebase --apply can copy notes' ' test "a note" = "$(git notes show HEAD)" ' +test_expect_success 'rebase drops notes of dropped commits' ' + git checkout n1 && + echo n3 >n3.t && + echo n4 >n4.t && + git add n3.t n4.t && + git commit -m n34 && + git rebase HEAD n3 && + test_commit_message HEAD -m n2 && + test_must_fail git notes list HEAD >actual && + test_must_be_empty actual +' + test_expect_success 'rebase commit with an ancient timestamp' ' git reset --hard && diff --git a/t/t5407-post-rewrite-hook.sh b/t/t5407-post-rewrite-hook.sh index ad7f8c6f00..51991956d1 100755 --- a/t/t5407-post-rewrite-hook.sh +++ b/t/t5407-post-rewrite-hook.sh @@ -310,4 +310,27 @@ test_expect_success 'git rebase -i (exec)' ' verify_hook_input ' +test_expect_success 'rebase with commits that become empty' ' + cat >todo <<-\EOF && + pick H + pick E + fixup I + fixup H + pick G + pick I + EOF + ( + set_replace_editor todo && + git rebase -i --empty=drop A A + ) && + echo rebase >expected.args && + cat >expected.data <<-EOF && + $(git rev-parse H) $(git rev-parse HEAD~2) + $(git rev-parse E) $(git rev-parse HEAD~1) + $(git rev-parse I) $(git rev-parse HEAD~1) + $(git rev-parse G) $(git rev-parse HEAD) + EOF + verify_hook_input +' + test_done From f5ca73edeb5528149440ba61e645478c15c71327 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 30 Jun 2026 12:04:01 -0700 Subject: [PATCH 12/15] fixup! sequencer: be more careful with external merge --- sequencer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sequencer.c b/sequencer.c index a85f9e8b77..7faf0093cb 100644 --- a/sequencer.c +++ b/sequencer.c @@ -2472,7 +2472,7 @@ static enum pick_result do_pick_commit(struct repository *r, opts->xopts.nr, opts->xopts.v, common, oid_to_hex(&head), remotes); /* - * If the there were conflicts, try_merge_command() returns 1, + * If there were conflicts, try_merge_command() returns 1, * any other no-zero return code means that either the merge * command could not be run, or it failed to merge. */ From e9e709aad5120cb140a6a38f91fdb8785bade028 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 30 Jun 2026 12:05:18 -0700 Subject: [PATCH 13/15] fixup! sequencer: never reschedule on failed commit --- sequencer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sequencer.c b/sequencer.c index 7faf0093cb..7bc885085f 100644 --- a/sequencer.c +++ b/sequencer.c @@ -2549,7 +2549,7 @@ fast_forward_edit: *check_todo = 1; } /* - * If "git commit" failed to run than res == -1 but we dont + * If "git commit" failed to run then res == -1, but we don't * want reschedule the last command because the picking the * commit was successful. */