am: support --patch-format=mboxrd

Combined with "git format-patch --pretty=mboxrd", this should allow us to round-trip commit messages with embedded mbox "From " lines without corruption. Signed-off-by: Eric Wong <e@80x24.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Eric Wong committed Jun 5, 2016 at 04:46 UTC d9925d1a714a440f4063f64e1bd776194d2dd918
3 files changed +33 -4
Documentation/git-am.txt
+2 -1
@@ -116,7 +116,8 @@ default. You can use `--no-utf8` to override this.
116 By default the command will try to detect the patch format
117 automatically. This option allows the user to bypass the automatic
118 detection and specify the patch format that the patch(es) should be
119 - interpreted as. Valid formats are mbox, stgit, stgit-series and hg.
119 + interpreted as. Valid formats are mbox, mboxrd,
120 + stgit, stgit-series and hg.
121
122 -i::
123 --interactive::
builtin/am.c
+11 -3
@@ -70,7 +70,8 @@ enum patch_format {
70 PATCH_FORMAT_MBOX,
71 PATCH_FORMAT_STGIT,
72 PATCH_FORMAT_STGIT_SERIES,
73 - PATCH_FORMAT_HG
73 + PATCH_FORMAT_HG,
74 + PATCH_FORMAT_MBOXRD
75 };
76
77 enum keep_type {
@@ -712,7 +713,8 @@ done:
713 * Splits out individual email patches from `paths`, where each path is either
714 * a mbox file or a Maildir. Returns 0 on success, -1 on failure.
715 */
715 -static int split_mail_mbox(struct am_state *state, const char **paths, int keep_cr)
716 +static int split_mail_mbox(struct am_state *state, const char **paths,
717 + int keep_cr, int mboxrd)
718 {
719 struct child_process cp = CHILD_PROCESS_INIT;
720 struct strbuf last = STRBUF_INIT;
@@ -724,6 +726,8 @@ static int split_mail_mbox(struct am_state *state, const char **paths, int keep_
726 argv_array_push(&cp.args, "-b");
727 if (keep_cr)
728 argv_array_push(&cp.args, "--keep-cr");
729 + if (mboxrd)
730 + argv_array_push(&cp.args, "--mboxrd");
731 argv_array_push(&cp.args, "--");
732 argv_array_pushv(&cp.args, paths);
733
@@ -965,13 +969,15 @@ static int split_mail(struct am_state *state, enum patch_format patch_format,
969
970 switch (patch_format) {
971 case PATCH_FORMAT_MBOX:
968 - return split_mail_mbox(state, paths, keep_cr);
972 + return split_mail_mbox(state, paths, keep_cr, 0);
973 case PATCH_FORMAT_STGIT:
974 return split_mail_conv(stgit_patch_to_mail, state, paths, keep_cr);
975 case PATCH_FORMAT_STGIT_SERIES:
976 return split_mail_stgit_series(state, paths, keep_cr);
977 case PATCH_FORMAT_HG:
978 return split_mail_conv(hg_patch_to_mail, state, paths, keep_cr);
979 + case PATCH_FORMAT_MBOXRD:
980 + return split_mail_mbox(state, paths, keep_cr, 1);
981 default:
982 die("BUG: invalid patch_format");
983 }
@@ -2201,6 +2207,8 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int
2207 *opt_value = PATCH_FORMAT_STGIT_SERIES;
2208 else if (!strcmp(arg, "hg"))
2209 *opt_value = PATCH_FORMAT_HG;
2210 + else if (!strcmp(arg, "mboxrd"))
2211 + *opt_value = PATCH_FORMAT_MBOXRD;
2212 else
2213 return error(_("Invalid value for --patch-format: %s"), arg);
2214 return 0;
t/t4150-am.sh
+20
@@ -957,4 +957,24 @@ test_expect_success 'am -s unexpected trailer block' '
957 test_cmp expect actual
958 '
959
960 +test_expect_success 'am --patch-format=mboxrd handles mboxrd' '
961 + rm -fr .git/rebase-apply &&
962 + git checkout -f first &&
963 + echo mboxrd >>file &&
964 + git add file &&
965 + cat >msg <<-\INPUT_END &&
966 + mboxrd should escape the body
967 +
968 + From could trip up a loose mbox parser
969 + >From extra escape for reversibility
970 + INPUT_END
971 + git commit -F msg &&
972 + git format-patch --pretty=mboxrd --stdout -1 >mboxrd1 &&
973 + grep "^>From could trip up a loose mbox parser" mboxrd1 &&
974 + git checkout -f first &&
975 + git am --patch-format=mboxrd mboxrd1 &&
976 + git cat-file commit HEAD | tail -n4 >out &&
977 + test_cmp msg out
978 +'
979 +
980 test_done