@leroysheep / CrazyWebTemps / commits / f36860873c

rebase: remember fixup -c after skipping fixup/squash

When the final command in a chain of "fixup" and "squash" commands is skipped, we should prompt the user to edit the commit message if the chain contains a "fixup -c" command that was not skipped. Unfortunately, commit_staged_changes() only looks for completed "squash" commands and so does not prompt the user to edit the message. Fix this by recording whether a fixup command has the "-c" flag set and then checking whether we have seen either a "fixup -c" or a "squash" command. Add regression tests for skipping a command in the middle of the chain (which currently works but has no test coverage), and for skipping the final command (which is fixed by this patch). Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Phillip Wood committed Jul 17, 2026 at 17:06 UTC f36860873c3a0fd2737c05d630b89a22b27bc695
2 files changed +63 -4
sequencer.c
+16 -4
index af3d2c7261..25ef076216 100644 --- a/sequencer.c +++ b/sequencer.c @@ -1926,6 +1926,13 @@ static int seen_squash(struct replay_ctx *ctx) strstr(ctx->current_fixups.buf, "\nsquash"); } +/* Does the current fixup chain contain a "fixup -c" command? */ +static int seen_fixup_edit_msg(struct replay_ctx *ctx) +{ + return starts_with(ctx->current_fixups.buf, "fixup -c") || + strstr(ctx->current_fixups.buf, "\nfixup -c"); +} + static void update_comment_bufs(struct strbuf *buf1, struct strbuf *buf2, int n) { strbuf_setlen(buf1, strlen(comment_line_str) + 1); @@ -2148,9 +2155,14 @@ static int update_squash_messages(struct repository *r, strbuf_release(&buf); if (!res) { - strbuf_addf(&ctx->current_fixups, "%s%s %s", + const char *fixup_flag = ""; + + if (is_fixup_flag(command, flag) && (flag & TODO_EDIT_FIXUP_MSG)) + fixup_flag = " -c"; + + strbuf_addf(&ctx->current_fixups, "%s%s%s %s", ctx->current_fixups.len ? "\n" : "", - command_to_string(command), + command_to_string(command), fixup_flag, oid_to_hex(&commit->object.oid)); res = write_message(ctx->current_fixups.buf, ctx->current_fixups.len, @@ -5391,8 +5403,8 @@ static int commit_staged_changes(struct repository *r, * message, no need to bother the user with * opening the commit message in the editor. */ - if (!starts_with(p, "squash ") && - !strstr(p, "\nsquash ")) + if (!seen_squash(ctx) && + !seen_fixup_edit_msg(ctx)) flags = (flags & ~EDIT_MSG) | CLEANUP_MSG; } else if (is_fixup(peek_command(todo_list, 0))) { /*
t/t3437-rebase-fixup-options.sh
+47
index 5d306a4769..a4b2a63165 100755 --- a/t/t3437-rebase-fixup-options.sh +++ b/t/t3437-rebase-fixup-options.sh @@ -186,6 +186,53 @@ test_expect_success 'multiple fixup -c opens editor once' ' test_commit_message HEAD expected-message ' +test_expect_success 'fixup -c is remembered after skipping final fixup' ' + test_when_finished "test_might_fail git rebase --abort" && + cat >todo <<-\EOF && + pick B + fixup -c A1 + fixup A3 + EOF + ( + set_fake_editor && + set_replace_editor todo && + test_must_fail git rebase -i A A && + git show && cat .git/rebase-merge/message-squash && + FAKE_COMMIT_AMEND=edited git rebase --skip + ) && + test_commit_message HEAD <<-\EOF + new subject + + new + body + + edited + EOF +' +test_expect_success 'fixup -c is remembered after skipping later fixup' ' + test_when_finished "test_might_fail git rebase --abort" && + cat >todo <<-\EOF && + pick B + fixup -c A1 + fixup A3 + fixup A2 + EOF + ( + set_fake_editor && + set_replace_editor todo && + test_must_fail git rebase -i A A && + FAKE_COMMIT_AMEND=edited git rebase --skip + ) && + test_commit_message HEAD <<-\EOF + new subject + + new + body + + edited + EOF +' + test_expect_success 'sequence squash, fixup & fixup -c gives combined message' ' test_when_finished "test_might_fail git rebase --abort" && git checkout --detach A3 &&