public inbox for git@vger.kernel.org 
 help / color / mirror / Atom feed
From: Mirko Faina <mroik@delayed•space>
To: git@vger•kernel.org
Cc: Mirko Faina <mroik@delayed•space>,
	Junio C Hamano <gitster@pobox•com>, Jeff King <peff@peff•net>
Subject: [PATCH v3 3/4] format-patch: add ability to use alt cover format
Date: Fri, 27 Feb 2026 02:52:38 +0100	[thread overview]
Message-ID: <190817fe6ac5199c6df95558a7dee4be3d2fffdd.1772156996.git.mroik@delayed.space> (raw)
In-Reply-To: <cover.1772156996.git.mroik@delayed.space>

Often when sending patch series there's a need to clarify to the
reviewer what's the purpose of said series, since it might be difficult
to understand it from reading the commits messages one by one.

"git format-patch" provides the useful "--cover-letter" flag to declare
if we want it to generate a template for us to use. By default it will
generate a "git shortlog" of the changes, which developers find less
useful than they'd like, mainly because the shortlog groups commits by
author, and gives no obvious chronological order.

Give the ability to format-patch to specify an alternative format spec
through the "--cover-letter-format" option. This option either takes
"shortlog", which is the current format, or a format spec prefixed with
"log:".

Example:
    git format-patch --cover-letter \
        --cover-letter-format="log:%s (%an)" HEAD~3

    [1/3] this is a commit summary (Mirko Faina)
    [2/3] this is another commit summary (Mirko Faina)
    ...

Signed-off-by: Mirko Faina <mroik@delayed•space>
---
 builtin/log.c           | 40 +++++++++++++++++++++++++++++++---
 t/t4014-format-patch.sh | 48 +++++++++++++++++++++++++++++++++++++++++
 t/t9902-completion.sh   |  1 +
 3 files changed, 86 insertions(+), 3 deletions(-)

diff --git a/builtin/log.c b/builtin/log.c
index 0d12272031..46c8e33773 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -1343,13 +1343,36 @@ static void generate_shortlog_cover_letter(struct shortlog *log,
 	shortlog_output(log);
 }
 
