Subject: [PATCH 7/7] format-patch: --commit-list-format without prefix

From: Mirko Faina <[email-masked]>
Date: Sun, 15 Mar 2026 00:20:50 +0100

Having to prefix a custom format-string with "log:" when passed from the
cli interface can be annoying for many users. It would be great if it
could be dropped an it were still accepted.

Teach make_cover_letter() to accept custom format-strings if a
placeholder is detected.

Note that both here and in "git log --format" the check is done naively
by just checking for the presence of a '%'.

Signed-off-by: Mirko Faina <[email-masked]>
---
 Documentation/git-format-patch.adoc |  4 +++-
 builtin/log.c                       |  2 ++
 t/t4014-format-patch.sh             | 24 ++++++++++++++++++++++++
 3 files changed, 29 insertions(+), 1 deletion(-)

diff --git a/Documentation/git-format-patch.adoc b/Documentation/git-format-patch.adoc
index 55cc680685..c52dbcc170 100644
--- a/Documentation/git-format-patch.adoc
+++ b/Documentation/git-format-patch.adoc
@@ -326,8 +326,10 @@ feeding the result to `git send-email`.
 --commit-list-format=<format-spec>::
 	Specify the format in which to generate the commit list of the patch
 	series. The accepted values for format-spec are `shortlog`, `modern` or a
-	format string prefixed with `log:`.
+	format-string prefixed with `log:`.
 	e.g. `log: %s (%an)`
+	The user is allowed to drop the prefix if the format-string contains a
+	`%<placeholder>`.
 	If not given, defaults to the `format.commitListFormat` configuration
 	variable.
 	This option implies the use of `--cover-letter` unless
diff --git a/builtin/log.c b/builtin/log.c
index c6cf04350a..ad7b7215fe 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -1448,6 +1448,8 @@ static void make_cover_letter(struct rev_info *rev, int use_separate_file,
 	else if (!strcmp(format, "modern"))
 		generate_commit_list_cover(rev->diffopt.file, "[%(count)/%(total)] %s",
 					   list, nr);
+	else if (strchr(format, '%'))
+		generate_commit_list_cover(rev->diffopt.file, format, list, nr);
 	else
 		die(_("'%s' is not a valid format string"), format);
 
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 7571cc582b..7517094bd6 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -392,6 +392,30 @@ test_expect_success 'cover letter with subject, author and count' '
 	test_grep "^\[1/1\] This is a subject (A U Thor)$" patches/0000-cover-letter.patch
 '
 
+test_expect_success 'cover letter with custom format no prefix' '
+	rm -rf patches &&
+	test_when_finished "git reset --hard HEAD~1" &&
+	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 --commit-list-format="[%(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_expect_success 'cover letter fail when no prefix and no placeholder' '
+	rm -rf patches &&
+	test_when_finished "git reset --hard HEAD~1" &&
+	test_when_finished "rm -rf patches test_file err" &&
+	touch test_file &&
+	git add test_file &&
+	git commit -m "This is a subject" &&
+	test_must_fail git format-patch --commit-list-format="this should fail" \
+	-o patches HEAD~1 2>err &&
+	test_grep "is not a valid format string" err
+'
+
 test_expect_success 'cover letter modern format' '
 	test_when_finished "git reset --hard HEAD~1" &&
 	test_when_finished "rm -rf patches test_file" &&
-- 
2.53.0.959.g497ff81fa9