[PATCH v2 3/6] format-patch: make cover letter subject configurable

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



We used to populate the subject of the cover letter generated by
git-format-patch with "*** SUBJECT HERE ***". However, if a user submits
multiple patchsets, they may want to keep a consistent subject between
rerolls.

If git-format-patch is run on a branch that has
`format.<branch-name>.coverSubject` defined, make the cover letter's
subject be that value instead of the generic "*** SUBJECT HERE ***".

In addition, add the `--cover-subject` option to override this setting.

Finally, make `git branch -d` also remove any `format.<branch-name>.*`
configs, just like it currently removes all `branch.<branch-name>.*`
configs.

Signed-off-by: Denton Liu <liu.denton@xxxxxxxxx>
---
 Documentation/config/format.txt    |  5 ++++
 Documentation/git-format-patch.txt | 12 +++++++++
 builtin/branch.c                   | 16 +++++++++---
 builtin/log.c                      | 41 +++++++++++++++++++++++++-----
 t/t3200-branch.sh                  |  4 ++-
 t/t4014-format-patch.sh            | 20 +++++++++++++++
 t/t9902-completion.sh              |  5 +++-
 7 files changed, 91 insertions(+), 12 deletions(-)

diff --git a/Documentation/config/format.txt b/Documentation/config/format.txt
index dc77941c48..7d2b3b7331 100644
--- a/Documentation/config/format.txt
+++ b/Documentation/config/format.txt
@@ -36,6 +36,11 @@ format.subjectPrefix::
 	The default for format-patch is to output files with the '[PATCH]'
 	subject prefix. Use this variable to change that prefix.
 
+format.<branch-name>.coverSubject::
+	When format-patch generates a cover letter for the given
+	<branch-name>, use the specified subject for the cover letter
+	instead of the generic template.
+
 format.signature::
 	The default for format-patch is to output a signature containing
 	the Git version number. Use this variable to change that default.
diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt
index 7b71d4e2ed..a43f317877 100644
--- a/Documentation/git-format-patch.txt
+++ b/Documentation/git-format-patch.txt
@@ -19,6 +19,7 @@ SYNOPSIS
 		   [--start-number <n>] [--numbered-files]
 		   [--in-reply-to=<Message-Id>] [--suffix=.<sfx>]
 		   [--ignore-if-in-upstream]
+		   [--cover-subject=<subject>]
 		   [--rfc] [--subject-prefix=<Subject-Prefix>]
 		   [(--reroll-count|-v) <n>]
 		   [--to=<email>] [--cc=<email>]
@@ -170,6 +171,10 @@ will want to ensure that threading is disabled for `git send-email`.
 	patches being generated, and any patch that matches is
 	ignored.
 
+--cover-subject=<subject>::
+	Instead of using the default "*** SUBJECT HERE ***" subject for
+	the cover letter, use the given <subject>.
+
 --subject-prefix=<Subject-Prefix>::
 	Instead of the standard '[PATCH]' prefix in the subject
 	line, instead use '[<Subject-Prefix>]'. This
@@ -346,6 +351,13 @@ attachments, and sign off patches with configuration variables.
 	coverletter = auto
 ------------
 
+In addition, for a specific branch, you can specify a custom cover
+letter subject.
+
+------------
+[format "branch-name"]
+	coverSubject = "subject for branch-name only"
+------------
 
 DISCUSSION
 ----------
diff --git a/builtin/branch.c b/builtin/branch.c
index d4359b33ac..367e1fc9bc 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -178,12 +178,22 @@ static int check_branch_commit(const char *branchname, const char *refname,
 	return 0;
 }
 
+static const char *branch_specific_config[] = {
+	"branch",
+	"format",
+	NULL
+};
+
 static void delete_branch_config(const char *branchname)
 {
 	struct strbuf buf = STRBUF_INIT;
-	strbuf_addf(&buf, "branch.%s", branchname);
-	if (git_config_rename_section(buf.buf, NULL) < 0)
-		warning(_("Update of config-file failed"));
+	int i;
+	for (i = 0; branch_specific_config[i]; i++) {
+		strbuf_addf(&buf, "%s.%s", branch_specific_config[i], branchname);
+		if (git_config_rename_section(buf.buf, NULL) < 0)
+			warning(_("Update of config-file failed"));
+		strbuf_reset(&buf);
+	}
 	strbuf_release(&buf);
 }
 
diff --git a/builtin/log.c b/builtin/log.c
index e43ee12fb1..2bbe712e7c 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -1030,17 +1030,33 @@ static void show_diffstat(struct rev_info *rev,
 	fprintf(rev->diffopt.file, "\n");
 }
 
