[PATCH v7 4/5] sequencer: extract helpers for the squash message markers
From: Harald Nordgren via GitGitGadget <hidden>
Date: 2026-07-06 08:51:07
Subsystem:
the rest · Maintainer:
Linus Torvalds
From: Harald Nordgren <redacted> When "git rebase -i" squashes commits it builds an editor template with a "This is a combination of N commits." banner, a "This is the 1st/Nth commit message:" header above each kept message (or a "will be skipped" header for a dropped one), and a commented-out subject for any fixup!, squash! or amend! commit. The banner, the headers and the subject-commenting all live in static helpers in sequencer.c wired to the rebase state, so no other command can present a squash the same way. Pull the three pieces out into add_squash_combination_header(), add_squash_message_header() (which takes a flag for the "will be skipped" variant) and squash_subject_comment_len(), and use them from update_squash_messages() and append_squash_message(). A later change reuses them to give "git history squash --reedit-message" the same template. No change in behavior. Signed-off-by: Harald Nordgren <redacted> --- sequencer.c | 64 ++++++++++++++++++++++++++++++++--------------------- sequencer.h | 23 +++++++++++++++++++ 2 files changed, 62 insertions(+), 25 deletions(-)
diff --git a/sequencer.c b/sequencer.c
index 57855b0066..f4893e8f40 100644
--- a/sequencer.c
+++ b/sequencer.c@@ -1892,6 +1892,32 @@ static const char skip_first_commit_msg_str[] = N_("The 1st commit message will static const char skip_nth_commit_msg_fmt[] = N_("The commit message #%d will be skipped:"); static const char combined_commit_msg_fmt[] = N_("This is a combination of %d commits."); +void add_squash_combination_header(struct strbuf *buf, int n) +{ + strbuf_addf(buf, "%s ", comment_line_str); + strbuf_addf(buf, _(combined_commit_msg_fmt), n); +} + +void add_squash_message_header(struct strbuf *buf, int n, int skip) +{ + strbuf_addf(buf, "%s ", comment_line_str); + if (n == 1) + strbuf_addstr(buf, skip ? _(skip_first_commit_msg_str) : + _(first_commit_msg_str)); + else + strbuf_addf(buf, skip ? _(skip_nth_commit_msg_fmt) : + _(nth_commit_msg_fmt), n); +} + +size_t squash_subject_comment_len(const char *body, int squashing) +{ + if (starts_with(body, "amend!") || + (squashing && (starts_with(body, "squash!") || + starts_with(body, "fixup!")))) + return commit_subject_length(body); + return 0; +} + static int is_fixup_flag(enum todo_command command, unsigned flag) { return command == TODO_FIXUP && ((flag & TODO_REPLACE_FIXUP_MSG) ||
@@ -2005,20 +2031,13 @@ static int append_squash_message(struct strbuf *buf, const char *body, { struct replay_ctx *ctx = opts->ctx; const char *fixup_msg; - size_t commented_len = 0, fixup_off; - /* - * amend is non-interactive and not normally used with fixup! - * or squash! commits, so only comment out those subjects when - * squashing commit messages. - */ - if (starts_with(body, "amend!") || - ((command == TODO_SQUASH || seen_squash(ctx)) && - (starts_with(body, "squash!") || starts_with(body, "fixup!")))) - commented_len = commit_subject_length(body); + size_t commented_len, fixup_off; + + commented_len = squash_subject_comment_len(body, + command == TODO_SQUASH || seen_squash(ctx)); - strbuf_addf(buf, "\n%s ", comment_line_str); - strbuf_addf(buf, _(nth_commit_msg_fmt), - ++ctx->current_fixup_count + 1); + strbuf_addch(buf, '\n'); + add_squash_message_header(buf, ++ctx->current_fixup_count + 1, 0); strbuf_addstr(buf, "\n\n"); strbuf_add_commented_lines(buf, body, commented_len, comment_line_str); /* buf->buf may be reallocated so store an offset into the buffer */
@@ -2083,9 +2102,8 @@ static int update_squash_messages(struct repository *r, eol = !starts_with(buf.buf, comment_line_str) ? buf.buf : strchrnul(buf.buf, '\n'); - strbuf_addf(&header, "%s ", comment_line_str); - strbuf_addf(&header, _(combined_commit_msg_fmt), - ctx->current_fixup_count + 2); + add_squash_combination_header(&header, + ctx->current_fixup_count + 2); strbuf_splice(&buf, 0, eol - buf.buf, header.buf, header.len); strbuf_release(&header); if (is_fixup_flag(command, flag) && !seen_squash(ctx))
@@ -2109,12 +2127,9 @@ static int update_squash_messages(struct repository *r, repo_unuse_commit_buffer(r, head_commit, head_message); return error(_("cannot write '%s'"), rebase_path_fixup_msg()); } - strbuf_addf(&buf, "%s ", comment_line_str); - strbuf_addf(&buf, _(combined_commit_msg_fmt), 2); - strbuf_addf(&buf, "\n%s ", comment_line_str); - strbuf_addstr(&buf, is_fixup_flag(command, flag) ? - _(skip_first_commit_msg_str) : - _(first_commit_msg_str)); + add_squash_combination_header(&buf, 2); + strbuf_addch(&buf, '\n'); + add_squash_message_header(&buf, 1, is_fixup_flag(command, flag)); strbuf_addstr(&buf, "\n\n"); if (is_fixup_flag(command, flag)) strbuf_add_commented_lines(&buf, body, strlen(body),
@@ -2133,9 +2148,8 @@ static int update_squash_messages(struct repository *r, if (command == TODO_SQUASH || is_fixup_flag(command, flag)) { res = append_squash_message(&buf, body, command, opts, flag); } else if (command == TODO_FIXUP) { - strbuf_addf(&buf, "\n%s ", comment_line_str); - strbuf_addf(&buf, _(skip_nth_commit_msg_fmt), - ++ctx->current_fixup_count + 1); + strbuf_addch(&buf, '\n'); + add_squash_message_header(&buf, ++ctx->current_fixup_count + 1, 1); strbuf_addstr(&buf, "\n\n"); strbuf_add_commented_lines(&buf, body, strlen(body), comment_line_str);
diff --git a/sequencer.h b/sequencer.h
index 3164bd437d..feed0e9de3 100644
--- a/sequencer.h
+++ b/sequencer.h@@ -208,6 +208,29 @@ int todo_list_rearrange_squash(struct todo_list *todo_list); */ void append_signoff(struct strbuf *msgbuf, size_t ignore_footer, unsigned flag); +/* + * Append the "This is a combination of N commits." banner that "git rebase + * -i" writes at the top of a squashed commit's message, commented out with + * the comment character. + */ +void add_squash_combination_header(struct strbuf *buf, int n); + +/* + * Append the header (1-based N) that "git rebase -i" writes above each message + * when squashing, commented out with the comment character. With SKIP it reads + * "The ... commit message will be skipped" for a message that is dropped (a + * fixup), otherwise "This is the ... commit message". + */ +void add_squash_message_header(struct strbuf *buf, int n, int skip); + +/* + * Return the length of the leading subject of BODY when it should be commented + * out in a squash message, or 0 otherwise. An "amend!" subject always + * qualifies; "squash!" and "fixup!" subjects only when SQUASHING, since a + * plain fixup chain keeps them. + */ +size_t squash_subject_comment_len(const char *body, int squashing); + void append_conflicts_hint(struct index_state *istate, struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode); enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg,
--
gitgitgadget