{"thread":{"id":"8956","subject":"[RFC] series headers","startedAt":"2007-07-10T06:14:00Z","lastAt":"2007-07-24T20:19:48Z","messageCount":11,"participants":["Daniel Barkalow","Junio C Hamano","Theodore Tso","Johannes Schindelin","Peter Oberndorfer"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"46918","messageId":"Pine.LNX.4.64.0707100126250.6977@iabervon.org","threadId":"8956","inReplyTo":null,"subject":"[RFC] series headers","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2007-07-10T06:14:00Z","receivedAt":"2007-07-10T06:14:00Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"I'd like to be able to get format-patch to produce a [PATCH 0/N] message, \nwith a message that's actually in my repository, plus various goodies \ngenerated either from diffing the ends of the series or by running through \nthe log an extra time to pick up summary information.\n\nThe second best idea I have for this currently is to have a commit at the \nend of the series which specifies which has the same tree as its parent \nand has a message with a line \"Since <sha1 of the first commit of the \nseries>\" and has the text. This goes at the end of the series, because it \ndescribes the state with all of the changes made, which is only a good \ndescription of a commit at the end of the series, not a commit at the \nstart of the series. Making it [PATCH 0/N] is just because it belongs \nfirst in presentation, regardless of whether the other commits are \npresented with recent commits first or last.\n\nThe better idea I just had was to have format-patch notice if the \"until\" \nside is a tag object instead of a commit, and generate a [0/N] with the \ntag message.\n\nAs far as implementing this... would it be sane to make struct \nrev_info.commit_format a callback, so that the code to generate an email \nmessage can be somewhere that's easy to use to generate an email that \nisn't for a commit in the log? I don't *think* git's quite fast enough for \nthe indirect jump to a callback instead of an if tree for an enum will \nactually hurt us.\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"46920","messageId":"7vejjgsq3y.fsf@assigned-by-dhcp.cox.net","threadId":"8956","inReplyTo":"Pine.LNX.4.64.0707100126250.6977@iabervon.org","subject":"Re: [RFC] series headers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-07-10T06:57:21Z","receivedAt":"2007-07-10T06:57:21Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Daniel Barkalow <barkalow@iabervon.org> writes:\n\n> I'd like to be able to get format-patch to produce a [PATCH 0/N] message, \n> with a message that's actually in my repository, plus various goodies \n> generated either from diffing the ends of the series or by running through \n> the log an extra time to pick up summary information.\n\nSo far, so good.\n\n> As far as implementing this... would it be sane to make struct \n> rev_info.commit_format a callback, so that the code to generate an email \n> message can be somewhere that's easy to use to generate an email that \n> isn't for a commit in the log? I don't *think* git's quite fast enough for \n> the indirect jump to a callback instead of an if tree for an enum will \n> actually hurt us.\n\nI suspect that temptation to touch rev_info.commit_format arises\npurely because you are thinking about making 0/N a (perhaps\nfake) commit.  I do not see a point in that.\n\nWhat is the workflow?\n\n $ work work work, commit commit commit, reorder and perfect\n $ git tag end-of-series\n ... in $EDITOR, edit the [0/N] message\n $ git format-patch origin..end-of-series\n ... which notices end-of-series, and perhaps internally runs\n ... $ git-shortlog origin..end-of-series\n ... $ git diff --stat --summary origin..end-of-series\n ... $ git cat-file tag end-of-series\n ... to create 0/N which it did not do so far in\n ... 0000-cover-letter.txt\n $ git-send-email 0*.txt\n\nWould it be so much better than this workflow which would\nprobably not need to touch much of the 'commit formatting\" code\nthat is used for [1/N]..[N/N] messages?\n\n $ work work work, commit commit commit, reorder and perfect\n $ git format-patch --with-cover origin..HEAD\n ... which notices --with-cover, and perhaps does\n ... $ git-shortlog origin..HEAD\n ... $ git diff --stat --summary origin..HEAD\n ... $ echo \"*** BLURB HERE ***\"\n ... to create 0/N which it did not do so far in\n ... 0000-cover-letter.txt\n $ $EDITOR 0000-cover-letter.txt\n $ git-send-email 0*.txt\n"},{"id":"46936","messageId":"20070710132401.GJ2343@thunk.org","threadId":"8956","inReplyTo":"7vejjgsq3y.fsf@assigned-by-dhcp.cox.net","subject":"Re: [RFC] series headers","fromName":"Theodore Tso","fromEmail":"tytso@mit.edu","sentAt":"2007-07-10T13:24:01Z","receivedAt":"2007-07-10T13:24:01Z","isPatch":false,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Mon, Jul 09, 2007 at 11:57:21PM -0700, Junio C Hamano wrote:\n> I suspect that temptation to touch rev_info.commit_format arises\n> purely because you are thinking about making 0/N a (perhaps\n> fake) commit.  I do not see a point in that.\n> \n> What is the workflow?\n\nIn general a patch series goes through multiple cycles of\nimprovements, where people send it out for review/comment, and then it\ngets fixed up, etc. etc.   So you don't want to just do this:\n\n>  $ work work work, commit commit commit, reorder and perfect\n>  $ git format-patch --with-cover origin..HEAD\n>  ... which notices --with-cover, and perhaps does\n>  ... $ git-shortlog origin..HEAD\n>  ... $ git diff --stat --summary origin..HEAD\n>  ... $ echo \"*** BLURB HERE ***\"\n>  ... to create 0/N which it did not do so far in\n>  ... 0000-cover-letter.txt\n>  $ $EDITOR 0000-cover-letter.txt\n>  $ git-send-email 0*.txt\n\nBecause you'll be sending out the 0000-cover-letter.txt multiple\ntimes, refining it (and the patches) as you go along.\n\nSome people will use quilt for this process; others will use guilt or\nstg in a seprate branch.  The way I would probably solve it is by\nmaking the Patch 0/N cover letter be a empty commit with no changes,\nand simply storing the comment in the commit log.  Yes, that means you\nhave to go back and edit the 0/N message after you've finished doing\nyour patch series, but the general work flow will require you to go\nback and clean up patch 3/27 given some comment that Cristoph Hellwig\nmade, so you'll be going back and forth using some tool like guilt or\nstg anyway.  So going back to edit the 0/N cover-letter is not a big deal.\n\nThe one advantage of putting the 0/N cover-letter at the end is that\nit makes it easier to drop it if the patch series ends up being pushed\nvia git, but again, given that the patch series is going to be\nreworked multiple times during its life cycle, reworking it one last\ntime to drop the cover letter doesn't seem like a major issue --- and\nif it is ends up getting applied by the maintainer via e-mail and\ngit-am, the cover letter will get dropped by the maintainer simply not\nincluding it in his mailbox of patches to apply.\n\n\t  \t     \t    \t       \t       - Ted\n"},{"id":"46939","messageId":"Pine.LNX.4.64.0707101424140.4047@racer.site","threadId":"8956","inReplyTo":"7vejjgsq3y.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] Teach the --cover-letter option to format-patch","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-10T13:26:45Z","receivedAt":"2007-07-10T13:26:45Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nYou can now generate a template for the cover letter by calling\n\n\tgit format-patch --cover-letter <...>\n\nIt will fill in the shortlog and diffstat for you.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n\n\tOn Mon, 9 Jul 2007, Junio C Hamano wrote:\n\n\t> Daniel Barkalow <barkalow@iabervon.org> writes:\n\t> \n\t> > I'd like to be able to get format-patch to produce a \n\t> > [PATCH 0/N] message, with a message that's actually in my \n\t> > repository, plus various goodies generated either from diffing \n\t> > the ends of the series or by running through the log an extra \n\t> > time to pick up summary information.\n\t> \n\t>  $ work work work, commit commit commit, reorder and perfect\n\t>  $ git format-patch --with-cover origin..HEAD\n\t>  ... which notices --with-cover, and perhaps does\n\t>  ... $ git-shortlog origin..HEAD\n\t>  ... $ git diff --stat --summary origin..HEAD\n\t>  ... $ echo \"*** BLURB HERE ***\"\n\t>  ... to create 0/N which it did not do so far in\n\t>  ... 0000-cover-letter.txt\n\t>  $ $EDITOR 0000-cover-letter.txt\n\t>  $ git-send-email 0*.txt\n\n\tVoila.\n\n\tBTW format-patch does not complain when there are skipped merges. \n\tIt surprised me, since you do not stand a chance to pipe that to \n\tgit-am successfully...\n\n Documentation/git-format-patch.txt                 |    6 +\n builtin-log.c                                      |  202 ++++++++++++++------\n log-tree.c                                         |    2 +-\n log-tree.h                                         |    1 +\n t/t4013-diff-various.sh                            |    1 +\n ...tch_--stdout_--cover-letter_-n_initial..master^ |  101 ++++++++++\n 6 files changed, 254 insertions(+), 59 deletions(-)\n create mode 100644 t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^\n\ndiff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt\nindex 6cbcf93..aaae083 100644\n--- a/Documentation/git-format-patch.txt\n+++ b/Documentation/git-format-patch.txt\n@@ -16,6 +16,7 @@ SYNOPSIS\n                    [--in-reply-to=Message-Id] [--suffix=.<sfx>]\n                    [--ignore-if-in-upstream]\n                    [--subject-prefix=Subject-Prefix]\n+\t\t   [--cover-letter]\n                    <since>[..<until>]\n \n DESCRIPTION\n@@ -126,6 +127,11 @@ want a filename like `0001-description-of-my-change.patch`, and\n the first letter does not have to be a dot.  Leaving it empty would\n not add any suffix.\n \n+--cover-letter::\n+\tGenerate a cover letter template.  You still have to fill in\n+\ta description, but the shortlog and the diffstat will be\n+\tgenerated for you.\n+\n CONFIGURATION\n -------------\n You can specify extra mail header lines to be added to each\ndiff --git a/builtin-log.c b/builtin-log.c\nindex 13bae31..e2b5e64 100644\n--- a/builtin-log.c\n+++ b/builtin-log.c\n@@ -14,6 +14,7 @@\n #include \"reflog-walk.h\"\n #include \"patch-ids.h\"\n #include \"refs.h\"\n+#include \"run-command.h\"\n \n static int default_show_root = 1;\n static const char *fmt_patch_subject_prefix = \"PATCH\";\n@@ -303,74 +304,77 @@ static int git_format_config(const char *var, const char *value)\n }\n \n \n+static const char *get_oneline_for_filename(struct commit *commit,\n+\t\tint keep_subject)\n+{\n+\tstatic char filename[PATH_MAX];\n+\tchar *sol;\n+\tint len = 0;\n+\n+\tsol = strstr(commit->buffer, \"\\n\\n\");\n+\tif (!sol)\n+\t\tfilename[0] = '\\0';\n+\telse {\n+\t\tint j, space = 0;\n+\n+\t\tsol += 2;\n+\t\t/* strip [PATCH] or [PATCH blabla] */\n+\t\tif (!keep_subject && !prefixcmp(sol, \"[PATCH\")) {\n+\t\t\tchar *eos = strchr(sol + 6, ']');\n+\t\t\tif (eos) {\n+\t\t\t\twhile (isspace(*eos))\n+\t\t\t\t\teos++;\n+\t\t\t\tsol = eos;\n+\t\t\t}\n+\t\t}\n+\n+\t\tfor (j = 0; len < sizeof(filename) &&\n+\t\t\t\tsol[j] && sol[j] != '\\n'; j++) {\n+\t\t\tif (istitlechar(sol[j])) {\n+\t\t\t\tif (space) {\n+\t\t\t\t\tfilename[len++] = '-';\n+\t\t\t\t\tspace = 0;\n+\t\t\t\t}\n+\t\t\t\tfilename[len++] = sol[j];\n+\t\t\t\tif (sol[j] == '.')\n+\t\t\t\t\twhile (sol[j + 1] == '.')\n+\t\t\t\t\t\tj++;\n+\t\t\t} else\n+\t\t\t\tspace = 1;\n+\t\t}\n+\t\twhile (filename[len - 1] == '.'\n+\t\t       || filename[len - 1] == '-')\n+\t\t\tlen--;\n+\t\tfilename[len] = '\\0';\n+\t}\n+\treturn filename;\n+}\n+\n static FILE *realstdout = NULL;\n static const char *output_directory = NULL;\n \n-static int reopen_stdout(struct commit *commit, int nr, int keep_subject,\n-\t\t\t int numbered_files)\n+static int reopen_stdout(const char *oneline, int nr, int total)\n {\n \tchar filename[PATH_MAX];\n-\tchar *sol;\n-\tint len = 0;\n \tint suffix_len = strlen(fmt_patch_suffix) + 1;\n+\tint len = 0;\n \n \tif (output_directory) {\n-\t\tif (strlen(output_directory) >=\n+\t\tlen = snprintf(filename, sizeof(filename), \"%s\",\n+\t\t\t\toutput_directory);\n+\t\tif (len >=\n \t\t    sizeof(filename) - FORMAT_PATCH_NAME_MAX - suffix_len)\n \t\t\treturn error(\"name of output directory is too long\");\n-\t\tstrlcpy(filename, output_directory, sizeof(filename) - suffix_len);\n-\t\tlen = strlen(filename);\n \t\tif (filename[len - 1] != '/')\n \t\t\tfilename[len++] = '/';\n \t}\n \n-\tif (numbered_files) {\n-\t\tsprintf(filename + len, \"%d\", nr);\n-\t\tlen = strlen(filename);\n-\n-\t} else {\n-\t\tsprintf(filename + len, \"%04d\", nr);\n-\t\tlen = strlen(filename);\n-\n-\t\tsol = strstr(commit->buffer, \"\\n\\n\");\n-\t\tif (sol) {\n-\t\t\tint j, space = 1;\n-\n-\t\t\tsol += 2;\n-\t\t\t/* strip [PATCH] or [PATCH blabla] */\n-\t\t\tif (!keep_subject && !prefixcmp(sol, \"[PATCH\")) {\n-\t\t\t\tchar *eos = strchr(sol + 6, ']');\n-\t\t\t\tif (eos) {\n-\t\t\t\t\twhile (isspace(*eos))\n-\t\t\t\t\t\teos++;\n-\t\t\t\t\tsol = eos;\n-\t\t\t\t}\n-\t\t\t}\n-\n-\t\t\tfor (j = 0;\n-\t\t\t     j < FORMAT_PATCH_NAME_MAX - suffix_len - 5 &&\n-\t\t\t\t     len < sizeof(filename) - suffix_len &&\n-\t\t\t\t     sol[j] && sol[j] != '\\n';\n-\t\t\t     j++) {\n-\t\t\t\tif (istitlechar(sol[j])) {\n-\t\t\t\t\tif (space) {\n-\t\t\t\t\t\tfilename[len++] = '-';\n-\t\t\t\t\t\tspace = 0;\n-\t\t\t\t\t}\n-\t\t\t\t\tfilename[len++] = sol[j];\n-\t\t\t\t\tif (sol[j] == '.')\n-\t\t\t\t\t\twhile (sol[j + 1] == '.')\n-\t\t\t\t\t\t\tj++;\n-\t\t\t\t} else\n-\t\t\t\t\tspace = 1;\n-\t\t\t}\n-\t\t\twhile (filename[len - 1] == '.'\n-\t\t\t       || filename[len - 1] == '-')\n-\t\t\t\tlen--;\n-\t\t\tfilename[len] = 0;\n-\t\t}\n-\t\tif (len + suffix_len >= sizeof(filename))\n-\t\t\treturn error(\"Patch pathname too long\");\n+\tif (!filename)\n+\t\tlen += sprintf(filename + len, \"%d\", nr);\n+\telse {\n+\t\tlen += sprintf(filename + len, \"%04d-\", nr);\n+\t\tlen += snprintf(filename + len, sizeof(filename) - len - 1\n+\t\t\t\t- suffix_len, \"%s\", oneline);\n \t\tstrcpy(filename + len, fmt_patch_suffix);\n \t}\n \n@@ -438,6 +442,70 @@ static void gen_message_id(char *dest, unsigned int length, char *base)\n \t\t (int)(email_end - email_start - 1), email_start + 1);\n }\n \n+static void make_cover_letter(struct rev_info *rev,\n+\t\tint use_stdout, int numbered, int numbered_files,\n+\t\tstruct commit *origin, struct commit *head)\n+{\n+\tconst char *committer, *sep;\n+\tconst char *origin_sha1, *head_sha1;\n+\tconst char *argv[7];\n+\n+\tif (rev->commit_format != CMIT_FMT_EMAIL)\n+\t\tdie(\"Cover letter needs email format\");\n+\n+\tif (!use_stdout && reopen_stdout(numbered_files ?\n+\t\t\t\tNULL : \"cover-letter\", 0, rev->total))\n+\t\treturn;\n+\n+\torigin_sha1 = sha1_to_hex(origin ? origin->object.sha1 : null_sha1);\n+\thead_sha1 = sha1_to_hex(head->object.sha1);\n+\n+\tprintf(\"From %s Mon Sep 17 00:00:00 2001\\n\", head_sha1);\n+\tif (rev->message_id)\n+\t\tprintf(\"Message-Id: <%s>\\n\", rev->message_id);\n+\tif (rev->ref_message_id)\n+\t\tprintf(\"In-Reply-To: <%s>\\nReferences: <%s>\\n\",\n+\t\t\t\trev->ref_message_id, rev->ref_message_id);\n+\tcommitter = git_committer_info(0);\n+\tsep = strchr(committer, '>');\n+\tif (sep)\n+\t\tsep++;\n+\telse\n+\t\tsep = committer + strlen(committer);\n+\tprintf(\"From: %.*s\\n\", sep - committer, committer);\n+\tprintf(\"Date:%s\\n\", sep);\n+\tif (rev->total)\n+\t\tprintf(\"Subject: [%s %0*d/%d] *** SUBJECT HERE ***\\n\",\n+\t\t\t\trev->subject_prefix,\n+\t\t\t\tdigits_in_number(rev->total), 0, rev->total);\n+\telse\n+\t\tprintf(\"Subject: *** SUBJECT HERE ***\\n\");\n+\tprintf(\"\\n\\n\");\n+\n+\tprintf(\"*** BLURB HERE ***\\n\\n\");\n+\n+\targv[0] = \"shortlog\";\n+\targv[1] = head_sha1;\n+\targv[2] = \"--not\";\n+\targv[3] = origin_sha1;\n+\targv[4] = NULL;\n+\tfflush(stdout);\n+\trun_command_v_opt(argv, RUN_GIT_CMD);\n+\n+\targv[0] = \"diff\";\n+\targv[1] = \"--stat\";\n+\targv[2] = \"--summary\";\n+\targv[3] = head_sha1;\n+\targv[4] = \"--not\";\n+\targv[5] = origin_sha1;\n+\targv[6] = NULL;\n+\tfflush(stdout);\n+\trun_command_v_opt(argv, RUN_GIT_CMD);\n+\n+\tfflush(stdout);\n+\tprintf(\"\\n\");\n+}\n+\n int cmd_format_patch(int argc, const char **argv, const char *prefix)\n {\n \tstruct commit *commit;\n@@ -452,6 +520,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \tint subject_prefix = 0;\n \tint ignore_if_in_upstream = 0;\n \tint thread = 0;\n+\tint cover_letter = 0;\n+\tstruct commit *origin = NULL, *head = NULL;\n \tconst char *in_reply_to = NULL;\n \tstruct patch_ids ids;\n \tchar *add_signoff = NULL;\n@@ -550,6 +620,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\t\trev.subject_prefix = argv[i] + 17;\n \t\t} else if (!prefixcmp(argv[i], \"--suffix=\"))\n \t\t\tfmt_patch_suffix = argv[i] + 9;\n+\t\telse if (!strcmp(argv[i], \"--cover-letter\"))\n+\t\t\tcover_letter = 1;\n \t\telse\n \t\t\targv[j++] = argv[i];\n \t}\n@@ -594,6 +666,17 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\t * get_revision() would return only the specified count.\n \t\t */\n \t}\n+\tif (cover_letter) {\n+\t\t/* remember the range */\n+\t\tint i;\n+\t\tfor (i = 0; i < rev.pending.nr; i++) {\n+\t\t\tstruct object *o = rev.pending.objects[i].item;\n+\t\t\tif (o->flags & UNINTERESTING)\n+\t\t\t\torigin = (struct commit *)o;\n+\t\t\telse\n+\t\t\t\thead = (struct commit *)o;\n+\t\t}\n+\t}\n \n \tif (ignore_if_in_upstream)\n \t\tget_patch_ids(&rev, &ids, prefix);\n@@ -618,6 +701,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \ttotal = nr;\n \tif (numbered)\n \t\trev.total = total + start_number - 1;\n+\tif (cover_letter)\n+\t\tmake_cover_letter(&rev, use_stdout, numbered, numbered_files,\n+\t\t\t\torigin, head);\n \trev.add_signoff = add_signoff;\n \trev.ref_message_id = in_reply_to;\n \twhile (0 <= --nr) {\n@@ -636,10 +722,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\t\t\t       sha1_to_hex(commit->object.sha1));\n \t\t\trev.message_id = message_id;\n \t\t}\n-\t\tif (!use_stdout)\n-\t\t\tif (reopen_stdout(commit, rev.nr, keep_subject,\n-\t\t\t\t\t  numbered_files))\n-\t\t\t\tdie(\"Failed to create output files\");\n+\t\tif (!use_stdout && reopen_stdout(numbered_files ? NULL :\n+\t\t\t\tget_oneline_for_filename(commit, keep_subject),\n+\t\t\t\trev.nr, rev.total))\n+\t\t\tdie(\"Failed to create output files\");\n \t\tshown = log_tree_commit(&rev, commit);\n \t\tfree(commit->buffer);\n \t\tcommit->buffer = NULL;\ndiff --git a/log-tree.c b/log-tree.c\nindex 8624d5a..5c20c74 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -130,7 +130,7 @@ static unsigned long append_signoff(char **buf_p, unsigned long *buf_sz_p,\n \treturn at;\n }\n \n-static unsigned int digits_in_number(unsigned int number)\n+unsigned int digits_in_number(unsigned int number)\n {\n \tunsigned int i = 10, result = 1;\n \twhile (i <= number) {\ndiff --git a/log-tree.h b/log-tree.h\nindex e82b56a..fbab51f 100644\n--- a/log-tree.h\n+++ b/log-tree.h\n@@ -12,5 +12,6 @@ int log_tree_diff_flush(struct rev_info *);\n int log_tree_commit(struct rev_info *, struct commit *);\n int log_tree_opt_parse(struct rev_info *, const char **, int);\n void show_log(struct rev_info *opt, const char *sep);\n+unsigned int digits_in_number(unsigned int number);\n \n #endif\ndiff --git a/t/t4013-diff-various.sh b/t/t4013-diff-various.sh\nindex 9eec754..6b4d1c5 100755\n--- a/t/t4013-diff-various.sh\n+++ b/t/t4013-diff-various.sh\n@@ -245,6 +245,7 @@ format-patch --inline --stdout initial..master\n format-patch --inline --stdout --subject-prefix=TESTCASE initial..master\n config format.subjectprefix DIFFERENT_PREFIX\n format-patch --inline --stdout initial..master^^\n+format-patch --stdout --cover-letter -n initial..master^\n \n diff --abbrev initial..side\n diff -r initial..side\ndiff --git a/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^\nnew file mode 100644\nindex 0000000..b66a568\n--- /dev/null\n+++ b/t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^\n@@ -0,0 +1,101 @@\n+$ git format-patch --stdout --cover-letter -n initial..master^\n+From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001\n+From: C O Mitter <committer@example.com>\n+Date: 1151280300 +0000\n+Subject: [DIFFERENT_PREFIX 0/2] *** SUBJECT HERE ***\n+\n+\n+*** BLURB HERE ***\n+\n+A U Thor (2):\n+      Second\n+      Third\n+\n+ dir/sub |    4 ++++\n+ file0   |    3 +++\n+ file1   |    3 +++\n+ file2   |    3 ---\n+ 4 files changed, 10 insertions(+), 3 deletions(-)\n+ create mode 100644 file1\n+ delete mode 100644 file2\n+\n+From 1bde4ae5f36c8d9abe3a0fce0c6aab3c4a12fe44 Mon Sep 17 00:00:00 2001\n+From: A U Thor <author@example.com>\n+Date: Mon, 26 Jun 2006 00:01:00 +0000\n+Subject: [DIFFERENT_PREFIX 1/2] Second\n+\n+This is the second commit.\n+---\n+ dir/sub |    2 ++\n+ file0   |    3 +++\n+ file2   |    3 ---\n+ 3 files changed, 5 insertions(+), 3 deletions(-)\n+ delete mode 100644 file2\n+\n+diff --git a/dir/sub b/dir/sub\n+index 35d242b..8422d40 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -1,2 +1,4 @@\n+ A\n+ B\n++C\n++D\n+diff --git a/file0 b/file0\n+index 01e79c3..b414108 100644\n+--- a/file0\n++++ b/file0\n+@@ -1,3 +1,6 @@\n+ 1\n+ 2\n+ 3\n++4\n++5\n++6\n+diff --git a/file2 b/file2\n+deleted file mode 100644\n+index 01e79c3..0000000\n+--- a/file2\n++++ /dev/null\n+@@ -1,3 +0,0 @@\n+-1\n+-2\n+-3\n+-- \n+g-i-t--v-e-r-s-i-o-n\n+\n+\n+From 9a6d4949b6b76956d9d5e26f2791ec2ceff5fdc0 Mon Sep 17 00:00:00 2001\n+From: A U Thor <author@example.com>\n+Date: Mon, 26 Jun 2006 00:02:00 +0000\n+Subject: [DIFFERENT_PREFIX 2/2] Third\n+\n+---\n+ dir/sub |    2 ++\n+ file1   |    3 +++\n+ 2 files changed, 5 insertions(+), 0 deletions(-)\n+ create mode 100644 file1\n+\n+diff --git a/dir/sub b/dir/sub\n+index 8422d40..cead32e 100644\n+--- a/dir/sub\n++++ b/dir/sub\n+@@ -2,3 +2,5 @@ A\n+ B\n+ C\n+ D\n++E\n++F\n+diff --git a/file1 b/file1\n+new file mode 100644\n+index 0000000..b1e6722\n+--- /dev/null\n++++ b/file1\n+@@ -0,0 +1,3 @@\n++A\n++B\n++C\n+-- \n+g-i-t--v-e-r-s-i-o-n\n+\n+$\n-- \n1.5.3.rc0.2782.g192a9-dirty\n"},{"id":"46946","messageId":"Pine.LNX.4.64.0707101452250.4047@racer.site","threadId":"8956","inReplyTo":"20070710132401.GJ2343@thunk.org","subject":"Re: [RFC] series headers","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-10T13:56:48Z","receivedAt":"2007-07-10T13:56:48Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 10 Jul 2007, Theodore Tso wrote:\n\n> In general a patch series goes through multiple cycles of\n> improvements, where people send it out for review/comment, and then it\n> gets fixed up, etc. etc.   So you don't want to just do this:\n> \n> On Mon, Jul 09, 2007 at 11:57:21PM -0700, Junio C Hamano wrote:\n> \n> >  $ work work work, commit commit commit, reorder and perfect\n> >  $ git format-patch --with-cover origin..HEAD\n> >  ... which notices --with-cover, and perhaps does\n> >  ... $ git-shortlog origin..HEAD\n> >  ... $ git diff --stat --summary origin..HEAD\n> >  ... $ echo \"*** BLURB HERE ***\"\n> >  ... to create 0/N which it did not do so far in\n> >  ... 0000-cover-letter.txt\n> >  $ $EDITOR 0000-cover-letter.txt\n> >  $ git-send-email 0*.txt\n> \n> Because you'll be sending out the 0000-cover-letter.txt multiple\n> times, refining it (and the patches) as you go along.\n\nAnd what is so wrong with\n\n[insert before format-patch] $EDITOR my-cover-letter.txt\n\n[replace $EDITOR 0000-cover-letter.txt] $EDITOR my-cover-letter.txt \n\t0000-cover-letter.patch\n\nand paste the changed text?\n\nOf course, you can still hand roll something with a commit.  Probably a \nsquash merge of your patch series.\n\nCiao,\nDscho\n"},{"id":"46954","messageId":"20070710144808.GA27033@thunk.org","threadId":"8956","inReplyTo":"Pine.LNX.4.64.0707101452250.4047@racer.site","subject":"Re: [RFC] series headers","fromName":"Theodore Tso","fromEmail":"tytso@mit.edu","sentAt":"2007-07-10T14:48:09Z","receivedAt":"2007-07-10T14:48:09Z","isPatch":false,"sender":{"key":"tytso@mit.edu","avatar":"https://avatars.githubusercontent.com/u/51416?v=4"},"body":"On Tue, Jul 10, 2007 at 02:56:48PM +0100, Johannes Schindelin wrote:\n> And what is so wrong with\n> \n> [insert before format-patch] $EDITOR my-cover-letter.txt\n> \n> [replace $EDITOR 0000-cover-letter.txt] $EDITOR my-cover-letter.txt \n> \t0000-cover-letter.patch\n> \n> and paste the changed text?\n\nNothing is *wrong* with it per-se, but if you have multiple things\nthat you are working on at the same-time, you might not want to keep\n0000-cover-letter.patch in your working directory.  \n\nThe simplest place to put it is in .git/patches/<branch> while I'm\nworking with it using guilt (or the equivalent place in stgit), and if\nyou include it in the series file then it becomes easier to hack it so\nthat git-format-patches will create the cover letter for you.  (And\nideally, you would be able to use guilt to edit the cover letter using\n\"guilt header -e cover-letter\" but that feature hasn't been added yet;\nshould be simple, though.)\n\nBasically, the issue is of handling the cover letter as a first-class\nobject, as opposed to something whic his manually handled via\ncut-and-paste.  A lot of the tools are actually there already if you\nare using tools like guilt and stgit.  So it's basically making a\nparticular workflow a bit more optimized, that's all.  \n\nThere certainly is nothing *wrong* with manual maintenance of the\ncover-letter file plus cut-and-paste when you want to update it.  Just\nas there's nothing *wrong* with using git-write-tree instead of\ngit-commit.  Just a question of which is more convenient and less\nerror prone.  :-)\n\n\t\t\t\t\t\t- Ted\n"},{"id":"46956","messageId":"Pine.LNX.4.64.0707101617520.4047@racer.site","threadId":"8956","inReplyTo":"20070710144808.GA27033@thunk.org","subject":"Re: [RFC] series headers","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-10T15:23:09Z","receivedAt":"2007-07-10T15:23:09Z","isPatch":false,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 10 Jul 2007, Theodore Tso wrote:\n\n> On Tue, Jul 10, 2007 at 02:56:48PM +0100, Johannes Schindelin wrote:\n> > And what is so wrong with\n> > \n> > [insert before format-patch] $EDITOR my-cover-letter.txt\n> > \n> > [replace $EDITOR 0000-cover-letter.txt] $EDITOR my-cover-letter.txt \n> > \t0000-cover-letter.patch\n> > \n> > and paste the changed text?\n> \n> Nothing is *wrong* with it per-se, but if you have multiple things that \n> you are working on at the same-time, you might not want to keep \n> 0000-cover-letter.patch in your working directory.\n\nAh, but then maybe you want to be able to say\n\n\tgit format-patch --cover-letter=<my-cover-letter> [...]\n\nWhere your cover-letter file looks something like this:\n\n\tMy patch series which will rule the world\n\n\tHere is the body, and I explain what the world should look like,\n\tand that they should accept me as the chosen one president of the\n\tunited geekheads of this world.\n\nIOW the file contents to produce what is produced with my patch would look \nlike this:\n\n\t*** SUBJECT HERE ***\n\n\t*** BLURB HERE ***\nCiao,\nDscho\n"},{"id":"46968","messageId":"Pine.LNX.4.64.0707101300450.6977@iabervon.org","threadId":"8956","inReplyTo":"Pine.LNX.4.64.0707101424140.4047@racer.site","subject":"Re: [PATCH] Teach the --cover-letter option to format-patch","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2007-07-10T17:20:03Z","receivedAt":"2007-07-10T17:20:03Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"I think this is missing the ultra-important \"extra_headers\" stuff, which \nis what makes my messages actually reach the right people. That's why I'd \nlike the code shared for generating headers (except for Subject) for a \nrev_info between the code that does it for patch messages and the code for \nthe cover letter. I think it's also missing making [PATCH 1/N] a reply to \nit if the series is set up as replies.\n\nI like the design, in any case. I want the blurb actually stored in the \nobjects directory somehow, so that I don't have to trawl through my sent \nemail for it when I send the series again for some reason, but that's a \nrelatively straightforward extension to your code. (Read an object with a \nhash and stick the text in instead of the ***...*** parts.)\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"46969","messageId":"Pine.LNX.4.64.0707101819350.4047@racer.site","threadId":"8956","inReplyTo":"Pine.LNX.4.64.0707101300450.6977@iabervon.org","subject":"Re: [PATCH] Teach the --cover-letter option to format-patch","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-07-10T17:20:35Z","receivedAt":"2007-07-10T17:20:35Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 10 Jul 2007, Daniel Barkalow wrote:\n\n> I think this is missing the ultra-important \"extra_headers\" stuff, which \n> is what makes my messages actually reach the right people. That's why \n> I'd like the code shared for generating headers (except for Subject) for \n> a rev_info between the code that does it for patch messages and the code \n> for the cover letter. I think it's also missing making [PATCH 1/N] a \n> reply to it if the series is set up as replies.\n\nAh yes. Both issues should be relatively easy to integrate into my patch.\n\n> I like the design, in any case. I want the blurb actually stored in the \n> objects directory somehow, so that I don't have to trawl through my sent \n> email for it when I send the series again for some reason, but that's a \n> relatively straightforward extension to your code. (Read an object with \n> a hash and stick the text in instead of the ***...*** parts.)\n\nI do not understand. But then, my patch should be a good starting point. \nGo wild.\n\nCiao,\nDscho\n"},{"id":"48509","messageId":"200707242212.27837.kumbayo84@arcor.de","threadId":"8956","inReplyTo":"Pine.LNX.4.64.0707101819350.4047@racer.site","subject":"Re: [PATCH] Teach the --cover-letter option to format-patch","fromName":"Peter Oberndorfer","fromEmail":"kumbayo84@arcor.de","sentAt":"2007-07-24T20:12:27Z","receivedAt":"2007-07-24T20:12:27Z","isPatch":true,"sender":{"key":"kumbayo84@arcor.de","avatar":"https://avatars.githubusercontent.com/u/1041267?v=4"},"body":"On Tuesday 10 July 2007 19:20, Johannes Schindelin wrote:\n> Hi,\n> \n> On Tue, 10 Jul 2007, Daniel Barkalow wrote:\n> \n> > I think this is missing the ultra-important \"extra_headers\" stuff, which \n> > is what makes my messages actually reach the right people. That's why \n> > I'd like the code shared for generating headers (except for Subject) for \n> > a rev_info between the code that does it for patch messages and the code \n> > for the cover letter. I think it's also missing making [PATCH 1/N] a \n> > reply to it if the series is set up as replies.\n> \n> Ah yes. Both issues should be relatively easy to integrate into my patch.\n> \n> > I like the design, in any case. I want the blurb actually stored in the \n> > objects directory somehow, so that I don't have to trawl through my sent \n> > email for it when I send the series again for some reason, but that's a \n> > relatively straightforward extension to your code. (Read an object with \n> > a hash and stick the text in instead of the ***...*** parts.)\n> \n> I do not understand. But then, my patch should be a good starting point. \n> Go wild.\n> \n> Ciao,\n> Dscho\nAnybody working on this?\nSomebody, *cough* convinced me into working on this.\nI already split up the existing patch into logic parts, and will now try to read message / header\nfrom file or a commit.\n\nGreetings Peter\n"},{"id":"48510","messageId":"Pine.LNX.4.64.0707241615170.29679@iabervon.org","threadId":"8956","inReplyTo":"200707242212.27837.kumbayo84@arcor.de","subject":"Re: [PATCH] Teach the --cover-letter option to format-patch","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2007-07-24T20:19:48Z","receivedAt":"2007-07-24T20:19:48Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Tue, 24 Jul 2007, Peter Oberndorfer wrote:\n\n> On Tuesday 10 July 2007 19:20, Johannes Schindelin wrote:\n> > Hi,\n> > \n> > On Tue, 10 Jul 2007, Daniel Barkalow wrote:\n> > \n> > > I think this is missing the ultra-important \"extra_headers\" stuff, which \n> > > is what makes my messages actually reach the right people. That's why \n> > > I'd like the code shared for generating headers (except for Subject) for \n> > > a rev_info between the code that does it for patch messages and the code \n> > > for the cover letter. I think it's also missing making [PATCH 1/N] a \n> > > reply to it if the series is set up as replies.\n> > \n> > Ah yes. Both issues should be relatively easy to integrate into my patch.\n> > \n> > > I like the design, in any case. I want the blurb actually stored in the \n> > > objects directory somehow, so that I don't have to trawl through my sent \n> > > email for it when I send the series again for some reason, but that's a \n> > > relatively straightforward extension to your code. (Read an object with \n> > > a hash and stick the text in instead of the ***...*** parts.)\n> > \n> > I do not understand. But then, my patch should be a good starting point. \n> > Go wild.\n> > \n> > Ciao,\n> > Dscho\n> Anybody working on this?\n> Somebody, *cough* convinced me into working on this.\n> I already split up the existing patch into logic parts, and will now try to read message / header\n> from file or a commit.\n\nLast night, I was thinking about it, but I hadn't actually gotten started. \nIf you do it, I'd suggest using an unsigned tag for the message rather \nthan a commit, since it fits the design for a message in an unsigned tag \n(extra information about the tagged version).\n\n\t-Daniel\n*This .sig left intentionally blank*\n"}]}