+static int read_branch_subject(struct strbuf *buf, const char *branch_name)
+{
+	char *v = NULL;
+	struct strbuf name = STRBUF_INIT;
+	strbuf_addf(&name, "format.%s.coverSubject", branch_name);
+	if (git_config_get_string(name.buf, &v)) {
+		strbuf_release(&name);
+		return -1;
+	}
+	strbuf_addstr(buf, v);
+	free(v);
+	strbuf_release(&name);
+	return 0;
+}
+
 static void make_cover_letter(struct rev_info *rev, int use_stdout,
 			      struct commit *origin,
 			      int nr, struct commit **list,
 			      const char *branch_name,
+			      const char *subject,
 			      int quiet)
 {
 	const char *committer;
-	const char *body = "*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n";
-	const char *msg;
+	const char *body = "*** BLURB HERE ***";
 	struct shortlog log;
 	struct strbuf sb = STRBUF_INIT;
+	struct strbuf subject_sb = STRBUF_INIT;
 	int i;
 	const char *encoding = "UTF-8";
 	int need_8bit_cte = 0;
@@ -1068,17 +1084,24 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
 	if (!branch_name)
 		branch_name = find_branch_name(rev);
 
-	msg = body;
+	if (!subject) {
+		if (branch_name && *branch_name && !read_branch_subject(&subject_sb, branch_name))
+			subject = subject_sb.buf;
+		else
+			subject = "*** SUBJECT HERE ***";
+	}
+
 	pp.fmt = CMIT_FMT_EMAIL;
 	pp.date_mode.type = DATE_RFC2822;
 	pp.rev = rev;
 	pp.print_email_subject = 1;
 	pp_user_info(&pp, NULL, &sb, committer, encoding);
-	pp_title_line(&pp, &msg, &sb, encoding, need_8bit_cte);
-	pp_remainder(&pp, &msg, &sb, 0);
+	pp_title_line(&pp, &subject, &sb, encoding, need_8bit_cte);
+	pp_remainder(&pp, &body, &sb, 0);
 	add_branch_description(&sb, branch_name);
 	fprintf(rev->diffopt.file, "%s\n", sb.buf);
 
+	strbuf_release(&subject_sb);
 	strbuf_release(&sb);
 
 	shortlog_init(&log);
@@ -1512,6 +1535,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 	int no_binary_diff = 0;
 	int zero_commit = 0;
 	struct commit *origin = NULL;
+	const char *cover_subject = NULL;
 	const char *in_reply_to = NULL;
 	struct patch_ids ids;
 	struct strbuf buf = STRBUF_INIT;
@@ -1554,6 +1578,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 		{ OPTION_CALLBACK, 0, "rfc", &rev, NULL,
 			    N_("Use [RFC PATCH] instead of [PATCH]"),
 			    PARSE_OPT_NOARG | PARSE_OPT_NONEG, rfc_callback },
+		OPT_STRING(0, "cover-subject", &cover_subject, N_("subject"),
+			    N_("the subject for the cover letter")),
 		{ OPTION_CALLBACK, 0, "subject-prefix", &rev, N_("prefix"),
 			    N_("Use [<prefix>] instead of [PATCH]"),
 			    PARSE_OPT_NONEG, subject_prefix_callback },
@@ -1617,8 +1643,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 	extra_to.strdup_strings = 1;
 	extra_cc.strdup_strings = 1;
 	init_log_defaults();
-	git_config(git_format_config, NULL);
 	repo_init_revisions(the_repository, &rev, prefix);
+
+	git_config(git_format_config, NULL);
 	rev.commit_format = CMIT_FMT_EMAIL;
 	rev.expand_tabs_in_log_default = 0;
 	rev.verbose_header = 1;
@@ -1893,7 +1920,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
 		if (thread)
 			gen_message_id(&rev, "cover");
 		make_cover_letter(&rev, use_stdout,
-				  origin, nr, list, branch_name, quiet);
+				  origin, nr, list, branch_name, cover_subject, quiet);
 		print_bases(&bases, rev.diffopt.file);
 		print_signature(rev.diffopt.file);
 		total++;
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index e9ad50b66d..dad23f7d4c 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -782,9 +782,11 @@ test_expect_success 'test tracking setup via --track but deeper' '
 '
 
 test_expect_success 'test deleting branch deletes branch config' '
+	git config format.my7.coverSubject "cover subject" &&
 	git branch -d my7 &&
 	test -z "$(git config branch.my7.remote)" &&
-	test -z "$(git config branch.my7.merge)"
+	test -z "$(git config branch.my7.merge)" &&
+	test -z "$(git config format.my7.coverSubject)"
 '
 
 test_expect_success 'test deleting branch without config' '
diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh
index 3423f974bc..9d11992e10 100755
--- a/t/t4014-format-patch.sh
+++ b/t/t4014-format-patch.sh
@@ -1469,6 +1469,26 @@ test_expect_success 'format patch ignores color.ui' '
 	test_cmp expect actual
 '
 
+test_expect_success 'cover letter with config subject' '
+	test_config format.rebuild-1.coverSubject "config subject" &&
+	git checkout rebuild-1 &&
+	git format-patch --stdout --cover-letter master >actual &&
+	grep "Subject: \[PATCH 0/2\] config subject" actual
+'
+
+test_expect_success 'cover letter with command-line subject' '
+	git checkout rebuild-1 &&
+	git format-patch --stdout --cover-letter --cover-subject "command-line subject" master >actual &&
+	grep "Subject: \[PATCH 0/2\] command-line subject" actual
+'
+
+test_expect_success 'cover letter with command-line subject overrides config' '
+	test_config format.rebuild-1.coverSubject "config subject" &&
+	git checkout rebuild-1 &&
+	git format-patch --stdout --cover-letter --cover-subject "command-line subject" master >actual &&
+	grep "Subject: \[PATCH 0/2\] command-line subject" actual
+'
+
 test_expect_success 'cover letter using branch description (1)' '
 	git checkout rebuild-1 &&
 	test_config branch.rebuild-1.description hello &&
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 43cf313a1c..a96f1662c7 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -1548,7 +1548,10 @@ test_expect_success 'complete tree filename with metacharacters' '
 '
 
 test_expect_success PERL 'send-email' '
-	test_completion "git send-email --cov" "--cover-letter " &&
+	test_completion "git send-email --cov" <<-\EOF &&
+	--cover-letter Z
+	--cover-subject=Z
+	EOF
 	test_completion "git send-email ma" "master "
 '
 
-- 
2.21.0.1049.geb646f7864




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux