git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v7 3/5] format-patch: add ability to use alt cover format

From
Mirko Faina <mroik@delayed.space>
Date
Mar 6, 2026, 23:34 UTC
Message-ID
<316c9e76ee49d73aff75b63299c970e9f55f79b6.1772839973.git.mroik@delayed.space>
In-Reply-To
<cover.1772839973.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 format-patch the ability 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:[%(count)/%(total)] %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..95e5d9755f 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.5.gbe7197aef5
Previous: Mirko FainaNext: Phillip Wood
Message 70 of 113 in “format-patch: better commit list for cover letter”
  1. format-patch: better commit list for cover letterMirko Faina, Feb 20, 2026
  2. format-patch: better commit list for cover letterMirko Faina, Feb 20, 2026
  3. Mirko FainaFeb 21, 2026
  4. Junio C HamanoFeb 21, 2026
  5. Mirko FainaFeb 21, 2026
  6. Junio C HamanoFeb 21, 2026
  7. Junio C HamanoFeb 21, 2026
  8. Mirko FainaFeb 21, 2026
  9. Junio C HamanoFeb 21, 2026
  10. Mirko FainaFeb 21, 2026
  11. 0/3 format-patch: add cover-letter-format optionMirko Faina, Feb 24, 2026
  12. Mirko FainaFeb 24, 2026
  13. 0/2 format-patch: add cover-letter-format optionMirko Faina, Feb 24, 2026
  14. 1/2 format-patch: add ability to use alt cover formatMirko Faina, Feb 24, 2026
  15. Junio C HamanoFeb 24, 2026
  16. Mirko FainaFeb 24, 2026
  17. Junio C HamanoFeb 25, 2026
  18. Jeff KingFeb 25, 2026
  19. Junio C HamanoFeb 24, 2026
  20. Jeff KingFeb 25, 2026
  21. Mirko FainaFeb 25, 2026
  22. 2/2 format-patch: add commitListFormat configMirko Faina, Feb 24, 2026
  23. Junio C HamanoFeb 24, 2026
  24. Mirko FainaFeb 25, 2026
  25. Junio C HamanoFeb 25, 2026
  26. Mirko FainaFeb 26, 2026
  27. Junio C HamanoFeb 26, 2026
  28. Junio C HamanoFeb 24, 2026
  29. Junio C HamanoFeb 24, 2026
  30. Mirko FainaFeb 25, 2026
  31. Junio C HamanoFeb 25, 2026
  32. 0/4 format-patch: add cover-letter-format optionMirko Faina, Feb 27, 2026
  33. 1/4 pretty.c: add %(count) and %(total) placeholdersMirko Faina, Feb 27, 2026
  34. 2/4 format-patch: move cover letter summary generationMirko Faina, Feb 27, 2026
  35. 4/4 format-patch: add commitListFormat configMirko Faina, Feb 27, 2026
  36. 3/4 format-patch: add ability to use alt cover formatMirko Faina, Feb 27, 2026
  37. Junio C HamanoFeb 27, 2026
  38. Mirko FainaFeb 27, 2026
  39. 0/4 format-patch: add cover-letter-format optionMirko Faina, Feb 27, 2026
  40. 1/4 pretty.c: add %(count) and %(total) placeholdersMirko Faina, Feb 27, 2026
  41. 3/4 format-patch: add ability to use alt cover formatMirko Faina, Feb 27, 2026
  42. 2/4 format-patch: move cover letter summary generationMirko Faina, Feb 27, 2026
  43. 4/4 format-patch: add commitListFormat configMirko Faina, Feb 27, 2026
  44. 5/4 docs: add usage for the cover-letter fmt featureMirko Faina, Feb 27, 2026
  45. Junio C HamanoFeb 27, 2026
  46. Mirko FainaFeb 27, 2026
  47. Junio C HamanoFeb 27, 2026
  48. 0/5 format-patch: add cover-letter-format optionMirko Faina, Feb 27, 2026
  49. 1/5 pretty.c: add %(count) and %(total) placeholdersMirko Faina, Feb 27, 2026
  50. 2/5 format-patch: move cover letter summary generationMirko Faina, Feb 27, 2026
  51. 3/5 format-patch: add ability to use alt cover formatMirko Faina, Feb 27, 2026
  52. 4/5 format-patch: add commitListFormat configMirko Faina, Feb 27, 2026
  53. 5/5 docs: add usage for the cover-letter fmt featureMirko Faina, Feb 27, 2026
  54. Junio C HamanoMar 6, 2026
  55. Mirko FainaMar 6, 2026
  56. 0/5 format-patch: add cover-letter-format optionMirko Faina, Mar 6, 2026
  57. 1/5 pretty.c: add %(count) and %(total) placeholdersMirko Faina, Mar 6, 2026
  58. 2/5 format-patch: move cover letter summary generationMirko Faina, Mar 6, 2026
  59. 3/5 format-patch: add ability to use alt cover formatMirko Faina, Mar 6, 2026
  60. Junio C HamanoMar 10, 2026
  61. Mirko FainaMar 10, 2026
  62. 4/5 format-patch: add commitListFormat configMirko Faina, Mar 6, 2026
  63. 5/5 docs: add usage for the cover-letter fmt featureMirko Faina, Mar 6, 2026
  64. Junio C HamanoMar 6, 2026
  65. 0/5 format-patch: add cover-letter-format optionMirko Faina, Mar 6, 2026
  66. 1/5 pretty.c: add %(count) and %(total) placeholdersMirko Faina, Mar 6, 2026
  67. Phillip WoodMar 10, 2026
  68. Mirko FainaMar 10, 2026
  69. 2/5 format-patch: move cover letter summary generationMirko Faina, Mar 6, 2026
  70. 3/5 format-patch: add ability to use alt cover formatMirko Faina, Mar 6, 2026
  71. Phillip WoodMar 10, 2026
  72. MroikMar 10, 2026
  73. 4/5 format-patch: add commitListFormat configMirko Faina, Mar 6, 2026
  74. Phillip WoodMar 10, 2026
  75. Junio C HamanoMar 10, 2026
  76. Mirko FainaMar 10, 2026
  77. Phillip WoodMar 11, 2026
  78. Junio C HamanoMar 11, 2026
  79. Phillip WoodMar 11, 2026
  80. Junio C HamanoMar 11, 2026
  81. Mirko FainaMar 10, 2026
  82. 5/5 docs: add usage for the cover-letter fmt featureMirko Faina, Mar 6, 2026
  83. Bert WesargMar 10, 2026
  84. Phillip WoodMar 10, 2026
  85. 0/4 format-patch: add cover-letter-format optionMirko Faina, Mar 12, 2026
  86. 1/4 format-patch: move cover letter summary generationMirko Faina, Mar 12, 2026
  87. Junio C HamanoMar 12, 2026
  88. 2/4 format-patch: add ability to use alt cover formatMirko Faina, Mar 12, 2026
  89. Junio C HamanoMar 12, 2026
  90. Mirko FainaMar 12, 2026
  91. Junio C HamanoMar 12, 2026
  92. Junio C HamanoMar 12, 2026
  93. Phillip WoodMar 13, 2026
  94. Junio C HamanoMar 13, 2026
  95. Mirko FainaMar 13, 2026
  96. Junio C HamanoMar 13, 2026
  97. 3/4 format-patch: add "chronological" format for coverMirko Faina, Mar 12, 2026
  98. Junio C HamanoMar 12, 2026
  99. 4/4 format-patch: add commitListFormat configMirko Faina, Mar 12, 2026
  100. Junio C HamanoMar 12, 2026
  101. Junio C HamanoMar 12, 2026
  102. Mirko FainaMar 12, 2026
  103. Junio C HamanoMar 12, 2026
  104. 1/3 pretty.c: fix null pointer dereferenceMirko Faina, Feb 24, 2026
  105. Junio C HamanoFeb 24, 2026
  106. Mirko FainaFeb 24, 2026
  107. Mirko FainaFeb 24, 2026
  108. Jeff KingFeb 24, 2026
  109. 2/3 format-patch: add ability to use alt cover formatMirko Faina, Feb 24, 2026
  110. Jeff KingFeb 24, 2026
  111. Mirko FainaFeb 24, 2026
  112. Jeff KingFeb 24, 2026
  113. 3/3 format-patch: add commitListFormat configMirko Faina, Feb 24, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.