{"thread":{"id":"17795","subject":"[PATCH] bash completion: offer more options for gitk","startedAt":"2009-02-14T19:54:30Z","lastAt":"2009-02-22T16:49:45Z","messageCount":26,"participants":["Thomas Rast","Junio C Hamano","Santi Béjar","Jay Soffian","Jakub Narebski","Shawn O. Pearce","Daniel Barkalow"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"104676","messageId":"1234641270-14342-1-git-send-email-trast@student.ethz.ch","threadId":"17795","inReplyTo":null,"subject":"[PATCH] bash completion: offer more options for gitk","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-14T19:54:30Z","receivedAt":"2009-02-14T19:54:30Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Add some more git-log options to the gitk completion.  Not all of them\nmake sense, unfortunately.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nI was simply too lazy to keep typing --simplify-by-decoration.\n\nI made two passes over the git-log manpage and simply selected all\noptions that seemed to make sense, _seemed_ to work, and that didn't\nmangle the history view in horrible ways (such as disconnecting it\ninto little pieces).  It does handle --left-right correctly, very\nnice!\n\n\n contrib/completion/git-completion.bash |   10 +++++++++-\n 1 files changed, 9 insertions(+), 1 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex a7a10c0..cedca6d 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1808,7 +1808,15 @@ _gitk ()\n \tfi\n \tcase \"$cur\" in\n \t--*)\n-\t\t__gitcomp \"--not --all $merge\"\n+\t\t__gitcomp \"\n+\t\t\t--not --all $merge\n+\t\t\t--branches --tags --remotes\n+\t\t\t--first-parent\n+\t\t\t--dense --sparse --full-history\n+\t\t\t--simplify-merges --simplify-by-decoration\n+\t\t\t--since= --after= --until= --before=\n+\t\t\t--left-right\n+\t\t\t\"\n \t\treturn\n \t\t;;\n \tesac\n-- \n1.6.2.rc0.293.g947001\n"},{"id":"104752","messageId":"7vfxigniws.fsf@gitster.siamese.dyndns.org","threadId":"17795","inReplyTo":"1234641270-14342-1-git-send-email-trast@student.ethz.ch","subject":"Re: [PATCH] bash completion: offer more options for gitk","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-15T09:33:55Z","receivedAt":"2009-02-15T09:33:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> writes:\n\n> Add some more git-log options to the gitk completion.  Not all of them\n> make sense, unfortunately.\n>\n> Signed-off-by: Thomas Rast <trast@student.ethz.ch>\n> ---\n>\n> I was simply too lazy to keep typing --simplify-by-decoration.\n>\n> I made two passes over the git-log manpage and simply selected all\n> options that seemed to make sense, _seemed_ to work, and that didn't\n> mangle the history view in horrible ways (such as disconnecting it\n> into little pieces).  It does handle --left-right correctly, very\n> nice!\n\nThe --left-right support in gitk was done in tandem with the low-level\nsupport.\n\n> +\t\t__gitcomp \"\n> +\t\t\t--not --all $merge\n> +\t\t\t--branches --tags --remotes\n> +\t\t\t--first-parent\n> +\t\t\t--dense --sparse --full-history\n> +\t\t\t--simplify-merges --simplify-by-decoration\n> +\t\t\t--since= --after= --until= --before=\n> +\t\t\t--left-right\n> +\t\t\t\"\n\nMany options you add here are useful for git-log and not present in its\ncompletion, but as you point out not all git-log options necessarily make\nsense for gitk.  I think it would make sense to introduce an extra\nvariable $__git_log_basic_options that holds the basic ones that can be in\nboth, and add the ones that are specific to gitk or git-log in their own\ncompletion functions.  I suspect gitk's addition will be nil, while\ngit-log would add --graph, --walk-reflogs and --no-merges to the basic\nset.\n\n>  \t\treturn\n>  \t\t;;\n>  \tesac\n> -- \n> 1.6.2.rc0.293.g947001\n"},{"id":"104753","messageId":"adf1fd3d0902150156w67a16e6fp3c946446c5ae2bfd@mail.gmail.com","threadId":"17795","inReplyTo":"7vfxigniws.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] bash completion: offer more options for gitk","fromName":"Santi Béjar","fromEmail":"santi@agolina.net","sentAt":"2009-02-15T09:56:01Z","receivedAt":"2009-02-15T09:56:01Z","isPatch":true,"sender":{"key":"santi@agolina.net","avatar":null},"body":"2009/2/15 Junio C Hamano <gitster@pobox.com>:\n> Many options you add here are useful for git-log and not present in its\n> completion, but as you point out not all git-log options necessarily make\n> sense for gitk.  I think it would make sense to introduce an extra\n> variable $__git_log_basic_options that holds the basic ones that can be in\n> both, and add the ones that are specific to gitk or git-log in their own\n> completion functions.  I suspect gitk's addition will be nil, while\n> git-log would add --graph, --walk-reflogs and --no-merges to the basic\n> set.\n\nI sometimes use the --no-merges with gitk, normally within a range\n(the last 'next' update or so).\n\nSanti\n"},{"id":"104965","messageId":"cover.1234801852.git.trast@student.ethz.ch","threadId":"17795","inReplyTo":"adf1fd3d0902150156w67a16e6fp3c946446c5ae2bfd@mail.gmail.com","subject":"[PATCH v2 0/2] bash completion: more options for gitk/log/shortlog","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-16T16:34:55Z","receivedAt":"2009-02-16T16:34:55Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Santi BÃ©jar wrote:\n> 2009/2/15 Junio C Hamano <gitster@pobox.com>:\n> > Many options you add here are useful for git-log and not present in its\n> > completion, but as you point out not all git-log options necessarily make\n> > sense for gitk.  I think it would make sense to introduce an extra\n> > variable $__git_log_basic_options that holds the basic ones that can be in\n> > both, and add the ones that are specific to gitk or git-log in their own\n> > completion functions.  I suspect gitk's addition will be nil, while\n> > git-log would add --graph, --walk-reflogs and --no-merges to the basic\n> > set.\n\nRight.  Somehow git patches have a tendency to grow in scope; while I\nwas trying to refactor them in good ways, I couldn't help notice that\nshortlog falls in the same category.\n\n(Probably there's another log-like command that I missed?)\n\n> I sometimes use the --no-merges with gitk, normally within a range\n> (the last 'next' update or so).\n\nFor me that falls in the \"mangles history in horrible ways\" category,\nbut since you use it, I put it in.\n\n2/2 is new; I figured since gitk has this bit of code already, why not\nhave git-log do it the same way?\n\n\nThomas Rast (2):\n  bash completion: refactor common log, shortlog and gitk options\n  bash completion: only show 'log --merge' if merging\n\n contrib/completion/git-completion.bash |   56 ++++++++++++++++++++++---------\n 1 files changed, 40 insertions(+), 16 deletions(-)\n"},{"id":"104967","messageId":"c1564dd75592c6e4c3ce97c6187eedbe03d03bc7.1234801852.git.trast@student.ethz.ch","threadId":"17795","inReplyTo":"adf1fd3d0902150156w67a16e6fp3c946446c5ae2bfd@mail.gmail.com","subject":"[PATCH v2 1/2] bash completion: refactor common log, shortlog and gitk options","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-16T16:34:56Z","receivedAt":"2009-02-16T16:34:56Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Refactor options that are useful for more than one of them into a\nvariable used by the relevant completions.  This has the effect of\nadding the following options to git-log:\n\n  --branches --tags --remotes --first-parent --dense --sparse\n  --simplify-merges --simplify-by-decoration --first-parent\n  --no-merges\n\nThe following to git-shortlog:\n\n  --branches --tags --remotes --first-parent\n\nAnd the following to gitk:\n\n  --branches --tags --remotes --first-parent --no-merges --max-count=\n  --max-age= --since= --after= --min-age= --until= --before= --dense\n  --sparse --full-history --simplify-merges --simplify-by-decoration\n  --left-right\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n contrib/completion/git-completion.bash |   49 ++++++++++++++++++++++----------\n 1 files changed, 34 insertions(+), 15 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 412d2c0..a5b3bf3 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -975,6 +975,27 @@ _git_ls_tree ()\n \t__git_complete_file\n }\n \n+# Options that go well for log, shortlog and gitk\n+__git_log_common_options=\"\n+\t--not --all\n+\t--branches --tags --remotes\n+\t--first-parent --no-merges\n+\t--max-count=\n+\t--max-age= --since= --after=\n+\t--min-age= --until= --before=\n+\"\n+# Options that go well for log and gitk (not shortlog)\n+__git_log_gitk_options=\"\n+\t--dense --sparse --full-history\n+\t--simplify-merges --simplify-by-decoration\n+\t--left-right\n+\"\n+# Options that go well for log and shortlog (not gitk)\n+__git_log_shortlog_options=\"\n+\t--author= --committer= --grep=\n+\t--all-match\n+\"\n+\n __git_log_pretty_formats=\"oneline short medium full fuller email raw format:\"\n \n _git_log ()\n@@ -996,21 +1017,19 @@ _git_log ()\n \t\t;;\n \t--*)\n \t\t__gitcomp \"\n-\t\t\t--max-count= --max-age= --since= --after=\n-\t\t\t--min-age= --before= --until=\n+\t\t\t$__git_log_common_options\n+\t\t\t$__git_log_shortlog_options\n+\t\t\t$__git_log_gitk_options\n \t\t\t--root --topo-order --date-order --reverse\n-\t\t\t--no-merges --follow\n+\t\t\t--follow\n \t\t\t--abbrev-commit --abbrev=\n \t\t\t--relative-date --date=\n-\t\t\t--author= --committer= --grep=\n-\t\t\t--all-match\n \t\t\t--pretty=\n-\t\t\t--not --all\n-\t\t\t--left-right --cherry-pick\n+\t\t\t--cherry-pick\n \t\t\t--graph\n \t\t\t--decorate\n \t\t\t--walk-reflogs\n-\t\t\t--parents --children --full-history\n+\t\t\t--parents --children\n \t\t\t--merge\n \t\t\t$__git_diff_common_options\n \t\t\t--pickaxe-all --pickaxe-regex\n@@ -1495,12 +1514,8 @@ _git_shortlog ()\n \tcase \"$cur\" in\n \t--*)\n \t\t__gitcomp \"\n-\t\t\t--max-count= --max-age= --since= --after=\n-\t\t\t--min-age= --before= --until=\n-\t\t\t--no-merges\n-\t\t\t--author= --committer= --grep=\n-\t\t\t--all-match\n-\t\t\t--not --all\n+\t\t\t$__git_log_common_options\n+\t\t\t$__git_log_shortlog_options\n \t\t\t--numbered --summary\n \t\t\t\"\n \t\treturn\n@@ -1808,7 +1823,11 @@ _gitk ()\n \tfi\n \tcase \"$cur\" in\n \t--*)\n-\t\t__gitcomp \"--not --all $merge\"\n+\t\t__gitcomp \"\n+\t\t\t$__git_log_common_options\n+\t\t\t$__git_log_gitk_options\n+\t\t\t$merge\n+\t\t\t\"\n \t\treturn\n \t\t;;\n \tesac\n-- \n1.6.2.rc0.328.g2c702\n"},{"id":"104966","messageId":"bc66ec312ad33c4a7c9580ba4ade75c5998443d7.1234801852.git.trast@student.ethz.ch","threadId":"17795","inReplyTo":"adf1fd3d0902150156w67a16e6fp3c946446c5ae2bfd@mail.gmail.com","subject":"[PATCH v2 2/2] bash completion: only show 'log --merge' if merging","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-16T16:34:57Z","receivedAt":"2009-02-16T16:34:57Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"The gitk completion only shows --merge if MERGE_HEAD is present.\nDo it the same way for git-log completion.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n contrib/completion/git-completion.bash |    7 ++++++-\n 1 files changed, 6 insertions(+), 1 deletions(-)\n\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex a5b3bf3..489951b 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1003,6 +1003,11 @@ _git_log ()\n \t__git_has_doubledash && return\n \n \tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n+\tlocal g=\"$(git rev-parse --git-dir 2>/dev/null)\"\n+\tlocal merge=\"\"\n+\tif [ -f $g/MERGE_HEAD ]; then\n+\t\tmerge=\"--merge\"\n+\tfi\n \tcase \"$cur\" in\n \t--pretty=*)\n \t\t__gitcomp \"$__git_log_pretty_formats\n@@ -1030,7 +1035,7 @@ _git_log ()\n \t\t\t--decorate\n \t\t\t--walk-reflogs\n \t\t\t--parents --children\n-\t\t\t--merge\n+\t\t\t$merge\n \t\t\t$__git_diff_common_options\n \t\t\t--pickaxe-all --pickaxe-regex\n \t\t\t\"\n-- \n1.6.2.rc0.328.g2c702\n"},{"id":"104968","messageId":"200902161738.06509.trast@student.ethz.ch","threadId":"17795","inReplyTo":"cover.1234801852.git.trast@student.ethz.ch","subject":"Re: [PATCH v2 0/2] bash completion: more options for gitk/log/shortlog","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-16T16:38:01Z","receivedAt":"2009-02-16T16:38:01Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Unrelated note regarding --thread usage:\n\nWouldn't it be better if format-patch made it so that the cover\nletter, if any, is the (only) reply to the --in-reply-to, and all\nactual patches are replies to the cover letter?\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"104994","messageId":"1234810812-30499-1-git-send-email-trast@student.ethz.ch","threadId":"17795","inReplyTo":"cover.1234801852.git.trast@student.ethz.ch","subject":"[RFC PATCH] format-patch: thread as reply to cover letter even with in-reply-to","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-16T19:00:12Z","receivedAt":"2009-02-16T19:00:12Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Currently, format-patch --thread --cover-letter --in-reply-to $parent\nmakes all mails, including the cover letter, a reply to $parent.\nHowever, we would want the reader to consider the cover letter above\nall the patches.\n\nThis changes the semantics so that only the cover letter is a reply to\n$parent, while all the patches are formatted as replies to the cover\nletter.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nThomas Rast wrote:\n> Unrelated note regarding --thread usage:\n> \n> Wouldn't it be better if format-patch made it so that the cover\n> letter, if any, is the (only) reply to the --in-reply-to, and all\n> actual patches are replies to the cover letter?\n\nMaybe like this?\n\n\n builtin-log.c |   20 +++++++++++++++-----\n 1 files changed, 15 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin-log.c b/builtin-log.c\nindex 2ae39af..ec11f95 100644\n--- a/builtin-log.c\n+++ b/builtin-log.c\n@@ -1031,12 +1031,22 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\t\t/* Have we already had a message ID? */\n \t\t\tif (rev.message_id) {\n \t\t\t\t/*\n-\t\t\t\t * If we've got the ID to be a reply\n-\t\t\t\t * to, discard the current ID;\n-\t\t\t\t * otherwise, make everything a reply\n-\t\t\t\t * to that.\n+\t\t\t\t * Without --cover-letter and\n+\t\t\t\t * --in-reply-to, make every mail a\n+\t\t\t\t * reply to the one before.\n+\t\t\t\t *\n+\t\t\t\t * With --in-reply-to but no\n+\t\t\t\t * --cover-letter, make every mail a\n+\t\t\t\t * reply to the <reply-to>.\n+\t\t\t\t *\n+\t\t\t\t * With --cover-letter, make every\n+\t\t\t\t * mail but the cover letter a reply\n+\t\t\t\t * to the cover letter.  The cover\n+\t\t\t\t * letter is a reply to the\n+\t\t\t\t * --in-reply-to, if specified.\n \t\t\t\t */\n-\t\t\t\tif (rev.ref_message_id)\n+\t\t\t\tif (rev.ref_message_id\n+\t\t\t\t    && (!cover_letter || rev.nr > 1))\n \t\t\t\t\tfree(rev.message_id);\n \t\t\t\telse\n \t\t\t\t\trev.ref_message_id = rev.message_id;\n-- \n1.6.2.rc0.328.g2c702\n"},{"id":"104999","messageId":"76718490902161222p7f1ecbf9x6f965ff94b3cfae7@mail.gmail.com","threadId":"17795","inReplyTo":"1234810812-30499-1-git-send-email-trast@student.ethz.ch","subject":"Re: [RFC PATCH] format-patch: thread as reply to cover letter even with in-reply-to","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-16T20:22:14Z","receivedAt":"2009-02-16T20:22:14Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"On Mon, Feb 16, 2009 at 2:00 PM, Thomas Rast <trast@student.ethz.ch> wrote:\n> Currently, format-patch --thread --cover-letter --in-reply-to $parent\n> makes all mails, including the cover letter, a reply to $parent.\n> However, we would want the reader to consider the cover letter above\n> all the patches.\n>\n> This changes the semantics so that only the cover letter is a reply to\n> $parent, while all the patches are formatted as replies to the cover\n> letter.\n\nI think this change may be okay, but I think to go with it the\ncover-letter and all the patches should have a \"References:\" header\nwith the message-id given by --in-reply-to.\n\nRFC 2822 says:\n\n   The \"In-Reply-To:\" and \"References:\" fields are used when creating a\n   reply to a message.  They hold the message identifier of the original\n   message and the message identifiers of other messages (for example,\n   in the case of a reply to a message which was itself a reply).  The\n   \"In-Reply-To:\" field may be used to identify the message (or\n   messages) to which the new message is a reply, while the\n   \"References:\" field may be used to identify a \"thread\" of\n   conversation.\n\nj.\n"},{"id":"105002","messageId":"200902162134.28850.trast@student.ethz.ch","threadId":"17795","inReplyTo":"76718490902161222p7f1ecbf9x6f965ff94b3cfae7@mail.gmail.com","subject":"Re: [RFC PATCH] format-patch: thread as reply to cover letter even with in-reply-to","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-16T20:34:20Z","receivedAt":"2009-02-16T20:34:20Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Jay Soffian wrote:\n> I think this change may be okay, but I think to go with it the\n> cover-letter and all the patches should have a \"References:\" header\n> with the message-id given by --in-reply-to.\n\nThat's a completely separate issue.  I'm only proposing to change\nwhat is formatted as a reply to what, the In-Reply-To and References\nformatting is handled by the existing code.  That being said...\n\n> RFC 2822 says:\n> \n>    The \"In-Reply-To:\" and \"References:\" fields are used when creating a\n>    reply to a message.  They hold the message identifier of the original\n>    message and the message identifiers of other messages (for example,\n>    in the case of a reply to a message which was itself a reply).  The\n>    \"In-Reply-To:\" field may be used to identify the message (or\n>    messages) to which the new message is a reply, while the\n>    \"References:\" field may be used to identify a \"thread\" of\n>    conversation.\n\nThe References formatting can't satisfy the following requirement, two\nparagraphs further down in the RFC,\n\n   The \"References:\" field will contain the contents of the parent's\n   \"References:\" field (if any) followed by the contents of the parent's\n   \"Message-ID:\" field (if any).\n\nbecause it doesn't have access to the mail being replied to.  It\nmerely sets References to the same as In-Reply-To.\n\n(Note that I'm just guessing this from behaviour I can observe, I\nhaven't actually read the code for that part.)\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"105004","messageId":"m3bpt2t8a6.fsf@localhost.localdomain","threadId":"17795","inReplyTo":"200902162134.28850.trast@student.ethz.ch","subject":"Re: [RFC PATCH] format-patch: thread as reply to cover letter even with in-reply-to","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2009-02-16T20:52:50Z","receivedAt":"2009-02-16T20:52:50Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> writes:\n> Jay Soffian wrote:\n\n> > I think this change may be okay, but I think to go with it the\n> > cover-letter and all the patches should have a \"References:\" header\n> > with the message-id given by --in-reply-to.\n> \n> That's a completely separate issue.  I'm only proposing to change\n> what is formatted as a reply to what, the In-Reply-To and References\n> formatting is handled by the existing code.\n\nPerhaps a follow-up patch then?\n\n>  That being said...\n> \n> > RFC 2822 says:\n> > \n> >    The \"In-Reply-To:\" and \"References:\" fields are used when creating a\n> >    reply to a message.  They hold the message identifier of the original\n> >    message and the message identifiers of other messages (for example,\n> >    in the case of a reply to a message which was itself a reply).  The\n> >    \"In-Reply-To:\" field may be used to identify the message (or\n> >    messages) to which the new message is a reply, while the\n> >    \"References:\" field may be used to identify a \"thread\" of\n> >    conversation.\n> \n> The References formatting can't satisfy the following requirement, two\n> paragraphs further down in the RFC,\n> \n>    The \"References:\" field will contain the contents of the parent's\n>    \"References:\" field (if any) followed by the contents of the parent's\n>    \"Message-ID:\" field (if any).\n> \n> because it doesn't have access to the mail being replied to.  It\n> merely sets References to the same as In-Reply-To.\n\nI think \"References:\" field can be shortened, and although IIRC it is\nrecommended to leave first ancestor, two separators, and three last\nancestors in shortened \"References:\" header, it would be better if\npatches had both '--in-reply-to' message id AND cover letter id in\n\"References:\" header.  That would make for safer threading...\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"105027","messageId":"200902170027.09406.trast@student.ethz.ch","threadId":"17795","inReplyTo":"m3bpt2t8a6.fsf@localhost.localdomain","subject":"Re: [RFC PATCH] format-patch: thread as reply to cover letter even with in-reply-to","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-16T23:27:04Z","receivedAt":"2009-02-16T23:27:04Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Jakub Narebski wrote:\n> Thomas Rast <trast@student.ethz.ch> writes:\n> > Jay Soffian wrote:\n> \n> > > I think this change may be okay, but I think to go with it the\n> > > cover-letter and all the patches should have a \"References:\" header\n> > > with the message-id given by --in-reply-to.\n> > \n> > That's a completely separate issue.  I'm only proposing to change\n> > what is formatted as a reply to what, the In-Reply-To and References\n> > formatting is handled by the existing code.\n[...]\n> patches had both '--in-reply-to' message id AND cover letter id in\n> \"References:\" header.  That would make for safer threading...\n\nOh, now I see what you meant.\n\nIt seems that right now, send-email appends the right references for\n--thread mode, and format-patch only does the one-reference case.\nI'll try and make a patch for that.\n\n-- \nThomas Rast\ntrast@{inf,student}.ethz.ch\n"},{"id":"105324","messageId":"20090218170518.GD22848@spearce.org","threadId":"17795","inReplyTo":"bc66ec312ad33c4a7c9580ba4ade75c5998443d7.1234801852.git.trast@student.ethz.ch","subject":"Re: [PATCH v2 2/2] bash completion: only show 'log --merge' if merging","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-02-18T17:05:18Z","receivedAt":"2009-02-18T17:05:18Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> wrote:\n> The gitk completion only shows --merge if MERGE_HEAD is present.\n> Do it the same way for git-log completion.\n> \n> Signed-off-by: Thomas Rast <trast@student.ethz.ch>\n> ---\n>  contrib/completion/git-completion.bash |    7 ++++++-\n>  1 files changed, 6 insertions(+), 1 deletions(-)\n\nBoth patches,\n\nAcked-by: Shawn O. Pearce <spearce@spearce.org>\n \n> diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\n> index a5b3bf3..489951b 100755\n> --- a/contrib/completion/git-completion.bash\n> +++ b/contrib/completion/git-completion.bash\n> @@ -1003,6 +1003,11 @@ _git_log ()\n>  \t__git_has_doubledash && return\n>  \n>  \tlocal cur=\"${COMP_WORDS[COMP_CWORD]}\"\n> +\tlocal g=\"$(git rev-parse --git-dir 2>/dev/null)\"\n> +\tlocal merge=\"\"\n> +\tif [ -f $g/MERGE_HEAD ]; then\n> +\t\tmerge=\"--merge\"\n> +\tfi\n>  \tcase \"$cur\" in\n>  \t--pretty=*)\n>  \t\t__gitcomp \"$__git_log_pretty_formats\n> @@ -1030,7 +1035,7 @@ _git_log ()\n>  \t\t\t--decorate\n>  \t\t\t--walk-reflogs\n>  \t\t\t--parents --children\n> -\t\t\t--merge\n> +\t\t\t$merge\n>  \t\t\t$__git_diff_common_options\n>  \t\t\t--pickaxe-all --pickaxe-regex\n>  \t\t\t\"\n> -- \n> 1.6.2.rc0.328.g2c702\n> \n\n-- \nShawn.\n"},{"id":"105333","messageId":"7vwsbnwotw.fsf@gitster.siamese.dyndns.org","threadId":"17795","inReplyTo":"20090218170518.GD22848@spearce.org","subject":"Re: [PATCH v2 2/2] bash completion: only show 'log --merge' if merging","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-18T19:02:35Z","receivedAt":"2009-02-18T19:02:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Shawn O. Pearce\" <spearce@spearce.org> writes:\n\n> Thomas Rast <trast@student.ethz.ch> wrote:\n>> The gitk completion only shows --merge if MERGE_HEAD is present.\n>> Do it the same way for git-log completion.\n>> \n>> Signed-off-by: Thomas Rast <trast@student.ethz.ch>\n>> ---\n>>  contrib/completion/git-completion.bash |    7 ++++++-\n>>  1 files changed, 6 insertions(+), 1 deletions(-)\n>\n> Both patches,\n>\n> Acked-by: Shawn O. Pearce <spearce@spearce.org>\n\nThanks.\n"},{"id":"105520","messageId":"cover.1235078708.git.trast@student.ethz.ch","threadId":"17795","inReplyTo":"200902170027.09406.trast@student.ethz.ch","subject":"[PATCH 0/4] format-patch --cover-letter --in-reply-to","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-19T21:26:29Z","receivedAt":"2009-02-19T21:26:29Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Lemma 1: Any task, no matter how trivial, expands to at least three\n         patches.\n\nTurns out there were tests, but they never worked.  In any case it\nshould now know how to properly format References, and also knows\nabout deep and shallow threading.\n\nI formatted this series with\n\n  git format-patch origin/master..t/thread-reply-to-cover \\\n    --cover-letter --thread \\\n    --in-reply-to='<200902170027.09406.trast@student.ethz.ch>'\n\n\nThomas Rast (4):\n  format-patch: threading test reactivation\n  format-patch: track several references\n  format-patch: thread as reply to cover letter even with in-reply-to\n  format-patch: support deep threading\n\n Documentation/config.txt           |   10 ++\n Documentation/git-format-patch.txt |   10 ++-\n builtin-log.c                      |   65 ++++++++--\n log-tree.c                         |   11 +-\n revision.h                         |    2 +-\n t/t4014-format-patch.sh            |  265 ++++++++++++++++++++++++++++++------\n 6 files changed, 308 insertions(+), 55 deletions(-)\n"},{"id":"105521","messageId":"f4556c46b8b74d12ccfd0dc5c13865c89062233a.1235078708.git.trast@student.ethz.ch","threadId":"17795","inReplyTo":"cover.1235078708.git.trast@student.ethz.ch","subject":"[PATCH 1/4] format-patch: threading test reactivation","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-19T21:26:30Z","receivedAt":"2009-02-19T21:26:30Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"t4014 tests format-patch --thread since 7d812145, but the tests were\nineffective right from the start at least for bash and dash.  The\nloops of the form\n\n  for ...; do something || break; done\n\nintroduced by 7d812145 and 5d02294 always exit with status 0, even if\n'something' failed, because 'break' returns 0 unless there was no loop\nto break.\n\nWe take a rather different approach that uses an admittedly heinous\ninline Perl script to mangle all interesting information into a format\nthat is invariant between runs.  We can then test the full patch\nsequence in one go (with --stdout), doing away with the loop problem.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n t/t4014-format-patch.sh |  144 ++++++++++++++++++++++++++++++++++-------------\n 1 files changed, 104 insertions(+), 40 deletions(-)\n\ndiff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh\nindex f045898..345e6de 100755\n--- a/t/t4014-format-patch.sh\n+++ b/t/t4014-format-patch.sh\n@@ -138,56 +138,120 @@ test_expect_success 'multiple files' '\n \tls patches/0001-Side-changes-1.patch patches/0002-Side-changes-2.patch patches/0003-Side-changes-3-with-n-backslash-n-in-it.patch\n '\n \n-test_expect_success 'thread' '\n+check_threading () {\n+\texpect=\"$1\" &&\n+\tshift &&\n+\t(git format-patch --stdout \"$@\"; echo $? > status.out) |\n+\t# Prints everything between the Message-ID and In-Reply-To,\n+\t# and replaces all Message-ID-lookalikes by a sequence number\n+\tperl -ne '\n+\t\tif (/^(message-id|references|in-reply-to)/i) {\n+\t\t\t$printing = 1;\n+\t\t} elsif (/^\\S/) {\n+\t\t\t$printing = 0;\n+\t\t}\n+\t\tif ($printing) {\n+\t\t\t$h{$1}=$i++ if (/<([^>]+)>/ and !exists $h{$1});\n+\t\t\tfor $k (keys %h) {s/$k/$h{$k}/};\n+\t\t\tprint;\n+\t\t}\n+\t\tprint \"---\\n\" if /^From /i;\n+\t' > actual &&\n+\ttest 0 = \"$(cat status.out)\" &&\n+\ttest_cmp \"$expect\" actual\n+}\n+\n+cat >> expect.no-threading <<EOF\n+---\n+---\n+---\n+EOF\n \n-\trm -rf patches/ &&\n+test_expect_success 'no threading' '\n \tgit checkout side &&\n-\tgit format-patch --thread -o patches/ master &&\n-\tFIRST_MID=$(grep \"Message-Id:\" patches/0001-* | sed \"s/^[^<]*\\(<[^>]*>\\).*$/\\1/\") &&\n-\tfor i in patches/0002-* patches/0003-*\n-\tdo\n-\t  grep \"References: $FIRST_MID\" $i &&\n-\t  grep \"In-Reply-To: $FIRST_MID\" $i || break\n-\tdone\n+\tcheck_threading expect.no-threading master\n '\n \n-test_expect_success 'thread in-reply-to' '\n+cat > expect.thread <<EOF\n+---\n+Message-Id: <0>\n+---\n+Message-Id: <1>\n+In-Reply-To: <0>\n+References: <0>\n+---\n+Message-Id: <2>\n+In-Reply-To: <0>\n+References: <0>\n+EOF\n \n-\trm -rf patches/ &&\n-\tgit checkout side &&\n-\tgit format-patch --in-reply-to=\"<test.message>\" --thread -o patches/ master &&\n-\tFIRST_MID=\"<test.message>\" &&\n-\tfor i in patches/*\n-\tdo\n-\t  grep \"References: $FIRST_MID\" $i &&\n-\t  grep \"In-Reply-To: $FIRST_MID\" $i || break\n-\tdone\n+test_expect_success 'thread' '\n+\tcheck_threading expect.thread --thread master\n '\n \n-test_expect_success 'thread cover-letter' '\n+cat > expect.in-reply-to <<EOF\n+---\n+Message-Id: <0>\n+In-Reply-To: <1>\n+References: <1>\n+---\n+Message-Id: <2>\n+In-Reply-To: <1>\n+References: <1>\n+---\n+Message-Id: <3>\n+In-Reply-To: <1>\n+References: <1>\n+EOF\n \n-\trm -rf patches/ &&\n-\tgit checkout side &&\n-\tgit format-patch --cover-letter --thread -o patches/ master &&\n-\tFIRST_MID=$(grep \"Message-Id:\" patches/0000-* | sed \"s/^[^<]*\\(<[^>]*>\\).*$/\\1/\") &&\n-\tfor i in patches/0001-* patches/0002-* patches/0003-*\n-\tdo\n-\t  grep \"References: $FIRST_MID\" $i &&\n-\t  grep \"In-Reply-To: $FIRST_MID\" $i || break\n-\tdone\n+test_expect_success 'thread in-reply-to' '\n+\tcheck_threading expect.in-reply-to --in-reply-to=\"<test.message>\" \\\n+\t\t--thread master\n '\n \n-test_expect_success 'thread cover-letter in-reply-to' '\n+cat > expect.cover-letter <<EOF\n+---\n+Message-Id: <0>\n+---\n+Message-Id: <1>\n+In-Reply-To: <0>\n+References: <0>\n+---\n+Message-Id: <2>\n+In-Reply-To: <0>\n+References: <0>\n+---\n+Message-Id: <3>\n+In-Reply-To: <0>\n+References: <0>\n+EOF\n \n-\trm -rf patches/ &&\n-\tgit checkout side &&\n-\tgit format-patch --cover-letter --in-reply-to=\"<test.message>\" --thread -o patches/ master &&\n-\tFIRST_MID=\"<test.message>\" &&\n-\tfor i in patches/*\n-\tdo\n-\t  grep \"References: $FIRST_MID\" $i &&\n-\t  grep \"In-Reply-To: $FIRST_MID\" $i || break\n-\tdone\n+test_expect_success 'thread cover-letter' '\n+\tcheck_threading expect.cover-letter --cover-letter --thread master\n+'\n+\n+cat > expect.cl-irt <<EOF\n+---\n+Message-Id: <0>\n+In-Reply-To: <1>\n+References: <1>\n+---\n+Message-Id: <2>\n+In-Reply-To: <1>\n+References: <1>\n+---\n+Message-Id: <3>\n+In-Reply-To: <1>\n+References: <1>\n+---\n+Message-Id: <4>\n+In-Reply-To: <1>\n+References: <1>\n+EOF\n+\n+test_expect_success 'thread cover-letter in-reply-to' '\n+\tcheck_threading expect.cl-irt --cover-letter \\\n+\t\t--in-reply-to=\"<test.message>\" --thread master\n '\n \n test_expect_success 'excessive subject' '\n-- \n1.6.2.rc1.295.g1e29\n"},{"id":"105519","messageId":"5a41305e9103c870e8cae95dcf58655c275aba9b.1235078708.git.trast@student.ethz.ch","threadId":"17795","inReplyTo":"cover.1235078708.git.trast@student.ethz.ch","subject":"[PATCH 2/4] format-patch: track several references","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-19T21:26:31Z","receivedAt":"2009-02-19T21:26:31Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Currently, format-patch can only track a single reference (the\nIn-Reply-To:) for each mail.  To ensure proper threading, we should\nlist all known references for every mail.\n\nChange the rev_info.ref_message_id field to a string_list, so that we\ncan append references at will, and change the output formatting\nroutines to print all of them in the References: header.  The last\nentry in the list is implicitly assumed to be the In-Reply-To:, which\ngives output consistent with RFC 2822:\n\n   The \"References:\" field will contain the contents of the parent's\n   \"References:\" field (if any) followed by the contents of the\n   parent's \"Message-ID:\" field (if any).\n\nNote that this is just preparatory work; nothing uses it yet, so all\n\"References:\" fields in the output are still only one deep.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n builtin-log.c |   14 ++++++++++----\n log-tree.c    |   11 ++++++++---\n revision.h    |    2 +-\n 3 files changed, 19 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin-log.c b/builtin-log.c\nindex 2ae39af..b188575 100644\n--- a/builtin-log.c\n+++ b/builtin-log.c\n@@ -17,6 +17,7 @@\n #include \"run-command.h\"\n #include \"shortlog.h\"\n #include \"remote.h\"\n+#include \"string-list.h\"\n \n /* Set a default date-time format for git log (\"log.date\" config variable) */\n static const char *default_date_mode = NULL;\n@@ -1011,8 +1012,12 @@ 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-\tif (in_reply_to)\n-\t\trev.ref_message_id = clean_message_id(in_reply_to);\n+\tif (in_reply_to || thread || cover_letter)\n+\t\trev.ref_message_id = xcalloc(1, sizeof(struct string_list));\n+\tif (in_reply_to) {\n+\t\tconst char *msgid = clean_message_id(in_reply_to);\n+\t\tstring_list_append(msgid, rev.ref_message_id);\n+\t}\n \tif (cover_letter) {\n \t\tif (thread)\n \t\t\tgen_message_id(&rev, \"cover\");\n@@ -1036,10 +1041,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\t\t\t * otherwise, make everything a reply\n \t\t\t\t * to that.\n \t\t\t\t */\n-\t\t\t\tif (rev.ref_message_id)\n+\t\t\t\tif (rev.ref_message_id->nr > 0)\n \t\t\t\t\tfree(rev.message_id);\n \t\t\t\telse\n-\t\t\t\t\trev.ref_message_id = rev.message_id;\n+\t\t\t\t\tstring_list_append(rev.message_id,\n+\t\t\t\t\t\t\t   rev.ref_message_id);\n \t\t\t}\n \t\t\tgen_message_id(&rev, sha1_to_hex(commit->object.sha1));\n \t\t}\ndiff --git a/log-tree.c b/log-tree.c\nindex 84a74e5..72d97b8 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -6,6 +6,7 @@\n #include \"log-tree.h\"\n #include \"reflog-walk.h\"\n #include \"refs.h\"\n+#include \"string-list.h\"\n \n struct decoration name_decoration = { \"object names\" };\n \n@@ -211,9 +212,13 @@ void log_write_email_headers(struct rev_info *opt, const char *name,\n \t\tprintf(\"Message-Id: <%s>\\n\", opt->message_id);\n \t\tgraph_show_oneline(opt->graph);\n \t}\n-\tif (opt->ref_message_id) {\n-\t\tprintf(\"In-Reply-To: <%s>\\nReferences: <%s>\\n\",\n-\t\t       opt->ref_message_id, opt->ref_message_id);\n+\tif (opt->ref_message_id && opt->ref_message_id->nr > 0) {\n+\t\tint i, n;\n+\t\tn = opt->ref_message_id->nr;\n+\t\tprintf(\"In-Reply-To: <%s>\\n\", opt->ref_message_id->items[n-1].string);\n+\t\tfor (i = 0; i < n; i++)\n+\t\t\tprintf(\"%s<%s>\\n\", (i > 0 ? \"\\t\" : \"References: \"),\n+\t\t\t       opt->ref_message_id->items[i].string);\n \t\tgraph_show_oneline(opt->graph);\n \t}\n \tif (opt->mime_boundary) {\ndiff --git a/revision.h b/revision.h\nindex 7cf8487..01dc74e 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -89,7 +89,7 @@ struct rev_info {\n \tint\t\tnr, total;\n \tconst char\t*mime_boundary;\n \tchar\t\t*message_id;\n-\tconst char\t*ref_message_id;\n+\tstruct string_list *ref_message_id;\n \tconst char\t*add_signoff;\n \tconst char\t*extra_headers;\n \tconst char\t*log_reencode;\n-- \n1.6.2.rc1.295.g1e29\n"},{"id":"105523","messageId":"27f6b112941593e8ad92298814645b97a3e20fe2.1235078708.git.trast@student.ethz.ch","threadId":"17795","inReplyTo":"cover.1235078708.git.trast@student.ethz.ch","subject":"[PATCH 3/4] format-patch: thread as reply to cover letter even with in-reply-to","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-19T21:26:32Z","receivedAt":"2009-02-19T21:26:32Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Currently, format-patch --thread --cover-letter --in-reply-to $parent\nmakes all mails, including the cover letter, a reply to $parent.\nHowever, we would want the reader to consider the cover letter above\nall the patches.\n\nThis changes the semantics so that only the cover letter is a reply to\n$parent, while all the patches are formatted as replies to the cover\nletter.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n builtin-log.c           |   20 +++++++++++++++-----\n t/t4014-format-patch.sh |    9 ++++++---\n 2 files changed, 21 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin-log.c b/builtin-log.c\nindex b188575..89bfa70 100644\n--- a/builtin-log.c\n+++ b/builtin-log.c\n@@ -1036,12 +1036,22 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\t\t/* Have we already had a message ID? */\n \t\t\tif (rev.message_id) {\n \t\t\t\t/*\n-\t\t\t\t * If we've got the ID to be a reply\n-\t\t\t\t * to, discard the current ID;\n-\t\t\t\t * otherwise, make everything a reply\n-\t\t\t\t * to that.\n+\t\t\t\t * Without --cover-letter and\n+\t\t\t\t * --in-reply-to, make every mail a\n+\t\t\t\t * reply to the one before.\n+\t\t\t\t *\n+\t\t\t\t * With --in-reply-to but no\n+\t\t\t\t * --cover-letter, make every mail a\n+\t\t\t\t * reply to the <reply-to>.\n+\t\t\t\t *\n+\t\t\t\t * With --cover-letter, make every\n+\t\t\t\t * mail but the cover letter a reply\n+\t\t\t\t * to the cover letter.  The cover\n+\t\t\t\t * letter is a reply to the\n+\t\t\t\t * --in-reply-to, if specified.\n \t\t\t\t */\n-\t\t\t\tif (rev.ref_message_id->nr > 0)\n+\t\t\t\tif (rev.ref_message_id->nr > 0\n+\t\t\t\t    && (!cover_letter || rev.nr > 1))\n \t\t\t\t\tfree(rev.message_id);\n \t\t\t\telse\n \t\t\t\t\tstring_list_append(rev.message_id,\ndiff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh\nindex 345e6de..8b970c3 100755\n--- a/t/t4014-format-patch.sh\n+++ b/t/t4014-format-patch.sh\n@@ -237,16 +237,19 @@ In-Reply-To: <1>\n References: <1>\n ---\n Message-Id: <2>\n-In-Reply-To: <1>\n+In-Reply-To: <0>\n References: <1>\n+\t<0>\n ---\n Message-Id: <3>\n-In-Reply-To: <1>\n+In-Reply-To: <0>\n References: <1>\n+\t<0>\n ---\n Message-Id: <4>\n-In-Reply-To: <1>\n+In-Reply-To: <0>\n References: <1>\n+\t<0>\n EOF\n \n test_expect_success 'thread cover-letter in-reply-to' '\n-- \n1.6.2.rc1.295.g1e29\n"},{"id":"105522","messageId":"89a713f0418c31fcbc97f3019100779816f111b6.1235078708.git.trast@student.ethz.ch","threadId":"17795","inReplyTo":"cover.1235078708.git.trast@student.ethz.ch","subject":"[PATCH 4/4] format-patch: support deep threading","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-19T21:26:33Z","receivedAt":"2009-02-19T21:26:33Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"For deep threading mode, i.e., the mode that gives a thread structured\nlike\n\n  + [PATCH 0/n] Cover letter\n   `-+ [PATCH 1/n] First patch\n      `-+ [PATCH 2/n] Second patch\n         `-+ ...\n\nwe currently have to use 'git send-email --thread' (the default).  On\nthe other hand, format-patch also has a --thread option which gives\nshallow mode, i.e.,\n\n  + [PATCH 0/n] Cover letter\n  |-+ [PATCH 1/n] First patch\n  |-+ [PATCH 2/n] Second patch\n  ...\n\nTo reduce the confusion resulting from having two indentically named\nfeatures in different tools giving different results, let format-patch\ntake an optional argument '--thread=deep' that gives the same output\nas 'send-mail --thread'.  With no argument, or 'shallow', behave as\nbefore.  Also add a configuration variable format.thread with the same\nsemantics.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n Documentation/config.txt           |   10 +++\n Documentation/git-format-patch.txt |   10 +++-\n builtin-log.c                      |   35 +++++++++-\n t/t4014-format-patch.sh            |  120 ++++++++++++++++++++++++++++++++++++\n 4 files changed, 170 insertions(+), 5 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex f5152c5..300ab25 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -677,6 +677,16 @@ format.pretty::\n \tSee linkgit:git-log[1], linkgit:git-show[1],\n \tlinkgit:git-whatchanged[1].\n \n+format.thread::\n+\tThe default threading style for 'git-format-patch'.  Can be\n+\teither a boolean value, `shallow` or `deep`.  'Shallow'\n+\tthreading makes every mail a reply to the head of the series,\n+\twhere the head is chosen from the cover letter, the\n+\t`\\--in-reply-to`, and the first patch mail, in this order.\n+\t'Deep' threading makes every mail a reply to the previous one.\n+\tA true boolean value is the same as `shallow`, and a false\n+\tvalue disables threading.\n+\n gc.aggressiveWindow::\n \tThe window size parameter used in the delta compression\n \talgorithm used by 'git-gc --aggressive'.  This defaults\ndiff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt\nindex 11a7d77..4302b14 100644\n--- a/Documentation/git-format-patch.txt\n+++ b/Documentation/git-format-patch.txt\n@@ -122,10 +122,18 @@ include::diff-options.txt[]\n \twhich is the commit message and the patch itself in the\n \tsecond part, with \"Content-Disposition: inline\".\n \n---thread::\n+--thread[=<style>]::\n \tAdd In-Reply-To and References headers to make the second and\n \tsubsequent mails appear as replies to the first.  Also generates\n \tthe Message-Id header to reference.\n++\n+The optional <style> argument can be either `shallow` or `deep`.\n+'Shallow' threading makes every mail a reply to the head of the\n+series, where the head is chosen from the cover letter, the\n+`\\--in-reply-to`, and the first patch mail, in this order.  'Deep'\n+threading makes every mail a reply to the previous one.  If not\n+specified, defaults to the 'format.thread' configuration, or `shallow`\n+if that is not set.\n \n --in-reply-to=Message-Id::\n \tMake the first mail (or all the mails with --no-thread) appear as a\ndiff --git a/builtin-log.c b/builtin-log.c\nindex 89bfa70..101343b 100644\n--- a/builtin-log.c\n+++ b/builtin-log.c\n@@ -460,6 +460,10 @@ static void add_header(const char *value)\n \textra_hdr[extra_hdr_nr++] = xstrndup(value, len);\n }\n \n+#define THREAD_SHALLOW 1\n+#define THREAD_DEEP 2\n+static int thread = 0;\n+\n static int git_format_config(const char *var, const char *value, void *cb)\n {\n \tif (!strcmp(var, \"format.headers\")) {\n@@ -489,6 +493,18 @@ static int git_format_config(const char *var, const char *value, void *cb)\n \t\tauto_number = auto_number && numbered;\n \t\treturn 0;\n \t}\n+\tif (!strcmp(var, \"format.thread\")) {\n+\t\tif (value && !strcasecmp(value, \"deep\")) {\n+\t\t\tthread = THREAD_DEEP;\n+\t\t\treturn 0;\n+\t\t}\n+\t\tif (value && !strcasecmp(value, \"shallow\")) {\n+\t\t\tthread = THREAD_SHALLOW;\n+\t\t\treturn 0;\n+\t\t}\n+\t\tthread = git_config_bool(var, value) && THREAD_SHALLOW;\n+\t\treturn 0;\n+\t}\n \n \treturn git_log_config(var, value, cb);\n }\n@@ -767,7 +783,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \tint numbered_files = 0;\t\t/* _just_ numbers */\n \tint subject_prefix = 0;\n \tint ignore_if_in_upstream = 0;\n-\tint thread = 0;\n \tint cover_letter = 0;\n \tint boundary_count = 0;\n \tint no_binary_diff = 0;\n@@ -860,8 +875,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\t}\n \t\telse if (!strcmp(argv[i], \"--ignore-if-in-upstream\"))\n \t\t\tignore_if_in_upstream = 1;\n-\t\telse if (!strcmp(argv[i], \"--thread\"))\n-\t\t\tthread = 1;\n+\t\telse if (!strcmp(argv[i], \"--thread\")\n+\t\t\t|| !strcmp(argv[i], \"--thread=shallow\"))\n+\t\t\tthread = THREAD_SHALLOW;\n+\t\telse if (!strcmp(argv[i], \"--thread=deep\"))\n+\t\t\tthread = THREAD_DEEP;\n+\t\telse if (!strcmp(argv[i], \"--no-thread\"))\n+\t\t\tthread = 0;\n \t\telse if (!prefixcmp(argv[i], \"--in-reply-to=\"))\n \t\t\tin_reply_to = argv[i] + 14;\n \t\telse if (!strcmp(argv[i], \"--in-reply-to\")) {\n@@ -1036,6 +1056,12 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\t\t/* Have we already had a message ID? */\n \t\t\tif (rev.message_id) {\n \t\t\t\t/*\n+\t\t\t\t * For deep threading: make every mail\n+\t\t\t\t * a reply to the previous one, no\n+\t\t\t\t * matter what other options are set.\n+\t\t\t\t *\n+\t\t\t\t * For shallow threading:\n+\t\t\t\t *\n \t\t\t\t * Without --cover-letter and\n \t\t\t\t * --in-reply-to, make every mail a\n \t\t\t\t * reply to the one before.\n@@ -1050,7 +1076,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\t\t\t * letter is a reply to the\n \t\t\t\t * --in-reply-to, if specified.\n \t\t\t\t */\n-\t\t\t\tif (rev.ref_message_id->nr > 0\n+\t\t\t\tif (thread == THREAD_SHALLOW\n+\t\t\t\t    && rev.ref_message_id->nr > 0\n \t\t\t\t    && (!cover_letter || rev.nr > 1))\n \t\t\t\t\tfree(rev.message_id);\n \t\t\t\telse\ndiff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh\nindex 8b970c3..ebfc4a6 100755\n--- a/t/t4014-format-patch.sh\n+++ b/t/t4014-format-patch.sh\n@@ -257,6 +257,126 @@ test_expect_success 'thread cover-letter in-reply-to' '\n \t\t--in-reply-to=\"<test.message>\" --thread master\n '\n \n+test_expect_success 'thread explicit shallow' '\n+\tcheck_threading expect.cl-irt --cover-letter \\\n+\t\t--in-reply-to=\"<test.message>\" --thread=shallow master\n+'\n+\n+cat > expect.deep <<EOF\n+---\n+Message-Id: <0>\n+---\n+Message-Id: <1>\n+In-Reply-To: <0>\n+References: <0>\n+---\n+Message-Id: <2>\n+In-Reply-To: <1>\n+References: <0>\n+\t<1>\n+EOF\n+\n+test_expect_success 'thread deep' '\n+\tcheck_threading expect.deep --thread=deep master\n+'\n+\n+cat > expect.deep-irt <<EOF\n+---\n+Message-Id: <0>\n+In-Reply-To: <1>\n+References: <1>\n+---\n+Message-Id: <2>\n+In-Reply-To: <0>\n+References: <1>\n+\t<0>\n+---\n+Message-Id: <3>\n+In-Reply-To: <2>\n+References: <1>\n+\t<0>\n+\t<2>\n+EOF\n+\n+test_expect_success 'thread deep in-reply-to' '\n+\tcheck_threading expect.deep-irt  --thread=deep \\\n+\t\t--in-reply-to=\"<test.message>\" master\n+'\n+\n+cat > expect.deep-cl <<EOF\n+---\n+Message-Id: <0>\n+---\n+Message-Id: <1>\n+In-Reply-To: <0>\n+References: <0>\n+---\n+Message-Id: <2>\n+In-Reply-To: <1>\n+References: <0>\n+\t<1>\n+---\n+Message-Id: <3>\n+In-Reply-To: <2>\n+References: <0>\n+\t<1>\n+\t<2>\n+EOF\n+\n+test_expect_success 'thread deep cover-letter' '\n+\tcheck_threading expect.deep-cl --cover-letter --thread=deep master\n+'\n+\n+cat > expect.deep-cl-irt <<EOF\n+---\n+Message-Id: <0>\n+In-Reply-To: <1>\n+References: <1>\n+---\n+Message-Id: <2>\n+In-Reply-To: <0>\n+References: <1>\n+\t<0>\n+---\n+Message-Id: <3>\n+In-Reply-To: <2>\n+References: <1>\n+\t<0>\n+\t<2>\n+---\n+Message-Id: <4>\n+In-Reply-To: <3>\n+References: <1>\n+\t<0>\n+\t<2>\n+\t<3>\n+EOF\n+\n+test_expect_success 'thread deep cover-letter in-reply-to' '\n+\tcheck_threading expect.deep-cl-irt --cover-letter \\\n+\t\t--in-reply-to=\"<test.message>\" --thread=deep master\n+'\n+\n+test_expect_success 'thread via config' '\n+\tgit config format.thread true &&\n+\tcheck_threading expect.thread master\n+'\n+\n+test_expect_success 'thread deep via config' '\n+\tgit config format.thread deep &&\n+\tcheck_threading expect.deep master\n+'\n+\n+test_expect_success 'thread config + override' '\n+\tgit config format.thread deep &&\n+\tcheck_threading expect.thread --thread master\n+'\n+\n+test_expect_success 'thread config + --no-thread' '\n+\tgit config format.thread deep &&\n+\tcheck_threading expect.no-threading --no-thread master\n+'\n+\n test_expect_success 'excessive subject' '\n \n \trm -rf patches/ &&\n-- \n1.6.2.rc1.295.g1e29\n"},{"id":"105526","messageId":"alpine.LNX.1.00.0902191734110.19665@iabervon.org","threadId":"17795","inReplyTo":"5a41305e9103c870e8cae95dcf58655c275aba9b.1235078708.git.trast@student.ethz.ch","subject":"Re: [PATCH 2/4] format-patch: track several references","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2009-02-19T22:41:42Z","receivedAt":"2009-02-19T22:41:42Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Thu, 19 Feb 2009, Thomas Rast wrote:\n\n> Currently, format-patch can only track a single reference (the\n> In-Reply-To:) for each mail.  To ensure proper threading, we should\n> list all known references for every mail.\n> \n> Change the rev_info.ref_message_id field to a string_list\n\nIt would be nice to change the field name to \"ref_message_ids\", which is \nmore likely to suggest that it's a list of ids, rather than a single id \nstored strangely.\n\nAside from that, parts 2-4 look good to me (I'm not up on reviewing shell \ncode).\n\n\t-Daniel\n*This .sig left intentionally blank*\n"},{"id":"105642","messageId":"cover.1235158956.git.trast@student.ethz.ch","threadId":"17795","inReplyTo":"alpine.LNX.1.00.0902191734110.19665@iabervon.org","subject":"[PATCH v2 next 0/4] format-patch --cover-letter --in-reply-to","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-20T19:55:36Z","receivedAt":"2009-02-20T19:55:36Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Daniel Barkalow wrote:\n> On Thu, 19 Feb 2009, Thomas Rast wrote:\n> \n> > Currently, format-patch can only track a single reference (the\n> > In-Reply-To:) for each mail.  To ensure proper threading, we should\n> > list all known references for every mail.\n> > \n> > Change the rev_info.ref_message_id field to a string_list\n> \n> It would be nice to change the field name to \"ref_message_ids\", which is \n> more likely to suggest that it's a list of ids, rather than a single id \n> stored strangely.\n\nGood point, I changed that.\n\n> Aside from that, parts 2-4 look good to me (I'm not up on reviewing shell \n> code).\n\nThanks.\n\nI also noticed that there is a textual conflict with 0db5260 (Enable\nsetting attach as the default in .gitconfig for git-format-patch.,\n2009-02-12), which is already in 'next'.  So I rebased the series to\n'next'.\n\n\n\nThomas Rast (4):\n  format-patch: threading test reactivation\n  format-patch: track several references\n  format-patch: thread as reply to cover letter even with in-reply-to\n  format-patch: support deep threading\n\n Documentation/config.txt           |   10 ++\n Documentation/git-format-patch.txt |   10 ++-\n builtin-log.c                      |   66 ++++++++--\n log-tree.c                         |   11 +-\n revision.h                         |    2 +-\n t/t4014-format-patch.sh            |  265 ++++++++++++++++++++++++++++++------\n 6 files changed, 308 insertions(+), 56 deletions(-)\n"},{"id":"105646","messageId":"47e4d803ed1d784e9911a90e1ca052573f77b9d6.1235158956.git.trast@student.ethz.ch","threadId":"17795","inReplyTo":"cover.1235158956.git.trast@student.ethz.ch","subject":"[PATCH v2 next 1/4] format-patch: threading test reactivation","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-20T19:55:37Z","receivedAt":"2009-02-20T19:55:37Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"t4014 tests format-patch --thread since 7d812145, but the tests were\nineffective right from the start at least for bash and dash.  The\nloops of the form\n\n  for ...; do something || break; done\n\nintroduced by 7d812145 and 5d02294 always exit with status 0, even if\n'something' failed, because 'break' returns 0 unless there was no loop\nto break.\n\nWe take a rather different approach that uses an admittedly heinous\ninline Perl script to mangle all interesting information into a format\nthat is invariant between runs.  We can then test the full patch\nsequence in one go (with --stdout), doing away with the loop problem.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nSame as v1.\n\n\n t/t4014-format-patch.sh |  144 ++++++++++++++++++++++++++++++++++-------------\n 1 files changed, 104 insertions(+), 40 deletions(-)\n\ndiff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh\nindex f045898..345e6de 100755\n--- a/t/t4014-format-patch.sh\n+++ b/t/t4014-format-patch.sh\n@@ -138,56 +138,120 @@ test_expect_success 'multiple files' '\n \tls patches/0001-Side-changes-1.patch patches/0002-Side-changes-2.patch patches/0003-Side-changes-3-with-n-backslash-n-in-it.patch\n '\n \n-test_expect_success 'thread' '\n+check_threading () {\n+\texpect=\"$1\" &&\n+\tshift &&\n+\t(git format-patch --stdout \"$@\"; echo $? > status.out) |\n+\t# Prints everything between the Message-ID and In-Reply-To,\n+\t# and replaces all Message-ID-lookalikes by a sequence number\n+\tperl -ne '\n+\t\tif (/^(message-id|references|in-reply-to)/i) {\n+\t\t\t$printing = 1;\n+\t\t} elsif (/^\\S/) {\n+\t\t\t$printing = 0;\n+\t\t}\n+\t\tif ($printing) {\n+\t\t\t$h{$1}=$i++ if (/<([^>]+)>/ and !exists $h{$1});\n+\t\t\tfor $k (keys %h) {s/$k/$h{$k}/};\n+\t\t\tprint;\n+\t\t}\n+\t\tprint \"---\\n\" if /^From /i;\n+\t' > actual &&\n+\ttest 0 = \"$(cat status.out)\" &&\n+\ttest_cmp \"$expect\" actual\n+}\n+\n+cat >> expect.no-threading <<EOF\n+---\n+---\n+---\n+EOF\n \n-\trm -rf patches/ &&\n+test_expect_success 'no threading' '\n \tgit checkout side &&\n-\tgit format-patch --thread -o patches/ master &&\n-\tFIRST_MID=$(grep \"Message-Id:\" patches/0001-* | sed \"s/^[^<]*\\(<[^>]*>\\).*$/\\1/\") &&\n-\tfor i in patches/0002-* patches/0003-*\n-\tdo\n-\t  grep \"References: $FIRST_MID\" $i &&\n-\t  grep \"In-Reply-To: $FIRST_MID\" $i || break\n-\tdone\n+\tcheck_threading expect.no-threading master\n '\n \n-test_expect_success 'thread in-reply-to' '\n+cat > expect.thread <<EOF\n+---\n+Message-Id: <0>\n+---\n+Message-Id: <1>\n+In-Reply-To: <0>\n+References: <0>\n+---\n+Message-Id: <2>\n+In-Reply-To: <0>\n+References: <0>\n+EOF\n \n-\trm -rf patches/ &&\n-\tgit checkout side &&\n-\tgit format-patch --in-reply-to=\"<test.message>\" --thread -o patches/ master &&\n-\tFIRST_MID=\"<test.message>\" &&\n-\tfor i in patches/*\n-\tdo\n-\t  grep \"References: $FIRST_MID\" $i &&\n-\t  grep \"In-Reply-To: $FIRST_MID\" $i || break\n-\tdone\n+test_expect_success 'thread' '\n+\tcheck_threading expect.thread --thread master\n '\n \n-test_expect_success 'thread cover-letter' '\n+cat > expect.in-reply-to <<EOF\n+---\n+Message-Id: <0>\n+In-Reply-To: <1>\n+References: <1>\n+---\n+Message-Id: <2>\n+In-Reply-To: <1>\n+References: <1>\n+---\n+Message-Id: <3>\n+In-Reply-To: <1>\n+References: <1>\n+EOF\n \n-\trm -rf patches/ &&\n-\tgit checkout side &&\n-\tgit format-patch --cover-letter --thread -o patches/ master &&\n-\tFIRST_MID=$(grep \"Message-Id:\" patches/0000-* | sed \"s/^[^<]*\\(<[^>]*>\\).*$/\\1/\") &&\n-\tfor i in patches/0001-* patches/0002-* patches/0003-*\n-\tdo\n-\t  grep \"References: $FIRST_MID\" $i &&\n-\t  grep \"In-Reply-To: $FIRST_MID\" $i || break\n-\tdone\n+test_expect_success 'thread in-reply-to' '\n+\tcheck_threading expect.in-reply-to --in-reply-to=\"<test.message>\" \\\n+\t\t--thread master\n '\n \n-test_expect_success 'thread cover-letter in-reply-to' '\n+cat > expect.cover-letter <<EOF\n+---\n+Message-Id: <0>\n+---\n+Message-Id: <1>\n+In-Reply-To: <0>\n+References: <0>\n+---\n+Message-Id: <2>\n+In-Reply-To: <0>\n+References: <0>\n+---\n+Message-Id: <3>\n+In-Reply-To: <0>\n+References: <0>\n+EOF\n \n-\trm -rf patches/ &&\n-\tgit checkout side &&\n-\tgit format-patch --cover-letter --in-reply-to=\"<test.message>\" --thread -o patches/ master &&\n-\tFIRST_MID=\"<test.message>\" &&\n-\tfor i in patches/*\n-\tdo\n-\t  grep \"References: $FIRST_MID\" $i &&\n-\t  grep \"In-Reply-To: $FIRST_MID\" $i || break\n-\tdone\n+test_expect_success 'thread cover-letter' '\n+\tcheck_threading expect.cover-letter --cover-letter --thread master\n+'\n+\n+cat > expect.cl-irt <<EOF\n+---\n+Message-Id: <0>\n+In-Reply-To: <1>\n+References: <1>\n+---\n+Message-Id: <2>\n+In-Reply-To: <1>\n+References: <1>\n+---\n+Message-Id: <3>\n+In-Reply-To: <1>\n+References: <1>\n+---\n+Message-Id: <4>\n+In-Reply-To: <1>\n+References: <1>\n+EOF\n+\n+test_expect_success 'thread cover-letter in-reply-to' '\n+\tcheck_threading expect.cl-irt --cover-letter \\\n+\t\t--in-reply-to=\"<test.message>\" --thread master\n '\n \n test_expect_success 'excessive subject' '\n-- \n1.6.2.rc1.310.ga3b4a\n"},{"id":"105643","messageId":"456d13c294a3154f8200cf44e0f80963f1e09d9e.1235158956.git.trast@student.ethz.ch","threadId":"17795","inReplyTo":"cover.1235158956.git.trast@student.ethz.ch","subject":"[PATCH v2 next 2/4] format-patch: track several references","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-20T19:55:38Z","receivedAt":"2009-02-20T19:55:38Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Currently, format-patch can only track a single reference (the\nIn-Reply-To:) for each mail.  To ensure proper threading, we should\nlist all known references for every mail.\n\nReplace the rev_info.ref_message_id field by a string_list\nref_message_ids, so that we can append references at will, and change\nthe output formatting routines to print all of them in the References:\nheader.  The last entry in the list is implicitly assumed to be the\nIn-Reply-To:, which gives output consistent with RFC 2822:\n\n   The \"References:\" field will contain the contents of the parent's\n   \"References:\" field (if any) followed by the contents of the\n   parent's \"Message-ID:\" field (if any).\n\nNote that this is just preparatory work; nothing uses it yet, so all\n\"References:\" fields in the output are still only one deep.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nChanged 'ref_message_id' to 'ref_message_ids' as per Daniel's\nsuggestion.  Adjusted the commit message accordingly.\n\n builtin-log.c |   14 ++++++++++----\n log-tree.c    |   11 ++++++++---\n revision.h    |    2 +-\n 3 files changed, 19 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin-log.c b/builtin-log.c\nindex 8549028..1d7cf2f 100644\n--- a/builtin-log.c\n+++ b/builtin-log.c\n@@ -17,6 +17,7 @@\n #include \"run-command.h\"\n #include \"shortlog.h\"\n #include \"remote.h\"\n+#include \"string-list.h\"\n \n /* Set a default date-time format for git log (\"log.date\" config variable) */\n static const char *default_date_mode = NULL;\n@@ -1030,8 +1031,12 @@ 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-\tif (in_reply_to)\n-\t\trev.ref_message_id = clean_message_id(in_reply_to);\n+\tif (in_reply_to || thread || cover_letter)\n+\t\trev.ref_message_ids = xcalloc(1, sizeof(struct string_list));\n+\tif (in_reply_to) {\n+\t\tconst char *msgid = clean_message_id(in_reply_to);\n+\t\tstring_list_append(msgid, rev.ref_message_ids);\n+\t}\n \tif (cover_letter) {\n \t\tif (thread)\n \t\t\tgen_message_id(&rev, \"cover\");\n@@ -1055,10 +1060,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\t\t\t * otherwise, make everything a reply\n \t\t\t\t * to that.\n \t\t\t\t */\n-\t\t\t\tif (rev.ref_message_id)\n+\t\t\t\tif (rev.ref_message_ids->nr > 0)\n \t\t\t\t\tfree(rev.message_id);\n \t\t\t\telse\n-\t\t\t\t\trev.ref_message_id = rev.message_id;\n+\t\t\t\t\tstring_list_append(rev.message_id,\n+\t\t\t\t\t\t\t   rev.ref_message_ids);\n \t\t\t}\n \t\t\tgen_message_id(&rev, sha1_to_hex(commit->object.sha1));\n \t\t}\ndiff --git a/log-tree.c b/log-tree.c\nindex 84a74e5..a315ebb 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -6,6 +6,7 @@\n #include \"log-tree.h\"\n #include \"reflog-walk.h\"\n #include \"refs.h\"\n+#include \"string-list.h\"\n \n struct decoration name_decoration = { \"object names\" };\n \n@@ -211,9 +212,13 @@ void log_write_email_headers(struct rev_info *opt, const char *name,\n \t\tprintf(\"Message-Id: <%s>\\n\", opt->message_id);\n \t\tgraph_show_oneline(opt->graph);\n \t}\n-\tif (opt->ref_message_id) {\n-\t\tprintf(\"In-Reply-To: <%s>\\nReferences: <%s>\\n\",\n-\t\t       opt->ref_message_id, opt->ref_message_id);\n+\tif (opt->ref_message_ids && opt->ref_message_ids->nr > 0) {\n+\t\tint i, n;\n+\t\tn = opt->ref_message_ids->nr;\n+\t\tprintf(\"In-Reply-To: <%s>\\n\", opt->ref_message_ids->items[n-1].string);\n+\t\tfor (i = 0; i < n; i++)\n+\t\t\tprintf(\"%s<%s>\\n\", (i > 0 ? \"\\t\" : \"References: \"),\n+\t\t\t       opt->ref_message_ids->items[i].string);\n \t\tgraph_show_oneline(opt->graph);\n \t}\n \tif (opt->mime_boundary) {\ndiff --git a/revision.h b/revision.h\nindex 7cf8487..8c0a417 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -89,7 +89,7 @@ struct rev_info {\n \tint\t\tnr, total;\n \tconst char\t*mime_boundary;\n \tchar\t\t*message_id;\n-\tconst char\t*ref_message_id;\n+\tstruct string_list *ref_message_ids;\n \tconst char\t*add_signoff;\n \tconst char\t*extra_headers;\n \tconst char\t*log_reencode;\n-- \n1.6.2.rc1.310.ga3b4a\n"},{"id":"105644","messageId":"d0adbe1d8b07b245a5b71fd7d337a6be50fb2064.1235158956.git.trast@student.ethz.ch","threadId":"17795","inReplyTo":"cover.1235158956.git.trast@student.ethz.ch","subject":"[PATCH v2 next 3/4] format-patch: thread as reply to cover letter even with in-reply-to","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-20T19:55:39Z","receivedAt":"2009-02-20T19:55:39Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"Currently, format-patch --thread --cover-letter --in-reply-to $parent\nmakes all mails, including the cover letter, a reply to $parent.\nHowever, we would want the reader to consider the cover letter above\nall the patches.\n\nThis changes the semantics so that only the cover letter is a reply to\n$parent, while all the patches are formatted as replies to the cover\nletter.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nSame as v1.\n\n builtin-log.c           |   20 +++++++++++++++-----\n t/t4014-format-patch.sh |    9 ++++++---\n 2 files changed, 21 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin-log.c b/builtin-log.c\nindex 1d7cf2f..2dc6c48 100644\n--- a/builtin-log.c\n+++ b/builtin-log.c\n@@ -1055,12 +1055,22 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\t\t/* Have we already had a message ID? */\n \t\t\tif (rev.message_id) {\n \t\t\t\t/*\n-\t\t\t\t * If we've got the ID to be a reply\n-\t\t\t\t * to, discard the current ID;\n-\t\t\t\t * otherwise, make everything a reply\n-\t\t\t\t * to that.\n+\t\t\t\t * Without --cover-letter and\n+\t\t\t\t * --in-reply-to, make every mail a\n+\t\t\t\t * reply to the one before.\n+\t\t\t\t *\n+\t\t\t\t * With --in-reply-to but no\n+\t\t\t\t * --cover-letter, make every mail a\n+\t\t\t\t * reply to the <reply-to>.\n+\t\t\t\t *\n+\t\t\t\t * With --cover-letter, make every\n+\t\t\t\t * mail but the cover letter a reply\n+\t\t\t\t * to the cover letter.  The cover\n+\t\t\t\t * letter is a reply to the\n+\t\t\t\t * --in-reply-to, if specified.\n \t\t\t\t */\n-\t\t\t\tif (rev.ref_message_ids->nr > 0)\n+\t\t\t\tif (rev.ref_message_ids->nr > 0\n+\t\t\t\t    && (!cover_letter || rev.nr > 1))\n \t\t\t\t\tfree(rev.message_id);\n \t\t\t\telse\n \t\t\t\t\tstring_list_append(rev.message_id,\ndiff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh\nindex 345e6de..8b970c3 100755\n--- a/t/t4014-format-patch.sh\n+++ b/t/t4014-format-patch.sh\n@@ -237,16 +237,19 @@ In-Reply-To: <1>\n References: <1>\n ---\n Message-Id: <2>\n-In-Reply-To: <1>\n+In-Reply-To: <0>\n References: <1>\n+\t<0>\n ---\n Message-Id: <3>\n-In-Reply-To: <1>\n+In-Reply-To: <0>\n References: <1>\n+\t<0>\n ---\n Message-Id: <4>\n-In-Reply-To: <1>\n+In-Reply-To: <0>\n References: <1>\n+\t<0>\n EOF\n \n test_expect_success 'thread cover-letter in-reply-to' '\n-- \n1.6.2.rc1.310.ga3b4a\n"},{"id":"105645","messageId":"e8e7b8a8a9f8bf5d6f96875745f5c54b216f84b3.1235158956.git.trast@student.ethz.ch","threadId":"17795","inReplyTo":"cover.1235158956.git.trast@student.ethz.ch","subject":"[PATCH v2 next 4/4] format-patch: support deep threading","fromName":"Thomas Rast","fromEmail":"trast@student.ethz.ch","sentAt":"2009-02-20T19:55:40Z","receivedAt":"2009-02-20T19:55:40Z","isPatch":true,"sender":{"key":"tr@thomasrast.ch","avatar":"https://avatars.githubusercontent.com/u/153510?v=4"},"body":"For deep threading mode, i.e., the mode that gives a thread structured\nlike\n\n  + [PATCH 0/n] Cover letter\n   `-+ [PATCH 1/n] First patch\n      `-+ [PATCH 2/n] Second patch\n         `-+ ...\n\nwe currently have to use 'git send-email --thread' (the default).  On\nthe other hand, format-patch also has a --thread option which gives\nshallow mode, i.e.,\n\n  + [PATCH 0/n] Cover letter\n  |-+ [PATCH 1/n] First patch\n  |-+ [PATCH 2/n] Second patch\n  ...\n\nTo reduce the confusion resulting from having two indentically named\nfeatures in different tools giving different results, let format-patch\ntake an optional argument '--thread=deep' that gives the same output\nas 'send-mail --thread'.  With no argument, or 'shallow', behave as\nbefore.  Also add a configuration variable format.thread with the same\nsemantics.\n\nSigned-off-by: Thomas Rast <trast@student.ethz.ch>\n---\n\nSame as v1.\n\n Documentation/config.txt           |   10 +++\n Documentation/git-format-patch.txt |   10 +++-\n builtin-log.c                      |   36 +++++++++--\n t/t4014-format-patch.sh            |  120 ++++++++++++++++++++++++++++++++++++\n 4 files changed, 170 insertions(+), 6 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 3117d65..cf835c4 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -690,6 +690,16 @@ format.pretty::\n \tSee linkgit:git-log[1], linkgit:git-show[1],\n \tlinkgit:git-whatchanged[1].\n \n+format.thread::\n+\tThe default threading style for 'git-format-patch'.  Can be\n+\teither a boolean value, `shallow` or `deep`.  'Shallow'\n+\tthreading makes every mail a reply to the head of the series,\n+\twhere the head is chosen from the cover letter, the\n+\t`\\--in-reply-to`, and the first patch mail, in this order.\n+\t'Deep' threading makes every mail a reply to the previous one.\n+\tA true boolean value is the same as `shallow`, and a false\n+\tvalue disables threading.\n+\n gc.aggressiveWindow::\n \tThe window size parameter used in the delta compression\n \talgorithm used by 'git-gc --aggressive'.  This defaults\ndiff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt\nindex e7ae8cf..c14e3ee 100644\n--- a/Documentation/git-format-patch.txt\n+++ b/Documentation/git-format-patch.txt\n@@ -127,10 +127,18 @@ include::diff-options.txt[]\n \twhich is the commit message and the patch itself in the\n \tsecond part, with \"Content-Disposition: inline\".\n \n---thread::\n+--thread[=<style>]::\n \tAdd In-Reply-To and References headers to make the second and\n \tsubsequent mails appear as replies to the first.  Also generates\n \tthe Message-Id header to reference.\n++\n+The optional <style> argument can be either `shallow` or `deep`.\n+'Shallow' threading makes every mail a reply to the head of the\n+series, where the head is chosen from the cover letter, the\n+`\\--in-reply-to`, and the first patch mail, in this order.  'Deep'\n+threading makes every mail a reply to the previous one.  If not\n+specified, defaults to the 'format.thread' configuration, or `shallow`\n+if that is not set.\n \n --in-reply-to=Message-Id::\n \tMake the first mail (or all the mails with --no-thread) appear as a\ndiff --git a/builtin-log.c b/builtin-log.c\nindex 2dc6c48..8684fcd 100644\n--- a/builtin-log.c\n+++ b/builtin-log.c\n@@ -462,6 +462,10 @@ static void add_header(const char *value)\n \textra_hdr[extra_hdr_nr++] = xstrndup(value, len);\n }\n \n+#define THREAD_SHALLOW 1\n+#define THREAD_DEEP 2\n+static int thread = 0;\n+\n static int git_format_config(const char *var, const char *value, void *cb)\n {\n \tif (!strcmp(var, \"format.headers\")) {\n@@ -498,7 +502,18 @@ static int git_format_config(const char *var, const char *value, void *cb)\n \t\t\tdefault_attach = xstrdup(git_version_string);\n \t\treturn 0;\n \t}\n-\n+\tif (!strcmp(var, \"format.thread\")) {\n+\t\tif (value && !strcasecmp(value, \"deep\")) {\n+\t\t\tthread = THREAD_DEEP;\n+\t\t\treturn 0;\n+\t\t}\n+\t\tif (value && !strcasecmp(value, \"shallow\")) {\n+\t\t\tthread = THREAD_SHALLOW;\n+\t\t\treturn 0;\n+\t\t}\n+\t\tthread = git_config_bool(var, value) && THREAD_SHALLOW;\n+\t\treturn 0;\n+\t}\n \n \treturn git_log_config(var, value, cb);\n }\n@@ -777,7 +792,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \tint numbered_files = 0;\t\t/* _just_ numbers */\n \tint subject_prefix = 0;\n \tint ignore_if_in_upstream = 0;\n-\tint thread = 0;\n \tint cover_letter = 0;\n \tint boundary_count = 0;\n \tint no_binary_diff = 0;\n@@ -879,8 +893,13 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\t}\n \t\telse if (!strcmp(argv[i], \"--ignore-if-in-upstream\"))\n \t\t\tignore_if_in_upstream = 1;\n-\t\telse if (!strcmp(argv[i], \"--thread\"))\n-\t\t\tthread = 1;\n+\t\telse if (!strcmp(argv[i], \"--thread\")\n+\t\t\t|| !strcmp(argv[i], \"--thread=shallow\"))\n+\t\t\tthread = THREAD_SHALLOW;\n+\t\telse if (!strcmp(argv[i], \"--thread=deep\"))\n+\t\t\tthread = THREAD_DEEP;\n+\t\telse if (!strcmp(argv[i], \"--no-thread\"))\n+\t\t\tthread = 0;\n \t\telse if (!prefixcmp(argv[i], \"--in-reply-to=\"))\n \t\t\tin_reply_to = argv[i] + 14;\n \t\telse if (!strcmp(argv[i], \"--in-reply-to\")) {\n@@ -1055,6 +1074,12 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\t\t/* Have we already had a message ID? */\n \t\t\tif (rev.message_id) {\n \t\t\t\t/*\n+\t\t\t\t * For deep threading: make every mail\n+\t\t\t\t * a reply to the previous one, no\n+\t\t\t\t * matter what other options are set.\n+\t\t\t\t *\n+\t\t\t\t * For shallow threading:\n+\t\t\t\t *\n \t\t\t\t * Without --cover-letter and\n \t\t\t\t * --in-reply-to, make every mail a\n \t\t\t\t * reply to the one before.\n@@ -1069,7 +1094,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\t\t\t * letter is a reply to the\n \t\t\t\t * --in-reply-to, if specified.\n \t\t\t\t */\n-\t\t\t\tif (rev.ref_message_ids->nr > 0\n+\t\t\t\tif (thread == THREAD_SHALLOW\n+\t\t\t\t    && rev.ref_message_ids->nr > 0\n \t\t\t\t    && (!cover_letter || rev.nr > 1))\n \t\t\t\t\tfree(rev.message_id);\n \t\t\t\telse\ndiff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh\nindex 8b970c3..ebfc4a6 100755\n--- a/t/t4014-format-patch.sh\n+++ b/t/t4014-format-patch.sh\n@@ -257,6 +257,126 @@ test_expect_success 'thread cover-letter in-reply-to' '\n \t\t--in-reply-to=\"<test.message>\" --thread master\n '\n \n+test_expect_success 'thread explicit shallow' '\n+\tcheck_threading expect.cl-irt --cover-letter \\\n+\t\t--in-reply-to=\"<test.message>\" --thread=shallow master\n+'\n+\n+cat > expect.deep <<EOF\n+---\n+Message-Id: <0>\n+---\n+Message-Id: <1>\n+In-Reply-To: <0>\n+References: <0>\n+---\n+Message-Id: <2>\n+In-Reply-To: <1>\n+References: <0>\n+\t<1>\n+EOF\n+\n+test_expect_success 'thread deep' '\n+\tcheck_threading expect.deep --thread=deep master\n+'\n+\n+cat > expect.deep-irt <<EOF\n+---\n+Message-Id: <0>\n+In-Reply-To: <1>\n+References: <1>\n+---\n+Message-Id: <2>\n+In-Reply-To: <0>\n+References: <1>\n+\t<0>\n+---\n+Message-Id: <3>\n+In-Reply-To: <2>\n+References: <1>\n+\t<0>\n+\t<2>\n+EOF\n+\n+test_expect_success 'thread deep in-reply-to' '\n+\tcheck_threading expect.deep-irt  --thread=deep \\\n+\t\t--in-reply-to=\"<test.message>\" master\n+'\n+\n+cat > expect.deep-cl <<EOF\n+---\n+Message-Id: <0>\n+---\n+Message-Id: <1>\n+In-Reply-To: <0>\n+References: <0>\n+---\n+Message-Id: <2>\n+In-Reply-To: <1>\n+References: <0>\n+\t<1>\n+---\n+Message-Id: <3>\n+In-Reply-To: <2>\n+References: <0>\n+\t<1>\n+\t<2>\n+EOF\n+\n+test_expect_success 'thread deep cover-letter' '\n+\tcheck_threading expect.deep-cl --cover-letter --thread=deep master\n+'\n+\n+cat > expect.deep-cl-irt <<EOF\n+---\n+Message-Id: <0>\n+In-Reply-To: <1>\n+References: <1>\n+---\n+Message-Id: <2>\n+In-Reply-To: <0>\n+References: <1>\n+\t<0>\n+---\n+Message-Id: <3>\n+In-Reply-To: <2>\n+References: <1>\n+\t<0>\n+\t<2>\n+---\n+Message-Id: <4>\n+In-Reply-To: <3>\n+References: <1>\n+\t<0>\n+\t<2>\n+\t<3>\n+EOF\n+\n+test_expect_success 'thread deep cover-letter in-reply-to' '\n+\tcheck_threading expect.deep-cl-irt --cover-letter \\\n+\t\t--in-reply-to=\"<test.message>\" --thread=deep master\n+'\n+\n+test_expect_success 'thread via config' '\n+\tgit config format.thread true &&\n+\tcheck_threading expect.thread master\n+'\n+\n+test_expect_success 'thread deep via config' '\n+\tgit config format.thread deep &&\n+\tcheck_threading expect.deep master\n+'\n+\n+test_expect_success 'thread config + override' '\n+\tgit config format.thread deep &&\n+\tcheck_threading expect.thread --thread master\n+'\n+\n+test_expect_success 'thread config + --no-thread' '\n+\tgit config format.thread deep &&\n+\tcheck_threading expect.no-threading --no-thread master\n+'\n+\n test_expect_success 'excessive subject' '\n \n \trm -rf patches/ &&\n-- \n1.6.2.rc1.310.ga3b4a\n"},{"id":"105783","messageId":"7vocwu1knq.fsf@gitster.siamese.dyndns.org","threadId":"17795","inReplyTo":"cover.1235158956.git.trast@student.ethz.ch","subject":"Re: [PATCH v2 next 0/4] format-patch --cover-letter --in-reply-to","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-22T16:49:45Z","receivedAt":"2009-02-22T16:49:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thomas Rast <trast@student.ethz.ch> writes:\n\n> I also noticed that there is a textual conflict with 0db5260 (Enable\n> setting attach as the default in .gitconfig for git-format-patch.,\n> 2009-02-12), which is already in 'next'.  So I rebased the series to\n> 'next'.\n\nIn general I'd rather not to see a series based on 'next' merely for a\ntextual dependency like this (it is a different matter if your patch\nsemantically depends on somebody else's work in 'next').  Your own topic\nwill fork from 'master' and it will not want to be taken hostage of\n\"attach as default\" series.\n"}]}