{"thread":{"id":"12152","subject":"[PATCH 4/4] Add a --cover-letter option to format-patch","startedAt":"2008-02-17T18:35:54Z","lastAt":"2008-02-18T21:17:37Z","messageCount":7,"participants":["Daniel Barkalow","Junio C Hamano","Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"69016","messageId":"alpine.LNX.1.00.0802171335520.5816@iabervon.org","threadId":"12152","inReplyTo":null,"subject":"[PATCH 4/4] Add a --cover-letter option to format-patch","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2008-02-17T18:35:54Z","receivedAt":"2008-02-17T18:35:54Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"If --cover-letter is provided, generate a cover letter message before\nthe patches, numbered 0.\n\nOriginal patch thanks to Johannes Schindelin\n\nSigned-off-by: Daniel Barkalow <barkalow@iabervon.org>\n---\n Documentation/git-format-patch.txt                 |    6 +\n builtin-log.c                                      |  220 ++++++++++++++-----\n t/t4013-diff-various.sh                            |    1 +\n ...tch_--stdout_--cover-letter_-n_initial..master^ |  101 +++++++++\n 4 files changed, 270 insertions(+), 58 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 651efe6..53e6d2e 100644\n--- a/Documentation/git-format-patch.txt\n+++ b/Documentation/git-format-patch.txt\n@@ -17,6 +17,7 @@ SYNOPSIS\n                    [--in-reply-to=Message-Id] [--suffix=.<sfx>]\n                    [--ignore-if-in-upstream]\n                    [--subject-prefix=Subject-Prefix]\n+                   [--cover-letter]\n \t\t   [ <since> | <revision range> ]\n \n DESCRIPTION\n@@ -135,6 +136,11 @@ include::diff-options.txt[]\n \tallows for useful naming of a patch series, and can be\n \tcombined with the --numbered option.\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 --suffix=.<sfx>::\n \tInstead of using `.patch` as the suffix for generated\n \tfilenames, use specified suffix.  A common alternative is\ndiff --git a/builtin-log.c b/builtin-log.c\nindex 867cc13..bfefb67 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@@ -452,74 +453,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 \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 (!oneline)\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@@ -590,6 +594,74 @@ static void gen_message_id(struct rev_info *info, char *base)\n \tinfo->message_id = strbuf_detach(&buf, NULL);\n }\n \n+static void make_cover_letter(struct rev_info *rev,\n+\t\tint use_stdout, int numbered, int numbered_files,\n+\t\t\t      struct commit *origin, struct commit *head)\n+{\n+\tconst char *committer;\n+\tconst char *origin_sha1, *head_sha1;\n+\tconst char *argv[7];\n+\tconst char *subject_start = NULL;\n+\tconst char *body = \"*** SUBJECT HERE ***\\n\\n\\n*** BLURB HERE ***\\n\";\n+\tconst char *msg;\n+\tconst char *extra_headers = rev->extra_headers;\n+\tstruct strbuf sb;\n+\tconst char *encoding = \"utf-8\";\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+\twrite_email_headers(rev, head_sha1, &subject_start, &extra_headers);\n+\n+\tcommitter = git_committer_info(0);\n+\n+\tmsg = body;\n+\tstrbuf_init(&sb, 0);\n+\tadd_user_info(NULL, CMIT_FMT_EMAIL, &sb, committer, DATE_RFC2822,\n+\t\t      encoding);\n+\tpp_title_line(CMIT_FMT_EMAIL, &msg, &sb, subject_start, extra_headers,\n+\t\t      encoding, 0);\n+\tpp_remainder(CMIT_FMT_EMAIL, &msg, &sb, 0);\n+\tprintf(\"%s\\n\", sb.buf);\n+\n+\tstrbuf_release(&sb);\n+\n+\t/*\n+\t * We can only do diffstat with a unique reference point, and\n+\t * log is a bit tricky, so just skip it.\n+\t */\n+\tif (!origin)\n+\t\treturn;\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 static const char *clean_message_id(const char *msg_id)\n {\n \tchar ch;\n@@ -625,6 +697,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@@ -724,6 +798,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@@ -775,6 +851,25 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\t * get_revision() to do the usual traversal.\n \t\t */\n \t}\n+\tif (cover_letter) {\n+\t\t/* remember the range */\n+\t\tint negative_count = 0;\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\t\tnegative_count++;\n+\t\t\t} else\n+\t\t\t\thead = (struct commit *)o;\n+\t\t}\n+\t\t/* Multiple origins don't work for diffstat. */\n+\t\tif (negative_count > 1)\n+\t\t\torigin = NULL;\n+\t\t/* We can't generate a cover letter without any patches */\n+\t\tif (!head)\n+\t\t\treturn 0;\n+\t}\n \n \tif (ignore_if_in_upstream)\n \t\tget_patch_ids(&rev, &ids, prefix);\n@@ -801,9 +896,18 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\tnumbered = 1;\n \tif (numbered)\n \t\trev.total = total + start_number - 1;\n-\trev.add_signoff = add_signoff;\n \tif (in_reply_to)\n \t\trev.ref_message_id = clean_message_id(in_reply_to);\n+\tif (cover_letter) {\n+\t\tif (thread) {\n+\t\t\tgen_message_id(&rev, \"cover\");\n+\t\t}\n+\t\tmake_cover_letter(&rev, use_stdout, numbered, numbered_files,\n+\t\t\t\t  origin, head);\n+\t\ttotal++;\n+\t\tstart_number--;\n+\t}\n+\trev.add_signoff = add_signoff;\n \twhile (0 <= --nr) {\n \t\tint shown;\n \t\tcommit = list[nr];\n@@ -818,10 +922,10 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\t\t}\n \t\t\tgen_message_id(&rev, sha1_to_hex(commit->object.sha1));\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/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..311e207\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: Mon, 26 Jun 2006 00:05:00 +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.4.1.1350.g2b9ee\n"},{"id":"69082","messageId":"7v4pc7udux.fsf@gitster.siamese.dyndns.org","threadId":"12152","inReplyTo":"alpine.LNX.1.00.0802171335520.5816@iabervon.org","subject":"Re: [PATCH 4/4] Add a --cover-letter option to format-patch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-02-18T03:45:26Z","receivedAt":"2008-02-18T03:45:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Daniel Barkalow <barkalow@iabervon.org> writes:\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\nPlease make it a habit to always append \"--\" disambiguator for\nsuch command lines generated internally.  In this case you are\nnot usinging short and common name like \"master\" or \"HEAD\" but\n40-letter-long hex string, so it is much less likely to get hit\nby the \"ambiguous rev vs file\" rule, but even then it is still\npossible that a work tree happens to have a file with the same\nname.\n\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: Mon, 26 Jun 2006 00:05:00 +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\nThis probably falls within the \"personal taste\" category, but\nI'd rather not to see two extra blank lines between Subject: and\nBLURB HERE.\n"},{"id":"69138","messageId":"alpine.LSU.1.00.0802181245270.30505@racer.site","threadId":"12152","inReplyTo":"alpine.LNX.1.00.0802171335520.5816@iabervon.org","subject":"Re: [PATCH 4/4] Add a --cover-letter option to format-patch","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2008-02-18T13:19:21Z","receivedAt":"2008-02-18T13:19:21Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 17 Feb 2008, Daniel Barkalow wrote:\n\n> diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt\n> index 651efe6..53e6d2e 100644\n> --- a/Documentation/git-format-patch.txt\n> +++ b/Documentation/git-format-patch.txt\n> @@ -17,6 +17,7 @@ SYNOPSIS\n>                     [--in-reply-to=Message-Id] [--suffix=.<sfx>]\n>                     [--ignore-if-in-upstream]\n>                     [--subject-prefix=Subject-Prefix]\n> +                   [--cover-letter]\n>  \t\t   [ <since> | <revision range> ]\n\nSince you are already there, and it is really a small change, why not fix \nthe whitespace?\n\n> diff --git a/builtin-log.c b/builtin-log.c\n> index 867cc13..bfefb67 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> @@ -452,74 +453,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\nWhere has the FORMAT_PATCH_NAME_MAX handling gone?  See c06d2daa(Limit \nfilename for format-patch)...\n\nBTW it is not only because format-patch would fail.  The maximum length \nwas chosen such that it does not clutter the window when ls'ing the files.\n\n> @@ -590,6 +594,74 @@ static void gen_message_id(struct rev_info *info, char *base)\n>  \tinfo->message_id = strbuf_detach(&buf, NULL);\n>  }\n>  \n> +static void make_cover_letter(struct rev_info *rev,\n> +\t\tint use_stdout, int numbered, int numbered_files,\n> +\t\t\t      struct commit *origin, struct commit *head)\n> +{\n> +\tconst char *committer;\n> +\tconst char *origin_sha1, *head_sha1;\n> +\tconst char *argv[7];\n> +\tconst char *subject_start = NULL;\n> +\tconst char *body = \"*** SUBJECT HERE ***\\n\\n\\n*** BLURB HERE ***\\n\";\n> +\tconst char *msg;\n> +\tconst char *extra_headers = rev->extra_headers;\n> +\tstruct strbuf sb;\n> +\tconst char *encoding = \"utf-8\";\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> +\twrite_email_headers(rev, head_sha1, &subject_start, &extra_headers);\n> +\n> +\tcommitter = git_committer_info(0);\n> +\n> +\tmsg = body;\n> +\tstrbuf_init(&sb, 0);\n> +\tadd_user_info(NULL, CMIT_FMT_EMAIL, &sb, committer, DATE_RFC2822,\n> +\t\t      encoding);\n> +\tpp_title_line(CMIT_FMT_EMAIL, &msg, &sb, subject_start, extra_headers,\n> +\t\t      encoding, 0);\n> +\tpp_remainder(CMIT_FMT_EMAIL, &msg, &sb, 0);\n> +\tprintf(\"%s\\n\", sb.buf);\n> +\n> +\tstrbuf_release(&sb);\n> +\n> +\t/*\n> +\t * We can only do diffstat with a unique reference point, and\n> +\t * log is a bit tricky, so just skip it.\n> +\t */\n> +\tif (!origin)\n> +\t\treturn;\n> +\n> +\targv[0] = \"shortlog\";\n> +\targv[1] = head_sha1;\n> +\targv[2] = \"--not\";\n> +\targv[3] = origin_sha1;\n\nShould this not output a complete shortlog, if the user said\n\n\tgit format-patch --root --cover-letter HEAD\n\nHmm?\n\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\nLikewise.\n\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>  static const char *clean_message_id(const char *msg_id)\n>  {\n>  \tchar ch;\n> @@ -775,6 +851,25 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n>  \t\t * get_revision() to do the usual traversal.\n>  \t\t */\n>  \t}\n> +\tif (cover_letter) {\n> +\t\t/* remember the range */\n> +\t\tint negative_count = 0;\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\t\tnegative_count++;\n> +\t\t\t} else\n> +\t\t\t\thead = (struct commit *)o;\n> +\t\t}\n> +\t\t/* Multiple origins don't work for diffstat. */\n> +\t\tif (negative_count > 1)\n> +\t\t\torigin = NULL;\n\nOh, and here it gets interesting.  If you say\n\n\tgit format-patch --cover-letter ^commit1 ^commit2 HEAD\n\nthen origin will be set to NULL, and in the diffstat, instead of showing \n_no_ diffstat, you show the same as if no negative ref was given (which \n_should_ show a diff against the empty tree, but shows nothing currently).\n\nSo I suggest changing \"origin\" to a commit_list, and have cover-letter \n_not_ output a diffstat if more than one commits were given.\n\nOr as many diffstats.  Whatever.\n\n> +\t\t/* We can't generate a cover letter without any patches */\n> +\t\tif (!head)\n> +\t\t\treturn 0;\n\nShould this not\n\n\t\t\treturn error(\"You want a cover letter for what,\"\n\t\t\t\t\"exactly?\");\n\nHmm?\n\n> @@ -801,9 +896,18 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n>  \t\tnumbered = 1;\n>  \tif (numbered)\n>  \t\trev.total = total + start_number - 1;\n> -\trev.add_signoff = add_signoff;\n>  \tif (in_reply_to)\n>  \t\trev.ref_message_id = clean_message_id(in_reply_to);\n> +\tif (cover_letter) {\n> +\t\tif (thread) {\n> +\t\t\tgen_message_id(&rev, \"cover\");\n> +\t\t}\n\nThese curly brackets are sure distracting.\n\n> +\t\tmake_cover_letter(&rev, use_stdout, numbered, numbered_files,\n> +\t\t\t\t  origin, head);\n> +\t\ttotal++;\n> +\t\tstart_number--;\n> +\t}\n> +\trev.add_signoff = add_signoff;\n\nWhy not sign off the cover letter, too?\n\nBTW I had to chew over the thread handling quite a few minutes... maybe \nyou want to add a test for --cover-letter --thread, just to make sure it \ndoes not get broken (and of course, to prove that it works with your \npatches).\n\nThanks,\nDscho\n"},{"id":"69172","messageId":"alpine.LNX.1.00.0802181203080.5816@iabervon.org","threadId":"12152","inReplyTo":"7v4pc7udux.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 4/4] Add a --cover-letter option to format-patch","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2008-02-18T17:15:55Z","receivedAt":"2008-02-18T17:15:55Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Sun, 17 Feb 2008, Junio C Hamano wrote:\n\n> Daniel Barkalow <barkalow@iabervon.org> writes:\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> Please make it a habit to always append \"--\" disambiguator for\n> such command lines generated internally.  In this case you are\n> not usinging short and common name like \"master\" or \"HEAD\" but\n> 40-letter-long hex string, so it is much less likely to get hit\n> by the \"ambiguous rev vs file\" rule, but even then it is still\n> possible that a work tree happens to have a file with the same\n> name.\n\nSure.\n\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: Mon, 26 Jun 2006 00:05:00 +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> \n> This probably falls within the \"personal taste\" category, but\n> I'd rather not to see two extra blank lines between Subject: and\n> BLURB HERE.\n\nThe file is ugly with the double blank line, but I like it for what I \nthink is the normal case, where you import the series into your mail \nreader, edit the cover letter there (where it appears as a message with \nsome space devoted to the blurb by virtue of starting with now one blank \nline), and then send. In that context, I think it's nicer.\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"69187","messageId":"alpine.LNX.1.00.0802181254060.5816@iabervon.org","threadId":"12152","inReplyTo":"alpine.LSU.1.00.0802181245270.30505@racer.site","subject":"Re: [PATCH 4/4] Add a --cover-letter option to format-patch","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2008-02-18T18:54:36Z","receivedAt":"2008-02-18T18:54:36Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Mon, 18 Feb 2008, Johannes Schindelin wrote:\n\n> Hi,\n> \n> On Sun, 17 Feb 2008, Daniel Barkalow wrote:\n> \n> > diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt\n> > index 651efe6..53e6d2e 100644\n> > --- a/Documentation/git-format-patch.txt\n> > +++ b/Documentation/git-format-patch.txt\n> > @@ -17,6 +17,7 @@ SYNOPSIS\n> >                     [--in-reply-to=Message-Id] [--suffix=.<sfx>]\n> >                     [--ignore-if-in-upstream]\n> >                     [--subject-prefix=Subject-Prefix]\n> > +                   [--cover-letter]\n> >  \t\t   [ <since> | <revision range> ]\n> \n> Since you are already there, and it is really a small change, why not fix \n> the whitespace?\n\nWhat *is* the correct whitespace for alignment in documentation?\n\n> > diff --git a/builtin-log.c b/builtin-log.c\n> > index 867cc13..bfefb67 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> > @@ -452,74 +453,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> Where has the FORMAT_PATCH_NAME_MAX handling gone?  See c06d2daa(Limit \n> filename for format-patch)...\n\nWow, beats me. I'd have thought I'd have gotten some conflicts while \nrebasing.\n\nAnyway, fixed, and I'll add a test for this case.\n\n> > @@ -590,6 +594,74 @@ static void gen_message_id(struct rev_info *info, char *base)\n> >  \tinfo->message_id = strbuf_detach(&buf, NULL);\n> >  }\n> >  \n> > +static void make_cover_letter(struct rev_info *rev,\n> > +\t\tint use_stdout, int numbered, int numbered_files,\n> > +\t\t\t      struct commit *origin, struct commit *head)\n> > +{\n> > +\tconst char *committer;\n> > +\tconst char *origin_sha1, *head_sha1;\n> > +\tconst char *argv[7];\n> > +\tconst char *subject_start = NULL;\n> > +\tconst char *body = \"*** SUBJECT HERE ***\\n\\n\\n*** BLURB HERE ***\\n\";\n> > +\tconst char *msg;\n> > +\tconst char *extra_headers = rev->extra_headers;\n> > +\tstruct strbuf sb;\n> > +\tconst char *encoding = \"utf-8\";\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> > +\twrite_email_headers(rev, head_sha1, &subject_start, &extra_headers);\n> > +\n> > +\tcommitter = git_committer_info(0);\n> > +\n> > +\tmsg = body;\n> > +\tstrbuf_init(&sb, 0);\n> > +\tadd_user_info(NULL, CMIT_FMT_EMAIL, &sb, committer, DATE_RFC2822,\n> > +\t\t      encoding);\n> > +\tpp_title_line(CMIT_FMT_EMAIL, &msg, &sb, subject_start, extra_headers,\n> > +\t\t      encoding, 0);\n> > +\tpp_remainder(CMIT_FMT_EMAIL, &msg, &sb, 0);\n> > +\tprintf(\"%s\\n\", sb.buf);\n> > +\n> > +\tstrbuf_release(&sb);\n> > +\n> > +\t/*\n> > +\t * We can only do diffstat with a unique reference point, and\n> > +\t * log is a bit tricky, so just skip it.\n> > +\t */\n> > +\tif (!origin)\n> > +\t\treturn;\n> > +\n> > +\targv[0] = \"shortlog\";\n> > +\targv[1] = head_sha1;\n> > +\targv[2] = \"--not\";\n> > +\targv[3] = origin_sha1;\n> \n> Should this not output a complete shortlog, if the user said\n> \n> \tgit format-patch --root --cover-letter HEAD\n> \n> Hmm?\n\nIt should, but that's in the \"tricky\" category. For future work, I want to \nmake it possible to have the log mechanism able to output the same batch \nof commits twice with different settings, so that the cover letter's short \nlog will be an exact match for the contents of the series no matter what, \nbut that's a lot more work and not needed for the common case, which I'd \nlike to get in first.\n\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> \n> Likewise.\n\nHere, we really want to be able to ask the log-output stuff if we have \nexactly one non-included parent of included commits, which is what we \nshould diff against. In any case, again depends on being able to ask for \nthe right info from the library in order to do more than just the easy \ncase without reimplementing a lot or having a mess of special cases.\n\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> >  static const char *clean_message_id(const char *msg_id)\n> >  {\n> >  \tchar ch;\n> > @@ -775,6 +851,25 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n> >  \t\t * get_revision() to do the usual traversal.\n> >  \t\t */\n> >  \t}\n> > +\tif (cover_letter) {\n> > +\t\t/* remember the range */\n> > +\t\tint negative_count = 0;\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\t\tnegative_count++;\n> > +\t\t\t} else\n> > +\t\t\t\thead = (struct commit *)o;\n> > +\t\t}\n> > +\t\t/* Multiple origins don't work for diffstat. */\n> > +\t\tif (negative_count > 1)\n> > +\t\t\torigin = NULL;\n> \n> Oh, and here it gets interesting.  If you say\n> \n> \tgit format-patch --cover-letter ^commit1 ^commit2 HEAD\n> \n> then origin will be set to NULL, and in the diffstat, instead of showing \n> _no_ diffstat, you show the same as if no negative ref was given (which \n> _should_ show a diff against the empty tree, but shows nothing currently).\n>\n> So I suggest changing \"origin\" to a commit_list, and have cover-letter \n> _not_ output a diffstat if more than one commits were given.\n> \n> Or as many diffstats.  Whatever.\n\nI think it's better for now to leave the cover letter bare in all of the \ncomplicated cases, and add it when the core code can provide more info.\n\n> > +\t\t/* We can't generate a cover letter without any patches */\n> > +\t\tif (!head)\n> > +\t\t\treturn 0;\n> \n> Should this not\n> \n> \t\t\treturn error(\"You want a cover letter for what,\"\n> \t\t\t\t\"exactly?\");\n> \n> Hmm?\n\nI'm not sure. I decided to use the rule that, if there's nothing to \nformat, you get nothing with no error, which is true before this series. \nBut I think I'd rather get an error message if there's nothing to do. In \nany case, I don't think the result for no commits should depend on the \ncover letter option, in any case; the fact that these situations differ on \nwhether the result is technically what you asked for or not isn't that \nsignificant.\n\n> > @@ -801,9 +896,18 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n> >  \t\tnumbered = 1;\n> >  \tif (numbered)\n> >  \t\trev.total = total + start_number - 1;\n> > -\trev.add_signoff = add_signoff;\n> >  \tif (in_reply_to)\n> >  \t\trev.ref_message_id = clean_message_id(in_reply_to);\n> > +\tif (cover_letter) {\n> > +\t\tif (thread) {\n> > +\t\t\tgen_message_id(&rev, \"cover\");\n> > +\t\t}\n> \n> These curly brackets are sure distracting.\n\nYup, fixed.\n\n> > +\t\tmake_cover_letter(&rev, use_stdout, numbered, numbered_files,\n> > +\t\t\t\t  origin, head);\n> > +\t\ttotal++;\n> > +\t\tstart_number--;\n> > +\t}\n> > +\trev.add_signoff = add_signoff;\n> \n> Why not sign off the cover letter, too?\n\nI think cover letters aren't normally signed off, since they don't contain \nany content that goes into the history.\n\n> BTW I had to chew over the thread handling quite a few minutes... maybe \n> you want to add a test for --cover-letter --thread, just to make sure it \n> does not get broken (and of course, to prove that it works with your \n> patches).\n\nYeah, I probably want a comment explaining it, too, since I just chewed \nover it myself for a few minutes. Don't forget --in-reply-to=, which also \nworks right.\n\nActually, I guess it's a bit odd that --thread causes all of your messages \nto get Message-Id headers, of which at most one is referenced, while not \nhaving --thread means that none of them have IDs, even if they reference \nsome other message by way of --in-reply-to=. I suppose that's because we \nmight want to support having each message be a reply to the previous, \nwhich is not a style any of us like (I think), but some people somewhere \nlike it, IIRC.\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"69211","messageId":"7vejbanf8l.fsf@gitster.siamese.dyndns.org","threadId":"12152","inReplyTo":"alpine.LNX.1.00.0802181254060.5816@iabervon.org","subject":"Re: [PATCH 4/4] Add a --cover-letter option to format-patch","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2008-02-18T21:09:46Z","receivedAt":"2008-02-18T21:09:46Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Daniel Barkalow <barkalow@iabervon.org> writes:\n\n>> > diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt\n>> > index 651efe6..53e6d2e 100644\n>> > --- a/Documentation/git-format-patch.txt\n>> > +++ b/Documentation/git-format-patch.txt\n>> > @@ -17,6 +17,7 @@ SYNOPSIS\n>> >                     [--in-reply-to=Message-Id] [--suffix=.<sfx>]\n>> >                     [--ignore-if-in-upstream]\n>> >                     [--subject-prefix=Subject-Prefix]\n>> > +                   [--cover-letter]\n>> >  \t\t   [ <since> | <revision range> ]\n>> \n>> Since you are already there, and it is really a small change, why not fix \n>> the whitespace?\n>\n> What *is* the correct whitespace for alignment in documentation?\n\nThe last time I checked, AsciiDoc output did not change before\nand after running \"expand\" and then \"unexpand\" in all *.txt\nfiles in Documentation/ directory, so if it is indenting to\nmultiple of 8, HT is fine.\n\nDon't we have Documentation/.gitattributes that says indentation\nto 8*N-th column must be done with N HTs these days?\n\n>> Why not sign off the cover letter, too?\n>\n> I think cover letters aren't normally signed off, since they don't contain \n> any content that goes into the history.\n\nRight.  They do not contain any content that needs DCO.\n"},{"id":"69212","messageId":"alpine.LNX.1.00.0802181616530.5816@iabervon.org","threadId":"12152","inReplyTo":"7vejbanf8l.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 4/4] Add a --cover-letter option to format-patch","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2008-02-18T21:17:37Z","receivedAt":"2008-02-18T21:17:37Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Mon, 18 Feb 2008, Junio C Hamano wrote:\n\n> Daniel Barkalow <barkalow@iabervon.org> writes:\n> \n> >> > diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt\n> >> > index 651efe6..53e6d2e 100644\n> >> > --- a/Documentation/git-format-patch.txt\n> >> > +++ b/Documentation/git-format-patch.txt\n> >> > @@ -17,6 +17,7 @@ SYNOPSIS\n> >> >                     [--in-reply-to=Message-Id] [--suffix=.<sfx>]\n> >> >                     [--ignore-if-in-upstream]\n> >> >                     [--subject-prefix=Subject-Prefix]\n> >> > +                   [--cover-letter]\n> >> >  \t\t   [ <since> | <revision range> ]\n> >> \n> >> Since you are already there, and it is really a small change, why not fix \n> >> the whitespace?\n> >\n> > What *is* the correct whitespace for alignment in documentation?\n> \n> The last time I checked, AsciiDoc output did not change before\n> and after running \"expand\" and then \"unexpand\" in all *.txt\n> files in Documentation/ directory, so if it is indenting to\n> multiple of 8, HT is fine.\n> \n> Don't we have Documentation/.gitattributes that says indentation\n> to 8*N-th column must be done with N HTs these days?\n\nAh, yes, that's right; I'll fix that block.\n\n\t-Daniel\n*This .sig left intentionally blank*\n"}]}