+static void generate_commit_list_cover(FILE *cover_file,const char *format,
+				       struct commit **list, int n)
+{
+	struct strbuf commit_line = STRBUF_INIT;
+	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,
+				&commit_line, &ctx);
+		fprintf(cover_file, "%s\n", commit_line.buf);
+		strbuf_reset(&commit_line);
+	}
+	fprintf(cover_file, "\n");
+
+	strbuf_release(&commit_line);
+}
+
 static void make_cover_letter(struct rev_info *rev, int use_separate_file,
 			      struct commit *origin,
 			      int nr, struct commit **list,
 			      const char *description_file,
 			      const char *branch_name,
 			      int quiet,
-			      const struct format_config *cfg)
+			      const struct format_config *cfg,
+			      const char *format)
 {
 	const char *committer;
 	struct shortlog log;
@@ -1396,7 +1419,12 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
 	free(pp.after_subject);
 	strbuf_release(&sb);
 
-	generate_shortlog_cover_letter(&log, rev, list, nr);
+	if (skip_prefix(format, "log:", &format))
+		generate_commit_list_cover(rev->diffopt.file, format, list, nr);
+	else if (!strcmp(format, "shortlog"))
+		generate_shortlog_cover_letter(&log, rev, list, nr);
+	else
+		die(_("'%s' is not a valid format string"), format);
 
 	/* We can only do diffstat with a unique reference point */
 	if (origin)
@@ -1914,6 +1942,7 @@ int cmd_format_patch(int argc,
 	int just_numbers = 0;
 	int ignore_if_in_upstream = 0;
 	int cover_letter = -1;
+	const char *cover_letter_fmt = NULL;
 	int boundary_count = 0;
 	int no_binary_diff = 0;
 	int zero_commit = 0;
@@ -1960,6 +1989,8 @@ 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"),
+			    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")),
 		OPT_STRING(0, "suffix", &fmt_patch_suffix, N_("sfx"),
@@ -2297,6 +2328,7 @@ int cmd_format_patch(int argc,
 		/* nothing to do */
 		goto done;
 	total = list.nr;
+
 	if (cover_letter == -1) {
 		if (cfg.config_cover_letter == COVER_AUTO)
 			cover_letter = (total > 1);
@@ -2383,12 +2415,14 @@ int cmd_format_patch(int argc,
 	}
 	rev.numbered_files = just_numbers;
 	rev.patch_suffix = fmt_patch_suffix;
+
 	if (cover_letter) {
 		if (cfg.thread)
 			gen_message_id(&rev, "cover");
 		make_cover_letter(&rev, !!output_directory,
 				  origin, list.nr, list.items,
-				  description_file, branch_name, quiet, &cfg);
+				  description_file, branch_name, quiet, &cfg,
+				  cover_letter_fmt);
 		print_bases(&bases, rev.diffopt.file);
 		print_signature(signature, rev.diffopt.file);
 		total++;
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 21d6d0cd9e..458da80721 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -380,6 +380,54 @@ test_expect_success 'filename limit applies only to basename' '
 	done
 '
 
+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" &&
+	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
+'
+
+test_expected_success 'cover letter with author and count' '
+	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 \
+	--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
+'
+
+test_expect_success 'cover letter shortlog' '
+	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 --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
+'
+
+test_expect_success 'cover letter no format' '
+	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
+'
+
 test_expect_success 'reroll count' '
 	rm -fr patches &&
 	git format-patch -o patches --cover-letter --reroll-count 4 main..side >list &&
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 964e1f1569..4f760a7468 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -2774,6 +2774,7 @@ 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
-- 
2.53.0.4.g55f3102ead


  parent reply	other threads:[~2026-02-27  1:53 UTC|newest]

Thread overview: 113+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-20 23:06 [RFC PATCH] format-patch: better commit list for cover letter Mirko Faina
2026-02-20 23:55 ` [RFC PATCH v2] " Mirko Faina
2026-02-21  0:51   ` Mirko Faina
2026-02-21  4:54 ` [RFC PATCH] " Junio C Hamano
2026-02-21  5:18   ` Mirko Faina
2026-02-21  5:55     ` Junio C Hamano
2026-02-21  6:02       ` Junio C Hamano
2026-02-21 15:59         ` Mirko Faina
2026-02-21 17:33           ` Junio C Hamano
2026-02-21 19:16             ` Mirko Faina
2026-02-24  4:03 ` [PATCH 0/3] format-patch: add cover-letter-format option Mirko Faina
2026-02-24  4:06   ` Mirko Faina
2026-02-24  9:29   ` [PATCH v2 0/2] " Mirko Faina
2026-02-24  9:29     ` [PATCH v2 1/2] format-patch: add ability to use alt cover format Mirko Faina
2026-02-24 17:40       ` Junio C Hamano
2026-02-24 23:54         ` Mirko Faina
2026-02-25  0:29           ` Junio C Hamano
2026-02-25 13:47           ` Jeff King
2026-02-24 20:25       ` Junio C Hamano
2026-02-25 13:56       ` Jeff King
2026-02-25 22:55         ` Mirko Faina
2026-02-24  9:29     ` [PATCH v2 2/2] format-patch: add commitListFormat config Mirko Faina
2026-02-24 18:07       ` Junio C Hamano
2026-02-25  0:14         ` Mirko Faina
2026-02-25 17:25           ` Junio C Hamano
2026-02-26 21:40           ` Mirko Faina
2026-02-26 22:19             ` Junio C Hamano
2026-02-24 20:38     ` [PATCH v2 0/2] format-patch: add cover-letter-format option Junio C Hamano
2026-02-24 21:39       ` Junio C Hamano
2026-02-25  0:19         ` Mirko Faina
2026-02-25  2:46           ` Junio C Hamano
2026-02-27  1:52     ` [PATCH v3 0/4] " Mirko Faina
2026-02-27  1:52       ` [PATCH v3 1/4] pretty.c: add %(count) and %(total) placeholders Mirko Faina
2026-02-27  1:52       ` [PATCH v3 2/4] format-patch: move cover letter summary generation Mirko Faina
2026-02-27  1:52       ` Mirko Faina [this message]
2026-02-27  4:23         ` [PATCH v3 3/4] format-patch: add ability to use alt cover format Junio C Hamano
2026-02-27 12:41           ` Mirko Faina
2026-02-27  1:52       ` [PATCH v3 4/4] format-patch: add commitListFormat config Mirko Faina
2026-02-27 13:18       ` [PATCH v4 0/4] format-patch: add cover-letter-format option Mirko Faina
2026-02-27 13:18         ` [PATCH v4 1/4] pretty.c: add %(count) and %(total) placeholders Mirko Faina
2026-02-27 13:18         ` [PATCH v4 2/4] format-patch: move cover letter summary generation Mirko Faina
2026-02-27 13:18         ` [PATCH v4 3/4] format-patch: add ability to use alt cover format Mirko Faina
2026-02-27 13:18         ` [PATCH v4 4/4] format-patch: add commitListFormat config Mirko Faina
2026-02-27 16:42           ` [PATCH v4 5/4] docs: add usage for the cover-letter fmt feature Mirko Faina
2026-02-27 17:51           ` [PATCH v4 4/4] format-patch: add commitListFormat config Junio C Hamano
2026-02-27 21:51             ` Mirko Faina
2026-02-27 22:21               ` Junio C Hamano
2026-02-27 22:48         ` [PATCH v5 0/5] format-patch: add cover-letter-format option Mirko Faina
2026-02-27 22:48           ` [PATCH v5 1/5] pretty.c: add %(count) and %(total) placeholders Mirko Faina
2026-02-27 22:48           ` [PATCH v5 2/5] format-patch: move cover letter summary generation Mirko Faina
2026-02-27 22:48           ` [PATCH v5 3/5] format-patch: add ability to use alt cover format Mirko Faina
2026-02-27 22:48           ` [PATCH v5 4/5] format-patch: add commitListFormat config Mirko Faina
2026-02-27 22:48           ` [PATCH v5 5/5] docs: add usage for the cover-letter fmt feature Mirko Faina
2026-03-06 22:33           ` [PATCH v5 0/5] format-patch: add cover-letter-format option Junio C Hamano
2026-03-06 22:49             ` Mirko Faina
2026-03-06 22:58           ` [PATCH v6 " Mirko Faina
2026-03-06 22:58             ` [PATCH v6 1/5] pretty.c: add %(count) and %(total) placeholders Mirko Faina
2026-03-06 22:58             ` [PATCH v6 2/5] format-patch: move cover letter summary generation Mirko Faina
2026-03-06 22:58             ` [PATCH v6 3/5] format-patch: add ability to use alt cover format Mirko Faina
2026-03-10 22:14               ` Junio C Hamano
2026-03-10 22:32                 ` Mirko Faina
2026-03-06 22:58             ` [PATCH v6 4/5] format-patch: add commitListFormat config Mirko Faina
2026-03-06 22:58             ` [PATCH v6 5/5] docs: add usage for the cover-letter fmt feature Mirko Faina
2026-03-06 23:18               ` Junio C Hamano
2026-03-06 23:34             ` [PATCH v7 0/5] format-patch: add cover-letter-format option Mirko Faina
2026-03-06 23:34               ` [PATCH v7 1/5] pretty.c: add %(count) and %(total) placeholders Mirko Faina
2026-03-10 14:32                 ` Phillip Wood
2026-03-10 20:55                   ` Mirko Faina
2026-03-06 23:34               ` [PATCH v7 2/5] format-patch: move cover letter summary generation Mirko Faina
2026-03-06 23:34               ` [PATCH v7 3/5] format-patch: add ability to use alt cover format Mirko Faina
2026-03-10 14:33                 ` Phillip Wood
2026-03-10 21:05                   ` Mroik
2026-03-06 23:34               ` [PATCH v7 4/5] format-patch: add commitListFormat config Mirko Faina
2026-03-10 14:34                 ` Phillip Wood
2026-03-10 16:45                   ` Junio C Hamano
2026-03-10 21:23                     ` Mirko Faina
2026-03-11 10:38                       ` Phillip Wood
2026-03-11 17:13                         ` Junio C Hamano
2026-03-11 10:32                     ` Phillip Wood
2026-03-11 17:18                       ` Junio C Hamano
2026-03-10 21:19                   ` Mirko Faina
2026-03-06 23:34               ` [PATCH v7 5/5] docs: add usage for the cover-letter fmt feature Mirko Faina
2026-03-10  9:51                 ` Bert Wesarg
2026-03-10 14:34                 ` Phillip Wood
2026-03-12 16:20               ` [PATCH v8 0/4] format-patch: add cover-letter-format option Mirko Faina
2026-03-12 16:20                 ` [PATCH v8 1/4] format-patch: move cover letter summary generation Mirko Faina
2026-03-12 16:28                   ` Junio C Hamano
2026-03-12 16:20                 ` [PATCH v8 2/4] format-patch: add ability to use alt cover format Mirko Faina
2026-03-12 16:52                   ` Junio C Hamano
2026-03-12 17:18                     ` Mirko Faina
2026-03-12 17:25                       ` Junio C Hamano
2026-03-12 17:27                         ` Junio C Hamano
2026-03-13 10:38                         ` Phillip Wood
2026-03-13 17:20                           ` Junio C Hamano
2026-03-13 19:17                             ` Mirko Faina
2026-03-13 20:22                               ` Junio C Hamano
2026-03-12 16:20                 ` [PATCH v8 3/4] format-patch: add "chronological" format for cover Mirko Faina
2026-03-12 16:55                   ` Junio C Hamano
2026-03-12 16:20                 ` [PATCH v8 4/4] format-patch: add commitListFormat config Mirko Faina
2026-03-12 17:00                   ` Junio C Hamano
2026-03-12 17:20                 ` [PATCH v8 0/4] format-patch: add cover-letter-format option Junio C Hamano
2026-03-12 17:45                   ` Mirko Faina
2026-03-12 18:12                     ` Junio C Hamano
2026-02-24  4:03 ` [PATCH 1/3] pretty.c: fix null pointer dereference Mirko Faina
2026-02-24  6:25   ` Junio C Hamano
2026-02-24  7:08     ` Mirko Faina
2026-02-24  7:43       ` Mirko Faina
2026-02-24  8:41       ` Jeff King
2026-02-24  4:03 ` [PATCH 2/3] format-patch: add ability to use alt cover format Mirko Faina
2026-02-24  9:02   ` Jeff King
2026-02-24  9:09     ` Mirko Faina
2026-02-24  9:18       ` Jeff King
2026-02-24  4:03 ` [PATCH 3/3] format-patch: add commitListFormat config Mirko Faina

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=190817fe6ac5199c6df95558a7dee4be3d2fffdd.1772156996.git.mroik@delayed.space \
    --to=mroik@delayed$(echo .)space \
    --cc=git@vger$(echo .)kernel.org \
    --cc=gitster@pobox$(echo .)com \
    --cc=peff@peff$(echo .)net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox