Skip to content

Commit bf8e65b

Browse files
Denton-Lgitster
authored andcommitted
format-patch: teach --cover-from-description option
Before, when format-patch generated a cover letter, only the body would be populated with a branch's description while the subject would be populated with placeholder text. However, users may want to have the subject of their cover letter automatically populated in the same way. Teach format-patch to accept the `--cover-from-description` option and corresponding `format.coverFromDescription` config, allowing users to populate different parts of the cover letter (including the subject now). Signed-off-by: Denton Liu <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent a92331d commit bf8e65b

File tree

5 files changed

+279
-21
lines changed

5 files changed

+279
-21
lines changed

Documentation/config/format.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ format.subjectPrefix::
3636
The default for format-patch is to output files with the '[PATCH]'
3737
subject prefix. Use this variable to change that prefix.
3838

39+
format.coverFromDescription::
40+
The default mode for format-patch to determine which parts of
41+
the cover letter will be populated using the branch's
42+
description. See the `--cover-from-description` option in
43+
linkgit:git-format-patch[1].
44+
3945
format.signature::
4046
The default for format-patch is to output a signature containing
4147
the Git version number. Use this variable to change that default.

Documentation/git-format-patch.txt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ SYNOPSIS
1919
[--start-number <n>] [--numbered-files]
2020
[--in-reply-to=<message id>] [--suffix=.<sfx>]
2121
[--ignore-if-in-upstream]
22+
[--cover-from-description=<mode>]
2223
[--rfc] [--subject-prefix=<subject prefix>]
2324
[(--reroll-count|-v) <n>]
2425
[--to=<email>] [--cc=<email>]
@@ -171,6 +172,26 @@ will want to ensure that threading is disabled for `git send-email`.
171172
patches being generated, and any patch that matches is
172173
ignored.
173174

175+
--cover-from-description=<mode>::
176+
Controls which parts of the cover letter will be automatically
177+
populated using the branch's description.
178+
+
179+
If `<mode>` is `message` or `default`, the cover letter subject will be
180+
populated with placeholder text. The body of the cover letter will be
181+
populated with the branch's description. This is the default mode when
182+
no configuration nor command line option is specified.
183+
+
184+
If `<mode>` is `subject`, the first paragraph of the branch description will
185+
populate the cover letter subject. The remainder of the description will
186+
populate the body of the cover letter.
187+
+
188+
If `<mode>` is `auto`, if the first paragraph of the branch description
189+
is greater than 100 bytes, then the mode will be `message`, otherwise
190+
`subject` will be used.
191+
+
192+
If `<mode>` is `none`, both the cover letter subject and body will be
193+
populated with placeholder text.
194+
174195
--subject-prefix=<subject prefix>::
175196
Instead of the standard '[PATCH]' prefix in the subject
176197
line, instead use '[<subject prefix>]'. This
@@ -347,6 +368,7 @@ with configuration variables.
347368
signOff = true
348369
outputDirectory = <directory>
349370
coverLetter = auto
371+
coverFromDescription = auto
350372
------------
351373

352374

builtin/log.c

Lines changed: 75 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "range-diff.h"
3838

3939
#define MAIL_DEFAULT_WRAP 72
40+
#define COVER_FROM_AUTO_MAX_SUBJECT_LEN 100
4041

4142
/* Set a default date-time format for git log ("log.date" config variable) */
4243
static const char *default_date_mode = NULL;
@@ -777,6 +778,13 @@ enum thread_level {
777778
THREAD_DEEP
778779
};
779780

781+
enum cover_from_description {
782+
COVER_FROM_NONE,
783+
COVER_FROM_MESSAGE,
784+
COVER_FROM_SUBJECT,
785+
COVER_FROM_AUTO
786+
};
787+
780788
static enum thread_level thread;
781789
static int do_signoff;
782790
static int base_auto;
@@ -785,6 +793,23 @@ static const char *signature = git_version_string;
785793
static const char *signature_file;
786794
static enum cover_setting config_cover_letter;
787795
static const char *config_output_directory;
796+
static enum cover_from_description cover_from_description_mode = COVER_FROM_MESSAGE;
797+
798+
static enum cover_from_description parse_cover_from_description(const char *arg)
799+
{
800+
if (!arg || !strcmp(arg, "default"))
801+
return COVER_FROM_MESSAGE;
802+
else if (!strcmp(arg, "none"))
803+
return COVER_FROM_NONE;
804+
else if (!strcmp(arg, "message"))
805+
return COVER_FROM_MESSAGE;
806+
else if (!strcmp(arg, "subject"))
807+
return COVER_FROM_SUBJECT;
808+
else if (!strcmp(arg, "auto"))
809+
return COVER_FROM_AUTO;
810+
else
811+
die(_("%s: invalid cover from description mode"), arg);
812+
}
788813

789814
static int git_format_config(const char *var, const char *value, void *cb)
790815
{
@@ -891,6 +916,10 @@ static int git_format_config(const char *var, const char *value, void *cb)
891916
}
892917
return 0;
893918
}
919+
if (!strcmp(var, "format.coverfromdescription")) {
920+
cover_from_description_mode = parse_cover_from_description(value);
921+
return 0;
922+
}
894923

895924
return git_log_config(var, value, cb);
896925
}
@@ -997,20 +1026,6 @@ static void print_signature(FILE *file)
9971026
putc('\n', file);
9981027
}
9991028

