diff --git a/builtin/commit.c b/builtin/commit.c index cd455aa36..0a78e7649 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -596,32 +596,47 @@ static char *cut_ident_timestamp_part(char *string) /* * Inspect sb and determine the true "end" of the log message, in * order to find where to put a new Signed-off-by: line. Ignored are - * trailing "Conflict:" block. + * trailing comment lines and blank lines, and also the traditional + * "Conflicts:" block that is not commented out, so that we can use + * "git commit -s --amend" on an existing commit that forgot to remove + * it. * * Returns the number of bytes from the tail to ignore, to be fed as * the second parameter to append_signoff(). */ static int ignore_non_trailer(struct strbuf *sb) { - int ignore_footer = 0; - int i, eol, previous = 0; - const char *nl; + int boc = 0; + int bol = 0; + int in_old_conflicts_block = 0; - for (i = 0; i < sb->len; i++) { - nl = memchr(sb->buf + i, '\n', sb->len - i); - if (nl) - eol = nl - sb->buf; + while (bol < sb->len) { + char *next_line; + + if (!(next_line = memchr(sb->buf + bol, '\n', sb->len - bol))) + next_line = sb->buf + sb->len; else - eol = sb->len; - if (!prefixcmp(sb->buf + previous, "\nConflicts:\n")) { - ignore_footer = sb->len - previous; - break; + next_line++; + + if (sb->buf[bol] == comment_line_char || sb->buf[bol] == '\n') { + /* is this the first of the run of comments? */ + if (!boc) + boc = bol; + /* otherwise, it is just continuing */ + } else if (!prefixcmp(sb->buf + bol, "Conflicts:\n")) { + in_old_conflicts_block = 1; + if (!boc) + boc = bol; + } else if (in_old_conflicts_block && sb->buf[bol] == '\t') { + ; /* a pathname in the conflicts block */ + } else if (boc) { + /* the previous was not trailing comment */ + boc = 0; + in_old_conflicts_block = 0; } - while (i < eol) - i++; - previous = eol; + bol = next_line - sb->buf; } - return ignore_footer; + return boc ? sb->len - boc : 0; } static int prepare_to_commit(const char *index_file, const char *prefix, diff --git a/sequencer.c b/sequencer.c index 0f84bbeac..1d97da3ca 100644 --- a/sequencer.c +++ b/sequencer.c @@ -291,13 +291,12 @@ void append_conflicts_hint(struct strbuf *msgbuf) { int i; - strbuf_addstr(msgbuf, "\nConflicts:\n"); + strbuf_addch(msgbuf, '\n'); + strbuf_commented_addf(msgbuf, "Conflicts:\n"); for (i = 0; i < active_nr;) { const struct cache_entry *ce = active_cache[i++]; if (ce_stage(ce)) { - strbuf_addch(msgbuf, '\t'); - strbuf_addstr(msgbuf, ce->name); - strbuf_addch(msgbuf, '\n'); + strbuf_commented_addf(msgbuf, "\t%s\n", ce->name); while (i < active_nr && !strcmp(ce->name, active_cache[i]->name)) i++; diff --git a/t/t3507-cherry-pick-conflict.sh b/t/t3507-cherry-pick-conflict.sh index 223b98433..7c5ad0862 100755 --- a/t/t3507-cherry-pick-conflict.sh +++ b/t/t3507-cherry-pick-conflict.sh @@ -351,19 +351,45 @@ test_expect_success 'commit after failed cherry-pick does not add duplicated -s' test_expect_success 'commit after failed cherry-pick adds -s at the right place' ' pristine_detach initial && test_must_fail git cherry-pick picked && + git commit -a -s && - pwd && - cat < expected && -picked -Signed-off-by: C O Mitter + # Do S-o-b and Conflicts appear in the right order? + cat <<-\EOF >expect && + Signed-off-by: C O Mitter + # Conflicts: + EOF + grep -e "^# Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual && + test_cmp expect actual && + + cat <<-\EOF >expected && + picked -Conflicts: - foo -EOF + Signed-off-by: C O Mitter + EOF - git show -s --pretty=format:%B > actual && + git show -s --pretty=format:%B >actual && test_cmp expected actual ' +test_expect_success 'commit --amend -s places the sign-off at the right place' ' + pristine_detach initial && + test_must_fail git cherry-pick picked && + + # emulate old-style conflicts block + mv .git/MERGE_MSG .git/MERGE_MSG+ && + sed -e "/^# Conflicts:/,\$s/^# *//" <.git/MERGE_MSG+ >.git/MERGE_MSG && + + git commit -a && + git commit --amend -s && + + # Do S-o-b and Conflicts appear in the right order? + cat <<-\EOF >expect && + Signed-off-by: C O Mitter + Conflicts: + EOF + grep -e "^Conflicts:" -e '^Signed-off-by' <.git/COMMIT_EDITMSG >actual && + test_cmp expect actual +' + test_done