{"thread":{"id":"42531","subject":"[PATCH v2 0/3] support mboxrd format","startedAt":"2016-06-05T04:46:38Z","lastAt":"2016-06-06T23:02:48Z","messageCount":6,"participants":["Eric Wong","Junio C Hamano"],"isPatch":true,"patchVersion":2,"patchTotal":3},"messages":[{"id":"288382","messageId":"20160605044641.9221-1-e@80x24.org","threadId":"42531","inReplyTo":null,"subject":"[PATCH v2 0/3] support mboxrd format","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2016-06-05T04:46:38Z","receivedAt":"2016-06-05T04:46:38Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Changes since v2:\n\n* beef up tests, including accounting for the trailing whitespace\n  omission in pretty output but still accepting and preserving\n  trailing whitespace in mailsplit.\n\n* indicate disabling variable interpolation in heredoc (but\n  using variable interpolation as needed for trailing space\n  in tests).\n\n* use \"git grep\" for \"-A<NUM>\" for portability\n\n* avoid the use of regexp for matching /^From / and /^>+From /\n\nThanks to Eric Sunshine and Junio for helping with the first round.\n\nv1 started at http://mid.gmane.org/20160530232142.21098-1-e@80x24.org\n\nThe following changes since commit 6326f199252a1a5fbdea105473f8305d850cdd87:\n\n  Almost ready for 2.9-rc2 (2016-06-03 14:38:35 -0700)\n\nare available in the git repository at:\n\n  git://bogomips.org/git-svn.git mboxrd-v2\n\nfor you to fetch changes up to 1ab223c4f7b8d6cc246f873795d89ac97da84ae1:\n\n  am: support --patch-format=mboxrd (2016-06-05 04:16:57 +0000)\n\n----------------------------------------------------------------\nEric Wong (3):\n      pretty: support \"mboxrd\" output format\n      mailsplit: support unescaping mboxrd messages\n      am: support --patch-format=mboxrd\n\n Documentation/git-am.txt        |  3 ++-\n Documentation/git-mailsplit.txt |  7 ++++++-\n builtin/am.c                    | 14 +++++++++++---\n builtin/log.c                   |  2 +-\n builtin/mailsplit.c             | 18 ++++++++++++++++++\n commit.h                        |  6 ++++++\n log-tree.c                      |  4 ++--\n pretty.c                        | 33 +++++++++++++++++++++++++--------\n t/t4014-format-patch.sh         | 41 +++++++++++++++++++++++++++++++++++++++++\n t/t4150-am.sh                   | 20 ++++++++++++++++++++\n t/t5100-mailinfo.sh             | 31 +++++++++++++++++++++++++++++++\n t/t5100/0001mboxrd              |  4 ++++\n t/t5100/0002mboxrd              |  5 +++++\n t/t5100/sample.mboxrd           | 19 +++++++++++++++++++\n 14 files changed, 191 insertions(+), 16 deletions(-)\n create mode 100644 t/t5100/0001mboxrd\n create mode 100644 t/t5100/0002mboxrd\n create mode 100644 t/t5100/sample.mboxrd\n"},{"id":"288384","messageId":"20160605044641.9221-2-e@80x24.org","threadId":"42531","inReplyTo":"20160605044641.9221-1-e@80x24.org","subject":"[PATCH v2 1/3] pretty: support \"mboxrd\" output format","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2016-06-05T04:46:39Z","receivedAt":"2016-06-05T04:46:39Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This output format prevents format-patch output from breaking\nreaders if somebody copy+pasted an mbox into a commit message.\n\nUnlike the traditional \"mboxo\" format, \"mboxrd\" is designed to\nbe fully-reversible.  \"mboxrd\" also gracefully degrades to\nshowing extra \">\" in existing \"mboxo\" readers.\n\nThis degradation is preferable to breaking message splitting\ncompletely, a problem I've seen in \"mboxcl\" due to having\nmultiple, non-existent, or inaccurate Content-Length headers.\n\n\"mboxcl2\" is a non-starter since it's inherits the problems\nof \"mboxcl\" while being completely incompatible with existing\ntooling based around mailsplit.\n\nref: http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/mail-mbox-formats.html\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n builtin/log.c           |  2 +-\n commit.h                |  6 ++++++\n log-tree.c              |  4 ++--\n pretty.c                | 33 +++++++++++++++++++++++++--------\n t/t4014-format-patch.sh | 41 +++++++++++++++++++++++++++++++++++++++++\n 5 files changed, 75 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 099f4f7..6d6f368 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -953,7 +953,7 @@ static void make_cover_letter(struct rev_info *rev, int use_stdout,\n \tstruct pretty_print_context pp = {0};\n \tstruct commit *head = list[0];\n \n-\tif (rev->commit_format != CMIT_FMT_EMAIL)\n+\tif (!cmit_fmt_is_mail(rev->commit_format))\n \t\tdie(_(\"Cover letter needs email format\"));\n \n \tcommitter = git_committer_info(0);\ndiff --git a/commit.h b/commit.h\nindex b06db4d..1e04d3a 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -131,11 +131,17 @@ enum cmit_fmt {\n \tCMIT_FMT_FULLER,\n \tCMIT_FMT_ONELINE,\n \tCMIT_FMT_EMAIL,\n+\tCMIT_FMT_MBOXRD,\n \tCMIT_FMT_USERFORMAT,\n \n \tCMIT_FMT_UNSPECIFIED\n };\n \n+static inline int cmit_fmt_is_mail(enum cmit_fmt fmt)\n+{\n+\treturn (fmt == CMIT_FMT_EMAIL || fmt == CMIT_FMT_MBOXRD);\n+}\n+\n struct pretty_print_context {\n \t/*\n \t * Callers should tweak these to change the behavior of pp_* functions.\ndiff --git a/log-tree.c b/log-tree.c\nindex 78a5381..48daf84 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -603,7 +603,7 @@ void show_log(struct rev_info *opt)\n \t * Print header line of header..\n \t */\n \n-\tif (opt->commit_format == CMIT_FMT_EMAIL) {\n+\tif (cmit_fmt_is_mail(opt->commit_format)) {\n \t\tlog_write_email_headers(opt, commit, &ctx.subject, &extra_headers,\n \t\t\t\t\t&ctx.need_8bit_cte);\n \t} else if (opt->commit_format != CMIT_FMT_USERFORMAT) {\n@@ -694,7 +694,7 @@ void show_log(struct rev_info *opt)\n \n \tif ((ctx.fmt != CMIT_FMT_USERFORMAT) &&\n \t    ctx.notes_message && *ctx.notes_message) {\n-\t\tif (ctx.fmt == CMIT_FMT_EMAIL) {\n+\t\tif (cmit_fmt_is_mail(ctx.fmt)) {\n \t\t\tstrbuf_addstr(&msgbuf, \"---\\n\");\n \t\t\topt->shown_dashes = 1;\n \t\t}\ndiff --git a/pretty.c b/pretty.c\nindex 87c4497..6abd8a1 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -92,6 +92,7 @@ static void setup_commit_formats(void)\n \t\t{ \"medium\",\tCMIT_FMT_MEDIUM,\t0,\t8 },\n \t\t{ \"short\",\tCMIT_FMT_SHORT,\t\t0,\t0 },\n \t\t{ \"email\",\tCMIT_FMT_EMAIL,\t\t0,\t0 },\n+\t\t{ \"mboxrd\",\tCMIT_FMT_MBOXRD,\t0,\t0 },\n \t\t{ \"fuller\",\tCMIT_FMT_FULLER,\t0,\t8 },\n \t\t{ \"full\",\tCMIT_FMT_FULL,\t\t0,\t8 },\n \t\t{ \"oneline\",\tCMIT_FMT_ONELINE,\t1,\t0 }\n@@ -444,7 +445,7 @@ void pp_user_info(struct pretty_print_context *pp,\n \tif (pp->mailmap)\n \t\tmap_user(pp->mailmap, &mailbuf, &maillen, &namebuf, &namelen);\n \n-\tif (pp->fmt == CMIT_FMT_EMAIL) {\n+\tif (cmit_fmt_is_mail(pp->fmt)) {\n \t\tif (pp->from_ident && ident_cmp(pp->from_ident, &ident)) {\n \t\t\tstruct strbuf buf = STRBUF_INIT;\n \n@@ -494,6 +495,7 @@ void pp_user_info(struct pretty_print_context *pp,\n \t\t\t    show_ident_date(&ident, &pp->date_mode));\n \t\tbreak;\n \tcase CMIT_FMT_EMAIL:\n+\tcase CMIT_FMT_MBOXRD:\n \t\tstrbuf_addf(sb, \"Date: %s\\n\",\n \t\t\t    show_ident_date(&ident, DATE_MODE(RFC2822)));\n \t\tbreak;\n@@ -535,7 +537,7 @@ static void add_merge_info(const struct pretty_print_context *pp,\n {\n \tstruct commit_list *parent = commit->parents;\n \n-\tif ((pp->fmt == CMIT_FMT_ONELINE) || (pp->fmt == CMIT_FMT_EMAIL) ||\n+\tif ((pp->fmt == CMIT_FMT_ONELINE) || (cmit_fmt_is_mail(pp->fmt)) ||\n \t    !parent || !parent->next)\n \t\treturn;\n \n@@ -1614,7 +1616,7 @@ void pp_title_line(struct pretty_print_context *pp,\n \tif (pp->after_subject) {\n \t\tstrbuf_addstr(sb, pp->after_subject);\n \t}\n-\tif (pp->fmt == CMIT_FMT_EMAIL) {\n+\tif (cmit_fmt_is_mail(pp->fmt)) {\n \t\tstrbuf_addch(sb, '\\n');\n \t}\n \n@@ -1697,6 +1699,16 @@ static void pp_handle_indent(struct pretty_print_context *pp,\n \t\tstrbuf_add(sb, line, linelen);\n }\n \n+static int is_mboxrd_from(const char *line, int len)\n+{\n+\t/*\n+\t * a line matching /^From $/ here would only have len == 4\n+\t * at this point because is_empty_line would've trimmed all\n+\t * trailing space\n+\t */\n+\treturn len > 4 && starts_with(line + strspn(line, \">\"), \"From \");\n+}\n+\n void pp_remainder(struct pretty_print_context *pp,\n \t\t  const char **msg_p,\n \t\t  struct strbuf *sb,\n@@ -1725,8 +1737,13 @@ void pp_remainder(struct pretty_print_context *pp,\n \t\telse if (pp->expand_tabs_in_log)\n \t\t\tstrbuf_add_tabexpand(sb, pp->expand_tabs_in_log,\n \t\t\t\t\t     line, linelen);\n-\t\telse\n+\t\telse {\n+\t\t\tif (pp->fmt == CMIT_FMT_MBOXRD &&\n+\t\t\t\t\tis_mboxrd_from(line, linelen))\n+\t\t\t\tstrbuf_addch(sb, '>');\n+\n \t\t\tstrbuf_add(sb, line, linelen);\n+\t\t}\n \t\tstrbuf_addch(sb, '\\n');\n \t}\n }\n@@ -1750,14 +1767,14 @@ void pretty_print_commit(struct pretty_print_context *pp,\n \tencoding = get_log_output_encoding();\n \tmsg = reencoded = logmsg_reencode(commit, NULL, encoding);\n \n-\tif (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL)\n+\tif (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt))\n \t\tindent = 0;\n \n \t/*\n \t * We need to check and emit Content-type: to mark it\n \t * as 8-bit if we haven't done so.\n \t */\n-\tif (pp->fmt == CMIT_FMT_EMAIL && need_8bit_cte == 0) {\n+\tif (cmit_fmt_is_mail(pp->fmt) && need_8bit_cte == 0) {\n \t\tint i, ch, in_body;\n \n \t\tfor (in_body = i = 0; (ch = msg[i]); i++) {\n@@ -1785,7 +1802,7 @@ void pretty_print_commit(struct pretty_print_context *pp,\n \tmsg = skip_empty_lines(msg);\n \n \t/* These formats treat the title line specially. */\n-\tif (pp->fmt == CMIT_FMT_ONELINE || pp->fmt == CMIT_FMT_EMAIL)\n+\tif (pp->fmt == CMIT_FMT_ONELINE || cmit_fmt_is_mail(pp->fmt))\n \t\tpp_title_line(pp, &msg, sb, encoding, need_8bit_cte);\n \n \tbeginning_of_body = sb->len;\n@@ -1802,7 +1819,7 @@ void pretty_print_commit(struct pretty_print_context *pp,\n \t * format.  Make sure we did not strip the blank line\n \t * between the header and the body.\n \t */\n-\tif (pp->fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body)\n+\tif (cmit_fmt_is_mail(pp->fmt) && sb->len <= beginning_of_body)\n \t\tstrbuf_addch(sb, '\\n');\n \n \tunuse_commit_buffer(commit, reencoded);\ndiff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh\nindex 8049cad..8a1cab5 100755\n--- a/t/t4014-format-patch.sh\n+++ b/t/t4014-format-patch.sh\n@@ -1565,4 +1565,45 @@ test_expect_success 'format-patch --base overrides format.useAutoBase' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'format-patch --pretty=mboxrd' '\n+\tsp=\" \" &&\n+\tcat >msg <<-INPUT_END &&\n+\tmboxrd should escape the body\n+\n+\tFrom could trip up a loose mbox parser\n+\t>From extra escape for reversibility\n+\t>>From extra escape for reversibility 2\n+\tfrom lower case not escaped\n+\tFromm bad speling not escaped\n+\t From with leading space not escaped\n+\n+\tF\n+\tFrom\n+\tFrom$sp\n+\tFrom    $sp\n+\tFrom\t$sp\n+\tINPUT_END\n+\n+\tcat >expect <<-INPUT_END &&\n+\t>From could trip up a loose mbox parser\n+\t>>From extra escape for reversibility\n+\t>>>From extra escape for reversibility 2\n+\tfrom lower case not escaped\n+\tFromm bad speling not escaped\n+\t From with leading space not escaped\n+\n+\tF\n+\tFrom\n+\tFrom\n+\tFrom\n+\tFrom\n+\tINPUT_END\n+\n+\tC=$(git commit-tree HEAD^^{tree} -p HEAD <msg) &&\n+\tgit format-patch --pretty=mboxrd --stdout -1 $C~1..$C >patch &&\n+\tgit grep -h --no-index -A11 \\\n+\t\t\"^>From could trip up a loose mbox parser\" patch >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n"},{"id":"288383","messageId":"20160605044641.9221-3-e@80x24.org","threadId":"42531","inReplyTo":"20160605044641.9221-1-e@80x24.org","subject":"[PATCH v2 2/3] mailsplit: support unescaping mboxrd messages","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2016-06-05T04:46:40Z","receivedAt":"2016-06-05T04:46:40Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This will allow us to parse the output of --pretty=mboxrd\nand the output of other mboxrd generators.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n Documentation/git-mailsplit.txt |  7 ++++++-\n builtin/mailsplit.c             | 18 ++++++++++++++++++\n t/t5100-mailinfo.sh             | 31 +++++++++++++++++++++++++++++++\n t/t5100/0001mboxrd              |  4 ++++\n t/t5100/0002mboxrd              |  5 +++++\n t/t5100/sample.mboxrd           | 19 +++++++++++++++++++\n 6 files changed, 83 insertions(+), 1 deletion(-)\n create mode 100644 t/t5100/0001mboxrd\n create mode 100644 t/t5100/0002mboxrd\n create mode 100644 t/t5100/sample.mboxrd\n\ndiff --git a/Documentation/git-mailsplit.txt b/Documentation/git-mailsplit.txt\nindex 4d1b871..e3b2a88 100644\n--- a/Documentation/git-mailsplit.txt\n+++ b/Documentation/git-mailsplit.txt\n@@ -8,7 +8,8 @@ git-mailsplit - Simple UNIX mbox splitter program\n SYNOPSIS\n --------\n [verse]\n-'git mailsplit' [-b] [-f<nn>] [-d<prec>] [--keep-cr] -o<directory> [--] [(<mbox>|<Maildir>)...]\n+'git mailsplit' [-b] [-f<nn>] [-d<prec>] [--keep-cr] [--mboxrd]\n+\t\t-o<directory> [--] [(<mbox>|<Maildir>)...]\n \n DESCRIPTION\n -----------\n@@ -47,6 +48,10 @@ OPTIONS\n --keep-cr::\n \tDo not remove `\\r` from lines ending with `\\r\\n`.\n \n+--mboxrd::\n+\tInput is of the \"mboxrd\" format and \"^>+From \" line escaping is\n+\treversed.\n+\n GIT\n ---\n Part of the linkgit:git[1] suite\ndiff --git a/builtin/mailsplit.c b/builtin/mailsplit.c\nindex 4859ede..3068168 100644\n--- a/builtin/mailsplit.c\n+++ b/builtin/mailsplit.c\n@@ -45,6 +45,19 @@ static int is_from_line(const char *line, int len)\n \n static struct strbuf buf = STRBUF_INIT;\n static int keep_cr;\n+static int mboxrd;\n+\n+static int is_gtfrom(const struct strbuf *buf)\n+{\n+\tsize_t min = strlen(\">From \");\n+\tsize_t ngt;\n+\n+\tif (buf->len < min)\n+\t\treturn 0;\n+\n+\tngt = strspn(buf->buf, \">\");\n+\treturn ngt && starts_with(buf->buf + ngt, \"From \");\n+}\n \n /* Called with the first line (potentially partial)\n  * already in buf[] -- normally that should begin with\n@@ -77,6 +90,9 @@ static int split_one(FILE *mbox, const char *name, int allow_bare)\n \t\t\tstrbuf_addch(&buf, '\\n');\n \t\t}\n \n+\t\tif (mboxrd && is_gtfrom(&buf))\n+\t\t\tstrbuf_remove(&buf, 0, 1);\n+\n \t\tif (fwrite(buf.buf, 1, buf.len, output) != buf.len)\n \t\t\tdie_errno(\"cannot write output\");\n \n@@ -271,6 +287,8 @@ int cmd_mailsplit(int argc, const char **argv, const char *prefix)\n \t\t\tkeep_cr = 1;\n \t\t} else if ( arg[1] == 'o' && arg[2] ) {\n \t\t\tdir = arg+2;\n+\t\t} else if (!strcmp(arg, \"--mboxrd\")) {\n+\t\t\tmboxrd = 1;\n \t\t} else if ( arg[1] == '-' && !arg[2] ) {\n \t\t\targp++;\t/* -- marks end of options */\n \t\t\tbreak;\ndiff --git a/t/t5100-mailinfo.sh b/t/t5100-mailinfo.sh\nindex 85b3df5..1a5a546 100755\n--- a/t/t5100-mailinfo.sh\n+++ b/t/t5100-mailinfo.sh\n@@ -111,4 +111,35 @@ test_expect_success 'mailinfo on message with quoted >From' '\n \ttest_cmp \"$TEST_DIRECTORY\"/t5100/quoted-from.expect quoted-from/msg\n '\n \n+test_expect_success 'mailinfo unescapes with --mboxrd' '\n+\tmkdir mboxrd &&\n+\tgit mailsplit -omboxrd --mboxrd \\\n+\t\t\"$TEST_DIRECTORY\"/t5100/sample.mboxrd >last &&\n+\ttest x\"$(cat last)\" = x2 &&\n+\tfor i in 0001 0002\n+\tdo\n+\t\tgit mailinfo mboxrd/msg mboxrd/patch \\\n+\t\t  <mboxrd/$i >mboxrd/out &&\n+\t\ttest_cmp \"$TEST_DIRECTORY\"/t5100/${i}mboxrd mboxrd/msg\n+\tdone &&\n+\tsp=\" \" &&\n+\techo \"From \" >expect &&\n+\techo \"From \" >>expect &&\n+\techo >> expect &&\n+\tcat >sp <<-INPUT_END &&\n+\tFrom mboxrd Mon Sep 17 00:00:00 2001\n+\tFrom: trailing spacer <sp@example.com>\n+\tSubject: [PATCH] a commit with trailing space\n+\n+\tFrom$sp\n+\t>From$sp\n+\n+\tINPUT_END\n+\n+\tgit mailsplit -f2 -omboxrd --mboxrd <sp >last &&\n+\ttest x\"$(cat last)\" = x1 &&\n+\tgit mailinfo mboxrd/msg mboxrd/patch <mboxrd/0003 &&\n+\ttest_cmp expect mboxrd/msg\n+'\n+\n test_done\ndiff --git a/t/t5100/0001mboxrd b/t/t5100/0001mboxrd\nnew file mode 100644\nindex 0000000..494ec55\n--- /dev/null\n+++ b/t/t5100/0001mboxrd\n@@ -0,0 +1,4 @@\n+From the beginning, mbox should have been mboxrd\n+>From escaped\n+From not mangled but this line should have been escaped\n+\ndiff --git a/t/t5100/0002mboxrd b/t/t5100/0002mboxrd\nnew file mode 100644\nindex 0000000..71343d4\n--- /dev/null\n+++ b/t/t5100/0002mboxrd\n@@ -0,0 +1,5 @@\n+ >From unchanged\n+ From also unchanged\n+no trailing space, no escaping necessary and '>' was intended:\n+>From\n+\ndiff --git a/t/t5100/sample.mboxrd b/t/t5100/sample.mboxrd\nnew file mode 100644\nindex 0000000..79ad5ae\n--- /dev/null\n+++ b/t/t5100/sample.mboxrd\n@@ -0,0 +1,19 @@\n+From mboxrd Mon Sep 17 00:00:00 2001\n+From: mboxrd writer <mboxrd@example.com>\n+Date: Fri, 9 Jun 2006 00:44:16 -0700\n+Subject: [PATCH] a commit with escaped From lines\n+\n+>From the beginning, mbox should have been mboxrd\n+>>From escaped\n+From not mangled but this line should have been escaped\n+\n+From mboxrd Mon Sep 17 00:00:00 2001\n+From: mboxrd writer <mboxrd@example.com>\n+Date: Fri, 9 Jun 2006 00:44:16 -0700\n+Subject: [PATCH 2/2] another with fake From lines\n+\n+ >From unchanged\n+ From also unchanged\n+no trailing space, no escaping necessary and '>' was intended:\n+>From\n+\n"},{"id":"288385","messageId":"20160605044641.9221-4-e@80x24.org","threadId":"42531","inReplyTo":"20160605044641.9221-1-e@80x24.org","subject":"[PATCH v2 3/3] am: support --patch-format=mboxrd","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2016-06-05T04:46:41Z","receivedAt":"2016-06-05T04:46:41Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Combined with \"git format-patch --pretty=mboxrd\", this should\nallow us to round-trip commit messages with embedded mbox\n\"From \" lines without corruption.\n\nSigned-off-by: Eric Wong <e@80x24.org>\n---\n Documentation/git-am.txt |  3 ++-\n builtin/am.c             | 14 +++++++++++---\n t/t4150-am.sh            | 20 ++++++++++++++++++++\n 3 files changed, 33 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/git-am.txt b/Documentation/git-am.txt\nindex 13cdd7f..6348c29 100644\n--- a/Documentation/git-am.txt\n+++ b/Documentation/git-am.txt\n@@ -116,7 +116,8 @@ default.   You can use `--no-utf8` to override this.\n \tBy default the command will try to detect the patch format\n \tautomatically. This option allows the user to bypass the automatic\n \tdetection and specify the patch format that the patch(es) should be\n-\tinterpreted as. Valid formats are mbox, stgit, stgit-series and hg.\n+\tinterpreted as. Valid formats are mbox, mboxrd,\n+\tstgit, stgit-series and hg.\n \n -i::\n --interactive::\ndiff --git a/builtin/am.c b/builtin/am.c\nindex 3dfe70b..d5da5fe 100644\n--- a/builtin/am.c\n+++ b/builtin/am.c\n@@ -70,7 +70,8 @@ enum patch_format {\n \tPATCH_FORMAT_MBOX,\n \tPATCH_FORMAT_STGIT,\n \tPATCH_FORMAT_STGIT_SERIES,\n-\tPATCH_FORMAT_HG\n+\tPATCH_FORMAT_HG,\n+\tPATCH_FORMAT_MBOXRD\n };\n \n enum keep_type {\n@@ -712,7 +713,8 @@ done:\n  * Splits out individual email patches from `paths`, where each path is either\n  * a mbox file or a Maildir. Returns 0 on success, -1 on failure.\n  */\n-static int split_mail_mbox(struct am_state *state, const char **paths, int keep_cr)\n+static int split_mail_mbox(struct am_state *state, const char **paths,\n+\t\t\t\tint keep_cr, int mboxrd)\n {\n \tstruct child_process cp = CHILD_PROCESS_INIT;\n \tstruct strbuf last = STRBUF_INIT;\n@@ -724,6 +726,8 @@ static int split_mail_mbox(struct am_state *state, const char **paths, int keep_\n \targv_array_push(&cp.args, \"-b\");\n \tif (keep_cr)\n \t\targv_array_push(&cp.args, \"--keep-cr\");\n+\tif (mboxrd)\n+\t\targv_array_push(&cp.args, \"--mboxrd\");\n \targv_array_push(&cp.args, \"--\");\n \targv_array_pushv(&cp.args, paths);\n \n@@ -965,13 +969,15 @@ static int split_mail(struct am_state *state, enum patch_format patch_format,\n \n \tswitch (patch_format) {\n \tcase PATCH_FORMAT_MBOX:\n-\t\treturn split_mail_mbox(state, paths, keep_cr);\n+\t\treturn split_mail_mbox(state, paths, keep_cr, 0);\n \tcase PATCH_FORMAT_STGIT:\n \t\treturn split_mail_conv(stgit_patch_to_mail, state, paths, keep_cr);\n \tcase PATCH_FORMAT_STGIT_SERIES:\n \t\treturn split_mail_stgit_series(state, paths, keep_cr);\n \tcase PATCH_FORMAT_HG:\n \t\treturn split_mail_conv(hg_patch_to_mail, state, paths, keep_cr);\n+\tcase PATCH_FORMAT_MBOXRD:\n+\t\treturn split_mail_mbox(state, paths, keep_cr, 1);\n \tdefault:\n \t\tdie(\"BUG: invalid patch_format\");\n \t}\n@@ -2201,6 +2207,8 @@ static int parse_opt_patchformat(const struct option *opt, const char *arg, int\n \t\t*opt_value = PATCH_FORMAT_STGIT_SERIES;\n \telse if (!strcmp(arg, \"hg\"))\n \t\t*opt_value = PATCH_FORMAT_HG;\n+\telse if (!strcmp(arg, \"mboxrd\"))\n+\t\t*opt_value = PATCH_FORMAT_MBOXRD;\n \telse\n \t\treturn error(_(\"Invalid value for --patch-format: %s\"), arg);\n \treturn 0;\ndiff --git a/t/t4150-am.sh b/t/t4150-am.sh\nindex b41bd17..9ce9424 100755\n--- a/t/t4150-am.sh\n+++ b/t/t4150-am.sh\n@@ -957,4 +957,24 @@ test_expect_success 'am -s unexpected trailer block' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'am --patch-format=mboxrd handles mboxrd' '\n+\trm -fr .git/rebase-apply &&\n+\tgit checkout -f first &&\n+\techo mboxrd >>file &&\n+\tgit add file &&\n+\tcat >msg <<-\\INPUT_END &&\n+\tmboxrd should escape the body\n+\n+\tFrom could trip up a loose mbox parser\n+\t>From extra escape for reversibility\n+\tINPUT_END\n+\tgit commit -F msg &&\n+\tgit format-patch --pretty=mboxrd --stdout -1 >mboxrd1 &&\n+\tgrep \"^>From could trip up a loose mbox parser\" mboxrd1 &&\n+\tgit checkout -f first &&\n+\tgit am --patch-format=mboxrd mboxrd1 &&\n+\tgit cat-file commit HEAD | tail -n4 >out &&\n+\ttest_cmp msg out\n+'\n+\n test_done\n"},{"id":"288469","messageId":"xmqq7fe2xjii.fsf@gitster.mtv.corp.google.com","threadId":"42531","inReplyTo":"20160605044641.9221-3-e@80x24.org","subject":"Re: [PATCH v2 2/3] mailsplit: support unescaping mboxrd messages","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-06-06T18:24:53Z","receivedAt":"2016-06-06T18:24:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Wong <e@80x24.org> writes:\n\n> This will allow us to parse the output of --pretty=mboxrd\n> and the output of other mboxrd generators.\n>\n> Signed-off-by: Eric Wong <e@80x24.org>\n> ---\n>  Documentation/git-mailsplit.txt |  7 ++++++-\n>  builtin/mailsplit.c             | 18 ++++++++++++++++++\n>  t/t5100-mailinfo.sh             | 31 +++++++++++++++++++++++++++++++\n>  t/t5100/0001mboxrd              |  4 ++++\n>  t/t5100/0002mboxrd              |  5 +++++\n>  t/t5100/sample.mboxrd           | 19 +++++++++++++++++++\n>  6 files changed, 83 insertions(+), 1 deletion(-)\n>  create mode 100644 t/t5100/0001mboxrd\n>  create mode 100644 t/t5100/0002mboxrd\n>  create mode 100644 t/t5100/sample.mboxrd\n>\n> diff --git a/Documentation/git-mailsplit.txt b/Documentation/git-mailsplit.txt\n> index 4d1b871..e3b2a88 100644\n> --- a/Documentation/git-mailsplit.txt\n> +++ b/Documentation/git-mailsplit.txt\n> @@ -8,7 +8,8 @@ git-mailsplit - Simple UNIX mbox splitter program\n>  SYNOPSIS\n>  --------\n>  [verse]\n> -'git mailsplit' [-b] [-f<nn>] [-d<prec>] [--keep-cr] -o<directory> [--] [(<mbox>|<Maildir>)...]\n> +'git mailsplit' [-b] [-f<nn>] [-d<prec>] [--keep-cr] [--mboxrd]\n> +\t\t-o<directory> [--] [(<mbox>|<Maildir>)...]\n>  \n>  DESCRIPTION\n>  -----------\n> @@ -47,6 +48,10 @@ OPTIONS\n>  --keep-cr::\n>  \tDo not remove `\\r` from lines ending with `\\r\\n`.\n>  \n> +--mboxrd::\n> +\tInput is of the \"mboxrd\" format and \"^>+From \" line escaping is\n> +\treversed.\n\nThis just makes me wonder if there is a practical reason why people\nwould not want this always enabled.  I just looked at output from\n\n    $ git log --grep='>>*From '\n\nin the kernel repository, and I saw no cases where the committer\nreally wanted to preserve the leading one or more '>' on that line.\nNo, I didn't go through all of 150+ such commits, but I did check\nthe couple dozen of them from the recent history.\n\nOur history also have 5 instances of them, none of which should have\nhad the leading '>' if the committer were careful.\n\n> diff --git a/t/t5100/sample.mboxrd b/t/t5100/sample.mboxrd\n> new file mode 100644\n> index 0000000..79ad5ae\n> --- /dev/null\n> +++ b/t/t5100/sample.mboxrd\n> @@ -0,0 +1,19 @@\n> +From mboxrd Mon Sep 17 00:00:00 2001\n> +From: mboxrd writer <mboxrd@example.com>\n> +Date: Fri, 9 Jun 2006 00:44:16 -0700\n> +Subject: [PATCH] a commit with escaped From lines\n> +\n> +>From the beginning, mbox should have been mboxrd\n\nIndeed ;-)\n"},{"id":"288492","messageId":"20160606230248.GA15906@dcvr.yhbt.net","threadId":"42531","inReplyTo":"xmqq7fe2xjii.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH v2 2/3] mailsplit: support unescaping mboxrd messages","fromName":"Eric Wong","fromEmail":"e@80x24.org","sentAt":"2016-06-06T23:02:48Z","receivedAt":"2016-06-06T23:02:48Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Junio C Hamano <gitster@pobox.com> wrote:\n> This just makes me wonder if there is a practical reason why people\n> would not want this always enabled.  I just looked at output from\n> \n>     $ git log --grep='>>*From '\n\nMissing '^' ?\n\nAuto-unescaping in mailsplit might throw off people on older\nversions of git if reserialized as mail, though.\nMaybe in a few years, we can consider it.\n\nAuto-escaping on the other hand, I think we start doing in\n--pretty=email by default soon/today.  At least for lines\nmatching the stricter is_from_line() check from mailsplit.\n\n> in the kernel repository, and I saw no cases where the committer\n> really wanted to preserve the leading one or more '>' on that line.\n> No, I didn't go through all of 150+ such commits, but I did check\n> the couple dozen of them from the recent history.\n> \n> Our history also have 5 instances of them, none of which should have\n> had the leading '>' if the committer were careful.\n\nRight, but I'm actually more worried about unescaped /^From /\nbreaking further attempts to split.\n\n\tgit log --grep='^From .*:.*:.* .*'\n\n...finds 45 commits in Linux 4.6.1 which might cause incorrect\nsplits.  We have 5 of those ourselves.\n\nTechnically it is backwards-incompatible, but I would rather\nleave an extra '>' in the commit than break a split.\n\n> > +>From the beginning, mbox should have been mboxrd\n> \n> Indeed ;-)\n\nYes, I'm really wishing we did this 11 years ago :)\n"}]}