1000-
static void add_branch_description(struct strbuf *buf, const char *branch_name)
1001-
{
1002-
struct strbuf desc = STRBUF_INIT;
1003-
if (!branch_name || !*branch_name)
1004-
return;
1005-
read_branch_desc(&desc, branch_name);
1006-
if (desc.len) {
1007-
strbuf_addch(buf, '\n');
1008-
strbuf_addbuf(buf, &desc);
1009-
strbuf_addch(buf, '\n');
1010-
}
1011-
strbuf_release(&desc);
1012-
}
1013-
10141029
static char *find_branch_name(struct rev_info *rev)
10151030
{
10161031
int i, positive = -1;
@@ -1057,15 +1072,51 @@ static void show_diffstat(struct rev_info *rev,
10571072
fprintf(rev->diffopt.file, "\n");
10581073
}
10591074

1075+
static void prepare_cover_text(struct pretty_print_context *pp,
1076+
const char *branch_name,
1077+
struct strbuf *sb,
1078+
const char *encoding,
1079+
int need_8bit_cte)
1080+
{
1081+
const char *subject = "*** SUBJECT HERE ***";
1082+
const char *body = "*** BLURB HERE ***";
1083+
struct strbuf description_sb = STRBUF_INIT;
1084+
struct strbuf subject_sb = STRBUF_INIT;
1085+
1086+
if (cover_from_description_mode == COVER_FROM_NONE)
1087+
goto do_pp;
1088+
1089+
if (branch_name && *branch_name)
1090+
read_branch_desc(&description_sb, branch_name);
1091+
if (!description_sb.len)
1092+
goto do_pp;
1093+
1094+
if (cover_from_description_mode == COVER_FROM_SUBJECT ||
1095+
cover_from_description_mode == COVER_FROM_AUTO)
1096+
body = format_subject(&subject_sb, description_sb.buf, " ");
1097+
1098+
if (cover_from_description_mode == COVER_FROM_MESSAGE ||
1099+
(cover_from_description_mode == COVER_FROM_AUTO &&
1100+
subject_sb.len > COVER_FROM_AUTO_MAX_SUBJECT_LEN))
1101+
body = description_sb.buf;
1102+
else
1103+
subject = subject_sb.buf;
1104+
1105+
do_pp:
1106+
pp_title_line(pp, &subject, sb, encoding, need_8bit_cte);
1107+
pp_remainder(pp, &body, sb, 0);
1108+
1109+
strbuf_release(&description_sb);
1110+
strbuf_release(&subject_sb);
1111+
}
1112+
10601113
static void make_cover_letter(struct rev_info *rev, int use_stdout,
10611114
struct commit *origin,
10621115
int nr, struct commit **list,
10631116
const char *branch_name,
10641117
int quiet)
10651118
{
10661119
const char *committer;
1067-
const char *body = "*** SUBJECT HERE ***\n\n*** BLURB HERE ***\n";
1068-
const char *msg;
10691120
struct shortlog log;
10701121
struct strbuf sb = STRBUF_INIT;
10711122
int i;
@@ -1095,15 +1146,12 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,
10951146
if (!branch_name)
10961147
branch_name = find_branch_name(rev);
10971148

1098-
msg = body;
10991149
pp.fmt = CMIT_FMT_EMAIL;
11001150
pp.date_mode.type = DATE_RFC2822;
11011151
pp.rev = rev;
11021152
pp.print_email_subject = 1;
11031153
pp_user_info(&pp, NULL, &sb, committer, encoding);
1104-
pp_title_line(&pp, &msg, &sb, encoding, need_8bit_cte);
1105-
pp_remainder(&pp, &msg, &sb, 0);
1106-
add_branch_description(&sb, branch_name);
1154+
prepare_cover_text(&pp, branch_name, &sb, encoding, need_8bit_cte);
11071155
fprintf(rev->diffopt.file, "%s\n", sb.buf);
11081156

11091157
strbuf_release(&sb);
@@ -1545,6 +1593,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
15451593
int use_patch_format = 0;
15461594
int quiet = 0;
15471595
int reroll_count = -1;
1596+
char *cover_from_description_arg = NULL;
15481597
char *branch_name = NULL;
15491598
char *base_commit = NULL;
15501599
struct base_tree_info bases;
@@ -1581,6 +1630,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
15811630
{ OPTION_CALLBACK, 0, "rfc", &rev, NULL,
15821631
N_("Use [RFC PATCH] instead of [PATCH]"),
15831632
PARSE_OPT_NOARG | PARSE_OPT_NONEG, rfc_callback },
1633+
OPT_STRING(0, "cover-from-description", &cover_from_description_arg,
1634+
N_("cover-from-description-mode"),
1635+
N_("generate parts of a cover letter based on a branch's description")),
15841636
{ OPTION_CALLBACK, 0, "subject-prefix", &rev, N_("prefix"),
15851637
N_("Use [<prefix>] instead of [PATCH]"),
15861638
PARSE_OPT_NONEG, subject_prefix_callback },
@@ -1672,6 +1724,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
16721724
PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |
16731725
PARSE_OPT_KEEP_DASHDASH);
16741726

1727+
if (cover_from_description_arg)
1728+
cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
1729+
16751730
if (0 < reroll_count) {
16761731
struct strbuf sprefix = STRBUF_INIT;
16771732
strbuf_addf(&sprefix, "%s v%d",

0 commit comments

Comments
 (0)