format-patch: --rfc honors what --subject-prefix sets

Rather than replacing the configured subject prefix (either through the git config or command line) entirely with "RFC PATCH", this change prepends RFC to whatever subject prefix was already in use. This is useful, for example, when a user is working on a repository that has a subject prefix considered to disambiguate patches: git config format.subjectPrefix 'PATCH my-project' Prior to this change, formatting patches with --rfc would lose the 'my-project' information. The data flow for the subject-prefix was that rev.subject_prefix were to be kept the authoritative version of the subject prefix even while parsing command line options, and sprefix variable was used as a temporary area to futz with it. Now, the parsing code has been refactored to build the subject prefix into the sprefix variable and assigns its value at the end to rev.subject_prefix, which makes the flow easier to grasp. Signed-off-by: Drew DeVault <sir@cmpwn.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Drew DeVault committed Aug 30, 2023 at 08:43 UTC e0d7db7423a91673c001aaa5e580c815ce2f7f92
3 files changed +48 -23
Documentation/git-format-patch.txt
+12 -6
@@ -217,9 +217,15 @@ populated with placeholder text.
217
218 --subject-prefix=<subject prefix>::
219 Instead of the standard '[PATCH]' prefix in the subject
220 - line, instead use '[<subject prefix>]'. This
221 - allows for useful naming of a patch series, and can be
222 - combined with the `--numbered` option.
220 + line, instead use '[<subject prefix>]'. This can be used
221 + to name a patch series, and can be combined with the
222 + `--numbered` option.
223 ++
224 +The configuration variable `format.subjectPrefix` may also be used
225 +to configure a subject prefix to apply to a given repository for
226 +all patches. This is often useful on mailing lists which receive
227 +patches for several repositories and can be used to disambiguate
228 +the patches (with a value of e.g. "PATCH my-project").
229
230 --filename-max-length=<n>::
231 Instead of the standard 64 bytes, chomp the generated output
@@ -229,9 +235,9 @@ populated with placeholder text.
235 variable, or 64 if unconfigured.
236
237 --rfc::
232 - Alias for `--subject-prefix="RFC PATCH"`. RFC means "Request For
233 - Comments"; use this when sending an experimental patch for
234 - discussion rather than application.
238 + Prepends "RFC" to the subject prefix (producing "RFC PATCH" by
239 + default). RFC means "Request For Comments"; use this when sending
240 + an experimental patch for discussion rather than application.
241
242 -v <n>::
243 --reroll-count=<n>::
builtin/log.c
+15 -16
@@ -1468,19 +1468,16 @@ static int subject_prefix = 0;
1468 static int subject_prefix_callback(const struct option *opt, const char *arg,
1469 int unset)
1470 {
1471 + struct strbuf *sprefix;
1472 +
1473 BUG_ON_OPT_NEG(unset);
1474 + sprefix = opt->value;
1475 subject_prefix = 1;
1473 - ((struct rev_info *)opt->value)->subject_prefix = arg;
1476 + strbuf_reset(sprefix);
1477 + strbuf_addstr(sprefix, arg);
1478 return 0;
1479 }
1480
1477 -static int rfc_callback(const struct option *opt, const char *arg, int unset)
1478 -{
1479 - BUG_ON_OPT_NEG(unset);
1480 - BUG_ON_OPT_ARG(arg);
1481 - return subject_prefix_callback(opt, "RFC PATCH", unset);
1482 -}
1483 -
1481 static int numbered_cmdline_opt = 0;
1482
1483 static int numbered_callback(const struct option *opt, const char *arg,
@@ -1907,6 +1904,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
1904 struct strbuf rdiff_title = STRBUF_INIT;
1905 struct strbuf sprefix = STRBUF_INIT;
1906 int creation_factor = -1;
1907 + int rfc = 0;
1908
1909 const struct option builtin_format_patch_options[] = {
1910 OPT_CALLBACK_F('n', "numbered", &numbered, NULL,
@@ -1930,13 +1928,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
1928 N_("mark the series as Nth re-roll")),
1929 OPT_INTEGER(0, "filename-max-length", &fmt_patch_name_max,
1930 N_("max length of output filename")),
1933 - OPT_CALLBACK_F(0, "rfc", &rev, NULL,
1934 - N_("use [RFC PATCH] instead of [PATCH]"),
1935 - PARSE_OPT_NOARG | PARSE_OPT_NONEG, rfc_callback),
1931 + OPT_BOOL(0, "rfc", &rfc, N_("use [RFC PATCH] instead of [PATCH]")),
1932 OPT_STRING(0, "cover-from-description", &cover_from_description_arg,
1933 N_("cover-from-description-mode"),
1934 N_("generate parts of a cover letter based on a branch's description")),
1939 - OPT_CALLBACK_F(0, "subject-prefix", &rev, N_("prefix"),
1935 + OPT_CALLBACK_F(0, "subject-prefix", &sprefix, N_("prefix"),
1936 N_("use [<prefix>] instead of [PATCH]"),
1937 PARSE_OPT_NONEG, subject_prefix_callback),
1938 OPT_CALLBACK_F('o', "output-directory", &output_directory,
@@ -2016,11 +2012,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
2012 rev.max_parents = 1;
2013 rev.diffopt.flags.recursive = 1;
2014 rev.diffopt.no_free = 1;
2019 - rev.subject_prefix = fmt_patch_subject_prefix;
2015 memset(&s_r_opt, 0, sizeof(s_r_opt));
2016 s_r_opt.def = "HEAD";
2017 s_r_opt.revarg_opt = REVARG_COMMITTISH;
2018
2019 + strbuf_addstr(&sprefix, fmt_patch_subject_prefix);
2020 if (format_no_prefix)
2021 diff_set_noprefix(&rev.diffopt);
2022
@@ -2048,13 +2044,16 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
2044 if (cover_from_description_arg)
2045 cover_from_description_mode = parse_cover_from_description(cover_from_description_arg);
2046
2047 + if (rfc)
2048 + strbuf_insertstr(&sprefix, 0, "RFC ");
2049 +
2050 if (reroll_count) {
2052 - strbuf_addf(&sprefix, "%s v%s",
2053 - rev.subject_prefix, reroll_count);
2051 + strbuf_addf(&sprefix, " v%s", reroll_count);
2052 rev.reroll_count = reroll_count;
2055 - rev.subject_prefix = sprefix.buf;
2053 }
2054
2055 + rev.subject_prefix = sprefix.buf;
2056 +
2057 for (i = 0; i < extra_hdr.nr; i++) {
2058 strbuf_addstr(&buf, extra_hdr.items[i].string);
2059 strbuf_addch(&buf, '\n');
t/t4014-format-patch.sh
+21 -1
@@ -1373,7 +1373,27 @@ test_expect_success '--rfc' '
1373 Subject: [RFC PATCH 1/1] header with . in it
1374 EOF
1375 git format-patch -n -1 --stdout --rfc >patch &&
1376 - grep ^Subject: patch >actual &&
1376 + grep "^Subject:" patch >actual &&
1377 + test_cmp expect actual
1378 +'
1379 +
1380 +test_expect_success '--rfc does not overwrite prefix' '
1381 + cat >expect <<-\EOF &&
1382 + Subject: [RFC PATCH foobar 1/1] header with . in it
1383 + EOF
1384 + git -c format.subjectPrefix="PATCH foobar" \
1385 + format-patch -n -1 --stdout --rfc >patch &&
1386 + grep "^Subject:" patch >actual &&
1387 + test_cmp expect actual
1388 +'
1389 +
1390 +test_expect_success '--rfc is argument order independent' '
1391 + cat >expect <<-\EOF &&
1392 + Subject: [RFC PATCH foobar 1/1] header with . in it
1393 + EOF
1394 + git format-patch -n -1 --stdout --rfc \
1395 + --subject-prefix="PATCH foobar" >patch &&
1396 + grep "^Subject:" patch >actual &&
1397 test_cmp expect actual
1398 '
1399