{"thread":{"id":"21744","subject":"git send-email --notmuch expr","startedAt":"2009-11-25T02:49:59Z","lastAt":"2009-11-25T13:06:47Z","messageCount":5,"participants":["Jed Brown","Jakub Narebski"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"128277","messageId":"87d4375ne0.fsf@59A2.org","threadId":"21744","inReplyTo":null,"subject":"git send-email --notmuch expr","fromName":"Jed Brown","fromEmail":"jed@59a2.org","sentAt":"2009-11-25T02:49:59Z","receivedAt":"2009-11-25T02:49:59Z","isPatch":false,"sender":{"key":"jed@59a2.org","avatar":"https://gravatar.com/avatar/1391d04d82555f9058a9fdf5eead233e909a48e40480db31fc554e7afeb301da?d=mp&s=160"},"body":"Notmuch is a new mail system with fast indexing and tagging, see\nnotmuchmail.org.  It has a command-line tool to build replies to emails,\nand I wrote a patch to format-patch that enables\n\n  git format-patch --notmuch EXPR\n\nwhere EXPR is any notmuch query, but usually id:<Message-ID> to match a\nspecific message.  This will set up several headers, notably\nIn-Reply-To, References, To, Cc, Bcc.  This works great, and the the\npatch follows this message.\n\n\nBut I really want\n\n  git send-email --notmuch EXPR\n\nThis sort-of works, but the interactive part prompts for the various\nheaders (even though format-patch supplies them), and then duplicates\nthe To header (both the possibly empty field the user provided, plus the\none coming from format-patch).  I had a brief look at\ngit-send-email.perl, and I'm a little confused.\n\n\t} elsif (/^(?:To|Cc|Bcc):/i) {\n\t\tprint \"To/Cc/Bcc fields are not interpreted yet, they have been ignored\\n\";\n\t\tnext;\n\t}\n\nThis regex doesn't match these headers (is the leading ?: a typo?) so\nthere is no warning.  But it's important that these headers *not* be\nignored, getting them set automatically is a key feature of the\n--notmuch option.  I'm having trouble discerning whether I would cause\nproblems by just using these headers coming out of format-patch.\nPresumably there was a reason why they were (intended to be) explicitly\nignored, and my poor perl skills are not helping.  Could someone\nenlighten me?\n\n\nJed\n"},{"id":"128278","messageId":"1259117447-23052-1-git-send-email-jed@59A2.org","threadId":"21744","inReplyTo":"87d4375ne0.fsf@59A2.org","subject":"[PATCH 1/2] Added the --notmuch option to git format-patch.","fromName":"Jed Brown","fromEmail":"jed@59a2.org","sentAt":"2009-11-25T02:50:46Z","receivedAt":"2009-11-25T02:50:46Z","isPatch":true,"sender":{"key":"jed@59a2.org","avatar":"https://gravatar.com/avatar/1391d04d82555f9058a9fdf5eead233e909a48e40480db31fc554e7afeb301da?d=mp&s=160"},"body":"The typical use case for this is\n\n  git format-patch --notmuch id:<MESSAGE-ID>\n\nwhich will format your patch with all threading, references, and To, Cc\nfields appropriate for a reply to the given message.\n---\n builtin-log.c |   61 +++++++++++++++++++++++++++++++++++++++++++++++++++++---\n 1 files changed, 57 insertions(+), 4 deletions(-)\n\ndiff --git a/builtin-log.c b/builtin-log.c\nindex 33fa6ea..9a44955 100644\n--- a/builtin-log.c\n+++ b/builtin-log.c\n@@ -754,6 +754,53 @@ static const char *clean_message_id(const char *msg_id)\n \treturn xmemdupz(a, z - a);\n }\n \n+static int get_notmuch_reply(struct strbuf *buf, struct string_list *ref_message_ids, const char *query)\n+{\n+\tstruct child_process notmuch;\n+\tstruct strbuf notmuch_out;\n+\tchar *p, *other_headers, *rstart;\n+\tssize_t len;\n+\tconst char *argv[] = {\"notmuch\", \"reply\", \"--format=headers-only\", query, NULL};\n+\n+\tmemset(&notmuch, 0, sizeof(notmuch));\n+\n+\tnotmuch.argv\t = argv;\n+\tnotmuch.no_stdin = 1;\n+\tnotmuch.out\t = -1;\n+\n+\tif (start_command(&notmuch))\n+\t\treturn error(\"could not run notmuch.\");\n+\n+\tstrbuf_init(&notmuch_out, 4096);\n+\tlen = strbuf_read(&notmuch_out, notmuch.out, 4096);\n+\tclose(notmuch.out);\n+\n+\tif (finish_command(&notmuch) || !len || len < 0)\n+\t\treturn error(\"notmuch did not return any headers\");\n+\n+\t/* Harvest the referenced message IDs, all on the first line */\n+\tp = notmuch_out.buf;\n+\n+\tif (!strncmp(p, \"References: \", sizeof(\"References: \")))\n+\t\treturn error(\"notmuch response malformed\");\n+\n+\tother_headers = strstr(p, \"To: \");\n+\tif (!other_headers)\n+\t\treturn error(\"notmuch provided no other headers\");\n+\n+\twhile ((rstart = strchr(p, '<')) && (p = strchr(rstart, '>')) && p < other_headers-1) {\n+\t\tif (!p)\n+\t\t\terror(\"notmuch returned malformed references\");\n+\t\tp++;\n+\t\t*p++ = 0;\n+\t\tstring_list_append(clean_message_id(rstart), ref_message_ids);\n+\t}\n+\t/* Add everything after the first line */\n+\tstrbuf_addstr(buf, other_headers);\n+\tstrbuf_release(&notmuch_out);\n+\treturn 0;\n+}\n+\n static const char *set_outdir(const char *prefix, const char *output_directory)\n {\n \tif (output_directory && is_absolute_path(output_directory))\n@@ -893,7 +940,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \tint boundary_count = 0;\n \tint no_binary_diff = 0;\n \tstruct commit *origin = NULL, *head = NULL;\n-\tconst char *in_reply_to = NULL;\n+\tconst char *in_reply_to = NULL, *notmuch = NULL;\n \tstruct patch_ids ids;\n \tchar *add_signoff = NULL;\n \tstruct strbuf buf = STRBUF_INIT;\n@@ -940,6 +987,8 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\t\t    PARSE_OPT_NONEG, cc_callback },\n \t\tOPT_STRING(0, \"in-reply-to\", &in_reply_to, \"message-id\",\n \t\t\t    \"make first mail a reply to <message-id>\"),\n+\t\tOPT_STRING(0, \"notmuch\", &notmuch, \"query\",\n+\t\t\t    \"make first mail a reply to messages matched by <query>\"),\n \t\t{ OPTION_CALLBACK, 0, \"attach\", &rev, \"boundary\",\n \t\t\t    \"attach the patch\", PARSE_OPT_OPTARG,\n \t\t\t    attach_callback },\n@@ -1015,8 +1064,6 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \t\tstrbuf_addch(&buf, '\\n');\n \t}\n \n-\trev.extra_headers = strbuf_detach(&buf, NULL);\n-\n \tif (start_number < 0)\n \t\tstart_number = 1;\n \n@@ -1135,12 +1182,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-\tif (in_reply_to || thread || cover_letter)\n+\tif (in_reply_to || thread || cover_letter || notmuch)\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 (notmuch) {\n+\t\tget_notmuch_reply(&buf, rev.ref_message_ids, notmuch);\n+\t}\n+\n+\trev.extra_headers = strbuf_detach(&buf, NULL);\n+\n \trev.numbered_files = numbered_files;\n \trev.patch_suffix = fmt_patch_suffix;\n \tif (cover_letter) {\n-- \n1.6.5.3\n"},{"id":"128279","messageId":"1259117447-23052-2-git-send-email-jed@59A2.org","threadId":"21744","inReplyTo":"1259117447-23052-1-git-send-email-jed@59A2.org","subject":"[PATCH 2/2] Documentation for format-patch --notmuch.","fromName":"Jed Brown","fromEmail":"jed@59a2.org","sentAt":"2009-11-25T02:50:47Z","receivedAt":"2009-11-25T02:50:47Z","isPatch":true,"sender":{"key":"jed@59a2.org","avatar":"https://gravatar.com/avatar/1391d04d82555f9058a9fdf5eead233e909a48e40480db31fc554e7afeb301da?d=mp&s=160"},"body":"---\n Documentation/git-format-patch.txt |    7 +++++++\n 1 files changed, 7 insertions(+), 0 deletions(-)\n\ndiff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt\nindex f1fd0df..aaa472d 100644\n--- a/Documentation/git-format-patch.txt\n+++ b/Documentation/git-format-patch.txt\n@@ -171,6 +171,13 @@ will want to ensure that threading is disabled for `git send-email`.\n \tto any configured headers, and may be used multiple times.\n \tFor example, `--add-header=\"Organization: git-foo\"`\n \n+--notmuch=<expr>::\n+\tGenerate headers appropriate for a reply to a notmuch search for the\n+\tgiven expression.  Usually an expression of the form id:<Message-ID>\n+\twill be used to match an exact message.  The reply will set\n+\tIn-Reply-To, References, To, Cc, Bcc, and possibly other headers\n+\t(depending on notmuch configuration).\n+\n --cover-letter::\n \tIn addition to the patches, generate a cover letter file\n \tcontaining the shortlog and the overall diffstat.  You can\n-- \n1.6.5.3\n"},{"id":"128293","messageId":"m3hbsic3l5.fsf@localhost.localdomain","threadId":"21744","inReplyTo":"87d4375ne0.fsf@59A2.org","subject":"Re: git send-email --notmuch expr","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2009-11-25T10:16:52Z","receivedAt":"2009-11-25T10:16:52Z","isPatch":false,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Jed Brown <jed@59A2.org> writes:\n\n> \t} elsif (/^(?:To|Cc|Bcc):/i) {\n> \t\tprint \"To/Cc/Bcc fields are not interpreted yet, they have been ignored\\n\";\n> \t\tnext;\n> \t}\n> \n> This regex doesn't match these headers (is the leading ?: a typo?) so\n> there is no warning.\n\n(?: ... ) is in Perl non-capturing grouping\n\n>From perlre(1)\n\n  \"(?:pattern)\"\n  \"(?imsx-imsx:pattern)\"\n       This is for clustering, not capturing; it groups subexpressions\n       like \"()\", but doesn't make backreferences as \"()\" does.\n\nSo it is not a bug, and it definitely should match... unless implicit\nvariable $_ (the default input and pattern-searching space) got\nmangled.  It would be better to use explicit form:\n\n   $variable =~ /pattern/\n\n-- \nJakub Narebski\nPoland\nShadeHawk on #git\n"},{"id":"128305","messageId":"87aaya69eg.fsf@59A2.org","threadId":"21744","inReplyTo":"m3hbsic3l5.fsf@localhost.localdomain","subject":"Re: git send-email --notmuch expr","fromName":"Jed Brown","fromEmail":"jed@59a2.org","sentAt":"2009-11-25T13:06:47Z","receivedAt":"2009-11-25T13:06:47Z","isPatch":false,"sender":{"key":"jed@59a2.org","avatar":"https://gravatar.com/avatar/1391d04d82555f9058a9fdf5eead233e909a48e40480db31fc554e7afeb301da?d=mp&s=160"},"body":"On Wed, 25 Nov 2009 02:16:52 -0800 (PST), Jakub Narebski <jnareb@gmail.com> wrote:\n> (?: ... ) is in Perl non-capturing grouping\n\nThanks.  Actually that code only executes under --compose, the headers\nprovided by format-patch all just come through untouched (but all the\ninteresting ones are duplicated).  So it looks like we just need to\nactually parse the relevant headers from format-patch, before the part\nwhere the user gets prompted.  These are a little harder because they\ncan span multiple lines.  The current validation with --compose is a bit\nbroken: suppose the user sets the perfectly valid header\n\nTo: foo@example.com,\n    bar@example.com\n\nThe validation will strip the first line while issuing warning, but\nsend the second through untouched.\n\nJed\n"}]}