From 60cb27ed6575daafe86938fa5fcf3778fc4876f2 Mon Sep 17 00:00:00 2001 From: Mirko Faina Date: Mon, 23 Mar 2026 17:57:28 +0100 Subject: [PATCH 1/8] pretty.c: better die message %(count) and %(total) Improve die messages for commands that do not support %(count) and %(total) Signed-off-by: Mirko Faina Signed-off-by: Junio C Hamano --- pretty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pretty.c b/pretty.c index 74673714c8..814803980b 100644 --- a/pretty.c +++ b/pretty.c @@ -1551,7 +1551,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ if (starts_with(placeholder, "(count)")) { if (!c->pretty_ctx->rev) - die(_("this format specifier can't be used with this command")); + die(_("%s is not supported by this command"), "%(count)"); strbuf_addf(sb, "%0*d", decimal_width(c->pretty_ctx->rev->total), c->pretty_ctx->rev->nr); return 7; @@ -1559,7 +1559,7 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ if (starts_with(placeholder, "(total)")) { if (!c->pretty_ctx->rev) - die(_("this format specifier can't be used with this command")); + die(_("%s is not supported by this command"), "%(total)"); strbuf_addf(sb, "%d", c->pretty_ctx->rev->total); return 7; } From 3482b4278793f3adb1fa811dd30c637563ca9cec Mon Sep 17 00:00:00 2001 From: Mirko Faina Date: Mon, 23 Mar 2026 17:57:29 +0100 Subject: [PATCH 2/8] format-patch: refactor generate_commit_list_cover Refactor for readability and remove unnecessary initialization. Signed-off-by: Mirko Faina Signed-off-by: Junio C Hamano --- builtin/log.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/builtin/log.c b/builtin/log.c index 716ebc2701..997bdd608e 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -1376,12 +1376,11 @@ static void generate_commit_list_cover(FILE *cover_file, const char *format, struct pretty_print_context ctx = {0}; struct rev_info rev = REV_INFO_INIT; - strbuf_init(&commit_line, 0); rev.total = n; ctx.rev = &rev; - for (int i = n - 1; i >= 0; i--) { - rev.nr = n - i; - repo_format_commit_message(the_repository, list[i], format, + for (int i = 1; i <= n; i++) { + rev.nr = i; + repo_format_commit_message(the_repository, list[n - i], format, &commit_line, &ctx); fprintf(cover_file, "%s\n", commit_line.buf); strbuf_reset(&commit_line); From 67ea2ad7d1b006194762cbfcc0b7801ffe652ca4 Mon Sep 17 00:00:00 2001 From: Mirko Faina Date: Mon, 23 Mar 2026 17:57:30 +0100 Subject: [PATCH 3/8] format-patch: rename --cover-letter-format option To align the name of the configuration variable and the name of the command line option, either one should change name. By changing the name of the option we get the added benefit of having --cover- expand to --cover-letter without ambiguity. If the user gives the --cover-letter-format option it would be reasonable to expect that the user wants to generate the cover letter despite not giving --cover-letter. Rename --cover-letter-format to --commit-list-format and make it imply --cover-letter unless --no-cover-letter is given. Signed-off-by: Mirko Faina Signed-off-by: Junio C Hamano --- Documentation/git-format-patch.adoc | 17 ++++++------ builtin/log.c | 4 ++- t/t4014-format-patch.sh | 41 +++++++++++++++-------------- t/t9902-completion.sh | 1 - 4 files changed, 32 insertions(+), 31 deletions(-) diff --git a/Documentation/git-format-patch.adoc b/Documentation/git-format-patch.adoc index 31fa492335..45ca72e670 100644 --- a/Documentation/git-format-patch.adoc +++ b/Documentation/git-format-patch.adoc @@ -24,7 +24,7 @@ SYNOPSIS [(--reroll-count|-v) ] [--to=] [--cc=] [--[no-]cover-letter] [--quiet] - [--cover-letter-format=] + [--commit-list-format=] [--[no-]encode-email-headers] [--no-notes | --notes[=]] [--interdiff=] @@ -323,16 +323,15 @@ feeding the result to `git send-email`. containing the branch description, shortlog and the overall diffstat. You can fill in a description in the file before sending it out. ---cover-letter-format=:: - Specify the format in which to generate the commit list of the - patch series. This option is available if the user wants to use - an alternative to the default `shortlog` format. The accepted - values for format-spec are "shortlog" or a format string - prefixed with `log:`. +--commit-list-format=:: + Specify the format in which to generate the commit list of the patch + series. The accepted values for format-spec are "shortlog" or a format + string prefixed with `log:`. e.g. `log: %s (%an)` - If defined, defaults to the `format.commitListFormat` configuration + If not given, defaults to the `format.commitListFormat` configuration variable. - This option is relevant only if a cover letter is generated. + This option implies the use of `--cover-letter` unless + `--no-cover-letter` is given. --encode-email-headers:: --no-encode-email-headers:: diff --git a/builtin/log.c b/builtin/log.c index 997bdd608e..a7f129d583 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -2014,7 +2014,7 @@ int cmd_format_patch(int argc, N_("print patches to standard out")), OPT_BOOL(0, "cover-letter", &cover_letter, N_("generate a cover letter")), - OPT_STRING(0, "cover-letter-format", &cover_letter_fmt, N_("format-spec"), + OPT_STRING(0, "commit-list-format", &cover_letter_fmt, N_("format-spec"), N_("format spec used for the commit list in the cover letter")), OPT_BOOL(0, "numbered-files", &just_numbers, N_("use simple number sequence for output file names")), @@ -2358,6 +2358,8 @@ int cmd_format_patch(int argc, cover_letter_fmt = cfg.fmt_cover_letter_commit_list; if (!cover_letter_fmt) cover_letter_fmt = "shortlog"; + } else if (cover_letter == -1) { + cover_letter = 1; } if (cover_letter == -1) { diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index 7c67bdf922..d2a775f78d 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -383,49 +383,50 @@ test_expect_success 'filename limit applies only to basename' ' test_expect_success 'cover letter with subject, author and count' ' rm -rf patches && test_when_finished "git reset --hard HEAD~1" && - test_when_finished "rm -rf patches result test_file" && + test_when_finished "rm -rf patches test_file" && touch test_file && git add test_file && git commit -m "This is a subject" && - git format-patch --cover-letter \ - --cover-letter-format="log:[%(count)/%(total)] %s (%an)" -o patches HEAD~1 && - grep "^\[1/1\] This is a subject (A U Thor)$" patches/0000-cover-letter.patch >result && - test_line_count = 1 result + git format-patch --commit-list-format="log:[%(count)/%(total)] %s (%an)" \ + -o patches HEAD~1 && + test_grep "^\[1/1\] This is a subject (A U Thor)$" patches/0000-cover-letter.patch ' -test_expected_success 'cover letter with author and count' ' +test_expect_success 'cover letter with author and count' ' test_when_finished "git reset --hard HEAD~1" && - test_when_finished "rm -rf patches result test_file" && + test_when_finished "rm -rf patches test_file" && touch test_file && git add test_file && git commit -m "This is a subject" && - git format-patch --cover-letter \ - --cover-letter-format="log:[%(count)/%(total)] %an" -o patches HEAD~1 && - grep "^\[1/1\] A U Thor$" patches/0000-cover-letter.patch >result && - test_line_count = 1 result + git format-patch --commit-list-format="log:[%(count)/%(total)] %an" \ + -o patches HEAD~1 && + test_grep "^\[1/1\] A U Thor$" patches/0000-cover-letter.patch ' test_expect_success 'cover letter shortlog' ' test_when_finished "git reset --hard HEAD~1" && - test_when_finished "rm -rf patches result test_file" && + test_when_finished "rm -rf expect patches result test_file" && + cat >expect <<-"EOF" && + A U Thor (1): + This is a subject + EOF touch test_file && git add test_file && git commit -m "This is a subject" && - git format-patch --cover-letter --cover-letter-format=shortlog \ - -o patches HEAD~1 && - sed -n -e "/^A U Thor/p;" patches/0000-cover-letter.patch >result && - test_line_count = 1 result + git format-patch --commit-list-format=shortlog -o patches HEAD~1 && + grep -E -A 1 "^A U Thor \([[:digit:]]+\):$" patches/0000-cover-letter.patch >result && + cat result && + test_cmp expect result ' -test_expect_success 'cover letter no format' ' +test_expect_success 'no cover letter but with format specified' ' test_when_finished "git reset --hard HEAD~1" && test_when_finished "rm -rf patches result test_file" && touch test_file && git add test_file && git commit -m "This is a subject" && - git format-patch --cover-letter -o patches HEAD~1 && - sed -n -e "/^A U Thor/p;" patches/0000-cover-letter.patch >result && - test_line_count = 1 result + git format-patch --no-cover-letter --commit-list-format="[%(count)] %s" -o patches HEAD~1 && + test_path_is_missing patches/0000-cover-letter.patch ' test_expect_success 'cover letter config with count, subject and author' ' diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh index 35e20b5351..2f9a597ec7 100755 --- a/t/t9902-completion.sh +++ b/t/t9902-completion.sh @@ -2775,7 +2775,6 @@ test_expect_success PERL 'send-email' ' test_completion "git send-email --cov" <<-\EOF && --cover-from-description=Z --cover-letter Z - --cover-letter-format=Z EOF test_completion "git send-email --val" <<-\EOF && --validate Z From 344f00ef9d0863f8b05e26253664fa6993ac5ac9 Mon Sep 17 00:00:00 2001 From: Mirko Faina Date: Mon, 23 Mar 2026 17:57:31 +0100 Subject: [PATCH 4/8] docs/pretty-formats: add %(count) and %(total) When --commit-list-format was introduced to format-patch, two new placeholders were added to the PRETTY FORMATS code without being documented. Do so now. Signed-off-by: Mirko Faina Signed-off-by: Junio C Hamano --- Documentation/pretty-formats.adoc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Documentation/pretty-formats.adoc b/Documentation/pretty-formats.adoc index 5405e57a60..2ae0eb11a9 100644 --- a/Documentation/pretty-formats.adoc +++ b/Documentation/pretty-formats.adoc @@ -253,6 +253,10 @@ The placeholders are: linkgit:git-rev-list[1]) +%d+:: ref names, like the --decorate option of linkgit:git-log[1] +%D+:: ref names without the " (", ")" wrapping. ++%(count)+:: the number of a patch within a patch series. Used only in + `--commit-list-format` in `format-patch` ++%(total)+:: the total number of patches in a patch series. Used only in + `--commit-list-format` in `format-patch` ++%(decorate++`[: