{"thread":{"id":"39539","subject":"[PATCH v2 0/2] specify commit by negative pattern","startedAt":"2015-06-06T00:24:53Z","lastAt":"2016-02-01T21:42:02Z","messageCount":26,"participants":["Will Palmer","Junio C Hamano","Stephen Smith","Stephen & Linda Smith","Duy Nguyen","Stephen P. Smith","Philip Oakley"],"isPatch":true,"patchVersion":2,"patchTotal":2},"messages":[{"id":"263076","messageId":"1433550295-15098-1-git-send-email-wmpalmer@gmail.com","threadId":"39539","inReplyTo":null,"subject":"[PATCH v2 0/2] specify commit by negative pattern","fromName":"Will Palmer","fromEmail":"wmpalmer@gmail.com","sentAt":"2015-06-06T00:24:53Z","receivedAt":"2015-06-06T00:24:53Z","isPatch":true,"sender":{"key":"wmpalmer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/357044?v=4"},"body":"add support for negative pattern matching in @^{/<pattern>} style\nrevision specifiers. So now you can find the first commit whose message\ndoesn't match a pattern, complementing the existing positive matching.\ne.g.:\n\n    $ git rebase -i @^{/!-^WIP}\n\nMy use-case is in having a \"work, work, work, rebase, push\"-style\nworkflow, which generates a lot of \"WIP foo\" commits. While rebasing is\nusually handled via \"git rebase -i origin/master\", occasionally I will\nalready have several \"good, but not yet ready to push\" commits hanging\naround while I finish work on related commits. In these situations, the\nability to quickly \"git diff @^{/!-^WIP}\" to get an overview of all\nchanges \"since the last one I was happy with\", can be useful.\n\nThis is the second version of the patch series. The previous attempt\nused the notation @^{/!WIP}, rather than @^{/!-WIP}, so the \"modifier\"\nwas the '!' character. Now, '!' is taken as an indicator that the\npattern is to be interpreted differently, and '-' is taken as an\nindicator of how it is to be interpreted differently. This follows\nrecent discussion with \"Junio C Hamano\" <gitster@pobox.com> and much-less\nrecent discussion archived at:\n\nhttp://thread.gmane.org/gmane.comp.version-control.git/40460/focus=40477\n\nIn summary, '!' is to be used as an \"escape hatch\", for further\nextension of the \"name commit by pattern\" functionality. Theorised future\nextensions indicated things like \"what was to be searched\",\ne.g.: @^{/!(a=author)}.  With only two interpretations of the '!'\nleader, for now (including the '!!' literal notation), adding such a\nverbose form, such as '@^{/!(negative)foo}', seemed inappropriate at this\ntime. In the event that such verbose forms are ever implemented, this new\nform may act as a shorthand, for a basic case.\n\nWill Palmer (2):\n  test for '!' handling in rev-parse's named commits\n  object name: introduce '^{/!-<negative pattern>}' notation\n\n Documentation/revisions.txt | 11 +++++-----\n sha1_name.c                 | 20 ++++++++++++-----\n t/t1511-rev-parse-caret.sh  | 53 ++++++++++++++++++++++++++++++++++++++++++++-\n 3 files changed, 73 insertions(+), 11 deletions(-)\n\n-- \n2.3.0.rc1\n"},{"id":"263078","messageId":"1433550295-15098-2-git-send-email-wmpalmer@gmail.com","threadId":"39539","inReplyTo":"1433550295-15098-1-git-send-email-wmpalmer@gmail.com","subject":"[PATCH v2 1/2] test for '!' handling in rev-parse's named commits","fromName":"Will Palmer","fromEmail":"wmpalmer@gmail.com","sentAt":"2015-06-06T00:24:54Z","receivedAt":"2015-06-06T00:24:54Z","isPatch":true,"sender":{"key":"wmpalmer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/357044?v=4"},"body":"In anticipation of extending this behaviour, add tests verifying the\nhandling of exclamation marks when looking up a commit \"by name\".\n\nSpecifically, as documented: '<rev>^{/!Message}' should fail, as the '!'\nprefix is reserved; while '<rev>^{!!Message}' should search for a commit\nwhose message contains the string \"!Message\".\n\nSigned-off-by: Will Palmer <wmpalmer@gmail.com>\n---\n t/t1511-rev-parse-caret.sh | 23 ++++++++++++++++++++++-\n 1 file changed, 22 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t1511-rev-parse-caret.sh b/t/t1511-rev-parse-caret.sh\nindex 15973f2..e0fe102 100755\n--- a/t/t1511-rev-parse-caret.sh\n+++ b/t/t1511-rev-parse-caret.sh\n@@ -18,7 +18,14 @@ test_expect_success 'setup' '\n \tgit checkout master &&\n \techo modified >>a-blob &&\n \tgit add -u &&\n-\tgit commit -m Modified\n+\tgit commit -m Modified &&\n+\techo changed! >>a-blob &&\n+\tgit add -u &&\n+\tgit commit -m !Exp &&\n+\tgit branch expref &&\n+\techo changed >>a-blob &&\n+\tgit add -u &&\n+\tgit commit -m Changed\n '\n \n test_expect_success 'ref^{non-existent}' '\n@@ -77,4 +84,18 @@ test_expect_success 'ref^{/Initial}' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'ref^{/!Exp}' '\n+\ttest_must_fail git rev-parse master^{/!Exp}\n+'\n+\n+test_expect_success 'ref^{/!}' '\n+\ttest_must_fail git rev-parse master^{/!}\n+'\n+\n+test_expect_success 'ref^{/!!Exp}' '\n+\tgit rev-parse expref >expected &&\n+\tgit rev-parse master^{/!!Exp} >actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_done\n-- \n2.3.0.rc1\n"},{"id":"263077","messageId":"1433550295-15098-3-git-send-email-wmpalmer@gmail.com","threadId":"39539","inReplyTo":"1433550295-15098-1-git-send-email-wmpalmer@gmail.com","subject":"[PATCH v2 2/2] object name: introduce '^{/!-<negative pattern>}' notation","fromName":"Will Palmer","fromEmail":"wmpalmer@gmail.com","sentAt":"2015-06-06T00:24:55Z","receivedAt":"2015-06-06T00:24:55Z","isPatch":true,"sender":{"key":"wmpalmer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/357044?v=4"},"body":"To name a commit, you can now say\n\n    $ git rev-parse HEAD^{/!-foo}\n\nand it will return the hash of the first commit reachable from HEAD,\nwhose commit message does not contain \"foo\". This is the opposite of the\nexisting <rev>^{/<pattern>} syntax.\n\nThe specific use-case this is intended for is to perform an operation,\nexcluding the most-recent commits containing a particular marker. For\nexample, if you tend to make \"work in progress\" commits, with messages\nbeginning with \"WIP\", you work, then it could be useful to diff against\n\"the most recent commit which was not a WIP commit\". That sort of thing\nnow possible, via commands such as:\n\n    $ git diff @^{/!-^WIP}\n\nThe leader '/!-', rather than simply '/!', to denote a negative match,\nis chosen to leave room for additional modifiers in the future.\n\nSigned-off-by: Will Palmer <wmpalmer@gmail.com>\n---\n Documentation/revisions.txt | 11 ++++++-----\n sha1_name.c                 | 20 +++++++++++++++-----\n t/t1511-rev-parse-caret.sh  | 32 +++++++++++++++++++++++++++++++-\n 3 files changed, 52 insertions(+), 11 deletions(-)\n\ndiff --git a/Documentation/revisions.txt b/Documentation/revisions.txt\nindex d85e303..0c84d4f 100644\n--- a/Documentation/revisions.txt\n+++ b/Documentation/revisions.txt\n@@ -176,11 +176,12 @@ existing tag object.\n   A colon, followed by a slash, followed by a text, names\n   a commit whose commit message matches the specified regular expression.\n   This name returns the youngest matching commit which is\n-  reachable from any ref.  If the commit message starts with a\n-  '!' you have to repeat that;  the special sequence ':/!',\n-  followed by something else than '!', is reserved for now.\n-  The regular expression can match any part of the commit message. To\n-  match messages starting with a string, one can use e.g. ':/^foo'.\n+  reachable from any ref. The regular expression can match any part of the\n+  commit message. To match messages starting with a string, one can use\n+  e.g. ':/^foo'. The special sequence ':/!' is reserved for modifiers to what\n+  is matched. ':/!-foo' performs a negative match, while ':/!!foo' matches a\n+  literal '!' character, followed by 'foo'. Any other sequence beginning with\n+  ':/!' is reserved for now.\n \n '<rev>:<path>', e.g. 'HEAD:README', ':README', 'master:./README'::\n   A suffix ':' followed by a path names the blob or tree\ndiff --git a/sha1_name.c b/sha1_name.c\nindex e57513e..82de2db 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -838,8 +838,12 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned l\n  * through history and returning the first commit whose message starts\n  * the given regular expression.\n  *\n- * For future extension, ':/!' is reserved. If you want to match a message\n- * beginning with a '!', you have to repeat the exclamation mark.\n+ * For negative-matching, prefix the pattern-part with '!-', like: ':/!-WIP'.\n+ *\n+ * For a literal '!' character at the beginning of a pattern, you have to repeat\n+ * that, like: ':/!!foo'\n+ *\n+ * For future extension, all other sequences beginning with ':/!' are reserved.\n  */\n \n /* Remember to update object flag allocation in object.h */\n@@ -868,12 +872,18 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,\n {\n \tstruct commit_list *backup = NULL, *l;\n \tint found = 0;\n+\tint negative = 0;\n \tregex_t regex;\n \n \tif (prefix[0] == '!') {\n-\t\tif (prefix[1] != '!')\n-\t\t\tdie (\"Invalid search pattern: %s\", prefix);\n \t\tprefix++;\n+\n+\t\tif (prefix[0] == '-') {\n+\t\t\tprefix++;\n+\t\t\tnegative = 1;\n+\t\t} else if (prefix[0] != '!') {\n+\t\t\tdie (\"Invalid search pattern: %s\", prefix);\n+\t\t}\n \t}\n \n \tif (regcomp(&regex, prefix, REG_EXTENDED))\n@@ -893,7 +903,7 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,\n \t\t\tcontinue;\n \t\tbuf = get_commit_buffer(commit, NULL);\n \t\tp = strstr(buf, \"\\n\\n\");\n-\t\tmatches = p && !regexec(&regex, p + 2, 0, NULL, 0);\n+\t\tmatches = p && (negative ^ !regexec(&regex, p + 2, 0, NULL, 0));\n \t\tunuse_commit_buffer(commit, buf);\n \n \t\tif (matches) {\ndiff --git a/t/t1511-rev-parse-caret.sh b/t/t1511-rev-parse-caret.sh\nindex e0fe102..8a5983f 100755\n--- a/t/t1511-rev-parse-caret.sh\n+++ b/t/t1511-rev-parse-caret.sh\n@@ -19,13 +19,17 @@ test_expect_success 'setup' '\n \techo modified >>a-blob &&\n \tgit add -u &&\n \tgit commit -m Modified &&\n+\tgit branch modref &&\n \techo changed! >>a-blob &&\n \tgit add -u &&\n \tgit commit -m !Exp &&\n \tgit branch expref &&\n \techo changed >>a-blob &&\n \tgit add -u &&\n-\tgit commit -m Changed\n+\tgit commit -m Changed &&\n+\techo changed-again >>a-blob &&\n+\tgit add -u &&\n+\tgit commit -m Changed-again\n '\n \n test_expect_success 'ref^{non-existent}' '\n@@ -98,4 +102,30 @@ test_expect_success 'ref^{/!!Exp}' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'ref^{/!-}' '\n+\ttest_must_fail git rev-parse master^{/!-}\n+'\n+\n+test_expect_success 'ref^{/!-.}' '\n+\ttest_must_fail git rev-parse master^{/!-.}\n+'\n+\n+test_expect_success 'ref^{/!-non-existent}' '\n+\tgit rev-parse master >expected &&\n+\tgit rev-parse master^{/!-non-existent} >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'ref^{/!-Changed}' '\n+\tgit rev-parse expref >expected &&\n+\tgit rev-parse master^{/!-Changed} >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'ref^{/!-!Exp}' '\n+\tgit rev-parse modref >expected &&\n+\tgit rev-parse expref^{/!-!Exp} >actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_done\n-- \n2.3.0.rc1\n"},{"id":"263248","messageId":"xmqqbngqcfxd.fsf@gitster.dls.corp.google.com","threadId":"39539","inReplyTo":"1433550295-15098-3-git-send-email-wmpalmer@gmail.com","subject":"Re: [PATCH v2 2/2] object name: introduce '^{/!-<negative pattern>}' notation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-06-08T16:39:58Z","receivedAt":"2015-06-08T16:39:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Will Palmer <wmpalmer@gmail.com> writes:\n\n> - * For future extension, ':/!' is reserved. If you want to match a message\n> - * beginning with a '!', you have to repeat the exclamation mark.\n> + * For negative-matching, prefix the pattern-part with '!-', like: ':/!-WIP'.\n> + *\n> + * For a literal '!' character at the beginning of a pattern, you have to repeat\n> + * that, like: ':/!!foo'\n> + *\n> + * For future extension, all other sequences beginning with ':/!' are reserved.\n>   */\n\nGood.\n\n> diff --git a/t/t1511-rev-parse-caret.sh b/t/t1511-rev-parse-caret.sh\n> index e0fe102..8a5983f 100755\n> --- a/t/t1511-rev-parse-caret.sh\n> +++ b/t/t1511-rev-parse-caret.sh\n> @@ -19,13 +19,17 @@ test_expect_success 'setup' '\n>  \techo modified >>a-blob &&\n>  \tgit add -u &&\n>  \tgit commit -m Modified &&\n> +\tgit branch modref &&\n\nThis probably belongs to the previous step, no?\n\n> +test_expect_success 'ref^{/!-}' '\n> +\ttest_must_fail git rev-parse master^{/!-}\n> +'\n\nHmmmm, we must fail because...?  We are looking for something that\ndoes not contain an empty string, which by definition does not\nexist.\n\nFunny, but is correct ;-).\n\n\n> +test_expect_success 'ref^{/!-.}' '\n> +\ttest_must_fail git rev-parse master^{/!-.}\n> +'\n\nLikewise.  I however wonder if we catch a commit without any message\n(which you probably have to craft with either commit-tree or\nhash-object), but that falls into the \"curiosity\" not the\n\"practicality\" category.\n\n> +test_expect_success 'ref^{/!-non-existent}' '\n> +\tgit rev-parse master >expected &&\n> +\tgit rev-parse master^{/!-non-existent} >actual &&\n> +\ttest_cmp expected actual\n> +'\n\nOK.\n\n> +test_expect_success 'ref^{/!-Changed}' '\n> +\tgit rev-parse expref >expected &&\n> +\tgit rev-parse master^{/!-Changed} >actual &&\n> +\ttest_cmp expected actual\n> +'\n\nOK.\n\n> +test_expect_success 'ref^{/!-!Exp}' '\n> +\tgit rev-parse modref >expected &&\n> +\tgit rev-parse expref^{/!-!Exp} >actual &&\n> +\ttest_cmp expected actual\n> +'\n\nOK.\n\n>  test_done\n"},{"id":"263390","messageId":"CAAKF_ub5c+2vVmG161O6gnUUeEcNfDUMU=mtn+k0T8bC-9ZHPw@mail.gmail.com","threadId":"39539","inReplyTo":"xmqqbngqcfxd.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH v2 2/2] object name: introduce '^{/!-<negative pattern>}' notation","fromName":"Will Palmer","fromEmail":"wmpalmer@gmail.com","sentAt":"2015-06-09T18:14:23Z","receivedAt":"2015-06-09T18:14:23Z","isPatch":true,"sender":{"key":"wmpalmer@gmail.com","avatar":"https://avatars.githubusercontent.com/u/357044?v=4"},"body":"On Mon, Jun 8, 2015 at 5:39 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Will Palmer <wmpalmer@gmail.com> writes:\n>> diff --git a/t/t1511-rev-parse-caret.sh b/t/t1511-rev-parse-caret.sh\n>> index e0fe102..8a5983f 100755\n>> --- a/t/t1511-rev-parse-caret.sh\n>> +++ b/t/t1511-rev-parse-caret.sh\n>> @@ -19,13 +19,17 @@ test_expect_success 'setup' '\n>>       echo modified >>a-blob &&\n>>       git add -u &&\n>>       git commit -m Modified &&\n>> +     git branch modref &&\n>\n> This probably belongs to the previous step, no?\n\nAs it isn't referenced until the \"negative\" tests, I didn't bother adding\nit in the \"verify the way things are\" tests. Funny that it was mentioned,\nas I *did* originally have it in the first commit, but I moved it to the\ncommit in which it was first used, so that it would be easier to notice.\n\n>\n>> +test_expect_success 'ref^{/!-}' '\n>> +     test_must_fail git rev-parse master^{/!-}\n>> +'\n>\n> Hmmmm, we must fail because...?  We are looking for something that\n> does not contain an empty string, which by definition does not\n> exist.\n>\n> Funny, but is correct ;-).\n\n\nThis is left-over from the original patch's logic, which included a\nshort-circuit to avoid an empty regex (as per 4322842 \"get_sha1: handle\nspecial case $commit^{/}\")... which I now realise perhaps should\nhave been simply rephrased, rather than ommitted entirely.\n\nI feel like adding something like:\n8<----------------------------------------------------------------------\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -737,11 +737,15 @@ static int peel_onion(const char *name, int len,\nunsigned char *sha1)\n\n                /*\n                 * $commit^{/}. Some regex implementation may reject.\n-                * We don't need regex anyway. '' pattern always matches.\n+                * We don't need regex anyway. '' pattern always matches,\n+                * and '!' pattern never matches.\n                 */\n                if (sp[1] == '}')\n                        return 0;\n\n+               if (sp[1] == '!' && sp[2] == '-' && sp[3] == '}')\n+                       return -1;\n+\n                prefix = xstrndup(sp + 1, name + len - 1 - (sp + 1));\n                commit_list_insert((struct commit *)o, &list);\n                ret = get_sha1_oneline(prefix, sha1, list);\n\n---------------------------------------------------------------------->8\n...would be the wrong place for this short-circuit check, in light of\ndiscussion around extensibility; so, I'll see how it looks moving that\ninto get_sha1_oneline(...)\n\n>\n>\n>> +test_expect_success 'ref^{/!-.}' '\n>> +     test_must_fail git rev-parse master^{/!-.}\n>> +'\n>\n> Likewise.  I however wonder if we catch a commit without any message\n> (which you probably have to craft with either commit-tree or\n> hash-object), but that falls into the \"curiosity\" not the\n> \"practicality\" category.\n\nA commit with \"no message\" should indeed by returned by 'master^{/!-.}',\nor at least, that is the intent. This test is only meant to cover the\nresult of there being \"no matching commit\", however.\n\n\n\n\nIn summary: it looks like I'll be sending another one.\n"},{"id":"272428","messageId":"xmqq7fm6lw35.fsf@gitster.mtv.corp.google.com","threadId":"39539","inReplyTo":"CAAKF_ub5c+2vVmG161O6gnUUeEcNfDUMU=mtn+k0T8bC-9ZHPw@mail.gmail.com","subject":"Re: [PATCH v2 2/2] object name: introduce '^{/!-<negative pattern>}' notation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2015-10-28T17:52:14Z","receivedAt":"2015-10-28T17:52:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Will Palmer <wmpalmer@gmail.com> writes:\n\n> In summary: it looks like I'll be sending another one.\n\nHas anything happened to this topic since then?  I am asking\nprimarily because I want to decide if I should discard\nwp/sha1-name-negative-match topic from my tree [*1*].\n\nI think what it attempts to do is a worthy thing, and it is shame to\nsee the initial implementation and review cycles we have spent so\nfar go to waste.\n\n\n[Footnote]\n\n*1* Not that my dropping a topic from 'pu' means very much; a\n    dropped topic can still be submitted and requeued after all.\n"},{"id":"275522","messageId":"loom.20160108T065547-969@post.gmane.org","threadId":"39539","inReplyTo":"xmqqbngqcfxd.fsf@gitster.dls.corp.google.com","subject":"Re: [PATCH v2 2/2] object name: introduce '^{/!-<negativepattern>}' notation","fromName":"Stephen Smith","fromEmail":"ischis2@cox.net","sentAt":"2016-01-08T06:04:34Z","receivedAt":"2016-01-08T06:04:34Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"Junio C Hamano <gitster <at> pobox.com> writes:\n> >  \techo modified >>a-blob &&\n> >  \tgit add -u &&\n> >  \tgit commit -m Modified &&\n> > +\tgit branch modref &&\n> \n> This probably belongs to the previous step, no?\n> \nWhat did you mean by this comment?  I looked at the original patch and at \nWill's response to your comment and am not quite sure what was meant.\n\n> > +test_expect_success 'ref^{/!-}' '\n> > +\ttest_must_fail git rev-parse master^{/!-}\n> > +'\n> \nI plan on leaving this in.\n\n> > +test_expect_success 'ref^{/!-.}' '\n> > +\ttest_must_fail git rev-parse master^{/!-.}\n> > +'\n> \nI plan on leaving this in.\n"},{"id":"275567","messageId":"xmqq37u82apv.fsf@gitster.mtv.corp.google.com","threadId":"39539","inReplyTo":"loom.20160108T065547-969@post.gmane.org","subject":"Re: [PATCH v2 2/2] object name: introduce '^{/!-<negativepattern>}' notation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-08T18:21:48Z","receivedAt":"2016-01-08T18:21:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Stephen Smith <ischis2@cox.net> writes:\n\n> Junio C Hamano <gitster <at> pobox.com> writes:\n>> >  \techo modified >>a-blob &&\n>> >  \tgit add -u &&\n>> >  \tgit commit -m Modified &&\n>> > +\tgit branch modref &&\n>> \n>> This probably belongs to the previous step, no?\n>> \n> What did you mean by this comment?  I looked at the original patch and at \n> Will's response to your comment and am not quite sure what was meant.\n\nNotice that the title is [2/2], so there is [1/2], which turns out\nto be http://article.gmane.org/gmane.comp.version-control.git/270898\n\nThat patch updates the preparatory steps of the test script so that\n[2/2] have more commits and refs to work with to perform more tests.\n\nMarking the result of that \"Modified\" commit so that it can be\nreferenced later with a short name 'modref' is something that should\nhave done in [1/2], which added that new invocation of \"git commit\"\nto record that \"Modified\" commit, not in [2/2] as an afterthought\n\"Oh I created Modified commit in 1/2 so that I can use it in the\ntest in 2/2, but I forgot to give it a name, so I am adding a new\ninvocation of 'git branch' in this step\".\n\n>\n>> > +test_expect_success 'ref^{/!-}' '\n>> > +\ttest_must_fail git rev-parse master^{/!-}\n>> > +'\n>> \n> I plan on leaving this in.\n>\n>> > +test_expect_success 'ref^{/!-.}' '\n>> > +\ttest_must_fail git rev-parse master^{/!-.}\n>> > +'\n>> \n> I plan on leaving this in.\n"},{"id":"275590","messageId":"17299684.zSfrSa31Pt@thunderbird","threadId":"39539","inReplyTo":"loom.20160108T065547-969@post.gmane.org","subject":"Re: [PATCH v2 2/2] object name: introduce '^{/!-<negativepattern>}' notation","fromName":"Stephen & Linda Smith","fromEmail":"ischis2@cox.net","sentAt":"2016-01-09T01:55:21Z","receivedAt":"2016-01-09T01:55:21Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"\nOn Friday, January 08, 2016 10:21:48 AM Junio C Hamano wrote:\n> Stephen Smith <ischis2@cox.net> writes:\n> \n> > Junio C Hamano <gitster <at> pobox.com> writes:\n> >> >  \techo modified >>a-blob &&\n> >> >  \tgit add -u &&\n> >> >  \tgit commit -m Modified &&\n> >> > +\tgit branch modref &&\n> >> \n> >> This probably belongs to the previous step, no?\n> >> \n> > What did you mean by this comment?  I looked at the original patch and at \n> > Will's response to your comment and am not quite sure what was meant.\n> \n> Notice that the title is [2/2], so there is [1/2], which turns out\n> to be http://article.gmane.org/gmane.comp.version-control.git/270898\n> \nI had that patch but didn't connect it to your comment.   \n\n> That patch updates the preparatory steps of the test script so that\n> [2/2] have more commits and refs to work with to perform more tests.\n> \n> Marking the result of that \"Modified\" commit so that it can be\n> referenced later with a short name 'modref' is something that should\n> have done in [1/2], which added that new invocation of \"git commit\"\n> to record that \"Modified\" commit, not in [2/2] as an afterthought\n> \"Oh I created Modified commit in 1/2 so that I can use it in the\n> test in 2/2, but I forgot to give it a name, so I am adding a new\n> invocation of 'git branch' in this step\".\nYep makes sense.\n\n> \n> >\n> >> > +test_expect_success 'ref^{/!-}' '\n> >> > +\ttest_must_fail git rev-parse master^{/!-}\n> >> > +'\n> >> \n> > I plan on leaving this in.\n> >\n> >> > +test_expect_success 'ref^{/!-.}' '\n> >> > +\ttest_must_fail git rev-parse master^{/!-.}\n> >> > +'\n> >> \n> > I plan on leaving this in.\n"},{"id":"275591","messageId":"CACsJy8Dar9sCkTg_SQsDUOWYNQ1PHjmA0KcgrvpvmeY=yVXPMg@mail.gmail.com","threadId":"39539","inReplyTo":"loom.20160108T065547-969@post.gmane.org","subject":"Re: [PATCH v2 2/2] object name: introduce '^{/!-<negativepattern>}' notation","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-01-09T02:18:11Z","receivedAt":"2016-01-09T02:18:11Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, Jan 8, 2016 at 1:04 PM, Stephen Smith <ischis2@cox.net> wrote:\n>> > +test_expect_success 'ref^{/!-}' '\n>> > +   test_must_fail git rev-parse master^{/!-}\n>> > +'\n\nShouldn't it be ^{!/... instead of ^{/!... ? People could have a\npattern starting with \"!\" and /! will change its meaning. On the other\nhand, anything else after { is still reserved and can safely be used.\n-- \nDuy\n"},{"id":"275601","messageId":"1452392429-2578-1-git-send-email-ischis2@cox.net","threadId":"39539","inReplyTo":"xmqq37u82apv.fsf@gitster.mtv.corp.google.com","subject":"[PATCH V3 0/2] specify commit by negative pattern","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2016-01-10T02:20:29Z","receivedAt":"2016-01-10T02:20:29Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"Add support for negative pattern matching in  <at> ^{/<pattern>} style\nrevision specifiers. So now you can find the first commit whose message\ndoesn't match a pattern, complementing the existing positive matching.\ne.g.:\n\n    $ git rebase -i  <at> ^{/!-^WIP}\n\nMy use-case is in having a \"work, work, work, rebase, push\"-style\nworkflow, which generates a lot of \"WIP foo\" commits. While rebasing is\nusually handled via \"git rebase -i origin/master\", occasionally I will\nalready have several \"good, but not yet ready to push\" commits hanging\naround while I finish work on related commits. In these situations, the\nability to quickly \"git diff  <at> ^{/!-^WIP}\" to get an overview of all\nchanges \"since the last one I was happy with\", can be useful.\n\nThis is the second version of the patch series. The previous attempt\nused the notation  <at> ^{/!WIP}, rather than  <at> ^{/!-WIP}, so the \"modifier\"\nwas the '!' character. Now, '!' is taken as an indicator that the\npattern is to be interpreted differently, and '-' is taken as an\nindicator of how it is to be interpreted differently. This follows\nrecent discussion with \"Junio C Hamano\" <gitster <at> pobox.com> and much-less\nrecent discussion archived at:\n\nhttp://thread.gmane.org/gmane.comp.version-control.git/40460/focus=40477\n\nIn summary, '!' is to be used as an \"escape hatch\", for further\nextension of the \"name commit by pattern\" functionality. Theorised future\nextensions indicated things like \"what was to be searched\",\ne.g.:  <at> ^{/!(a=author)}.  With only two interpretations of the '!'\nleader, for now (including the '!!' literal notation), adding such a\nverbose form, such as ' <at> ^{/!(negative)foo}', seemed inappropriate at this\ntime. In the event that such verbose forms are ever implemented, this new\nform may act as a shorthand, for a basic case.\n\nWill Palmer (2):\n  test for '!' handling in rev-parse's named commits\n  object name: introduce '^{/!-<negative pattern>}' notation\n\n Documentation/revisions.txt | 11 +++++-----\n sha1_name.c                 | 20 ++++++++++++-----\n t/t1511-rev-parse-caret.sh  | 53 ++++++++++++++++++++++++++++++++++++++++++++-\n 3 files changed, 73 insertions(+), 11 deletions(-)\n\n-- \n2.7.0-rc2\n"},{"id":"275602","messageId":"1452392549-2656-1-git-send-email-ischis2@cox.net","threadId":"39539","inReplyTo":"1452392429-2578-1-git-send-email-ischis2@cox.net","subject":"[PATCH V3 1/2] test for '!' handling in rev-parse's named commits","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2016-01-10T02:22:29Z","receivedAt":"2016-01-10T02:22:29Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"From: Will Palmer <wmpalmer@gmail.com>\n\nIn anticipation of extending this behaviour, add tests verifying the\nhandling of exclamation marks when looking up a commit \"by name\".\n\nSpecifically, as documented: '<rev>^{/!Message}' should fail, as the '!'\nprefix is reserved; while '<rev>^{!!Message}' should search for a commit\nwhose message contains the string \"!Message\".\n\nSigned-off-by: Will Palmer <wmpalmer@gmail.com>\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n\nNotes:\n    Moved modref branch from 2/2 to the 1/2 patch as discussed in [1] and\n    [2].\n    \n    In [3] the suggestion was made to change ^{!/... to ^{/!.  The comment\n    notes that anything after { is reserved and can be used.\n    \n    The v2 commit mesage (which has been retained) noted that !Message\n    should fail as '!' is reserved where !!Message should search for a\n    string that contains !Message.\n    \n    Because of the commit note, I chose not to make the change from\n    ^{!/... to ^{/!..\n    \n    [1] http://article.gmane.org/gmane.comp.version-control.git/271071\n    [2] http://article.gmane.org/gmane.comp.version-control.git/283573\n    [3] http://article.gmane.org/gmane.comp.version-control.git/283597\n\n t/t1511-rev-parse-caret.sh | 24 +++++++++++++++++++++++-\n 1 file changed, 23 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t1511-rev-parse-caret.sh b/t/t1511-rev-parse-caret.sh\nindex 15973f2..b2f90be 100755\n--- a/t/t1511-rev-parse-caret.sh\n+++ b/t/t1511-rev-parse-caret.sh\n@@ -18,7 +18,15 @@ test_expect_success 'setup' '\n \tgit checkout master &&\n \techo modified >>a-blob &&\n \tgit add -u &&\n-\tgit commit -m Modified\n+\tgit commit -m Modified &&\n+\tgit branch modref &&\n+\techo changed! >>a-blob &&\n+\tgit add -u &&\n+\tgit commit -m !Exp &&\n+\tgit branch expref &&\n+\techo changed >>a-blob &&\n+\tgit add -u &&\n+\tgit commit -m Changed\n '\n \n test_expect_success 'ref^{non-existent}' '\n@@ -77,4 +85,18 @@ test_expect_success 'ref^{/Initial}' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'ref^{/!Exp}' '\n+\ttest_must_fail git rev-parse master^{/!Exp}\n+'\n+\n+test_expect_success 'ref^{/!}' '\n+\ttest_must_fail git rev-parse master^{/!}\n+'\n+\n+test_expect_success 'ref^{/!!Exp}' '\n+\tgit rev-parse expref >expected &&\n+\tgit rev-parse master^{/!!Exp} >actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_done\n-- \n2.7.0-rc2\n"},{"id":"275603","messageId":"1452392583-2708-1-git-send-email-ischis2@cox.net","threadId":"39539","inReplyTo":"1452392429-2578-1-git-send-email-ischis2@cox.net","subject":"[PATCH V3 2/2] object name: introduce '^{/!-<negative pattern>}' notation","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2016-01-10T02:23:03Z","receivedAt":"2016-01-10T02:23:03Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"From: Will Palmer <wmpalmer@gmail.com>\n\nTo name a commit, you can now say\n\n    $ git rev-parse HEAD^{/!-foo}\n\nand it will return the hash of the first commit reachable from HEAD,\nwhose commit message does not contain \"foo\". This is the opposite of the\nexisting <rev>^{/<pattern>} syntax.\n\nThe specific use-case this is intended for is to perform an operation,\nexcluding the most-recent commits containing a particular marker. For\nexample, if you tend to make \"work in progress\" commits, with messages\nbeginning with \"WIP\", you work, then it could be useful to diff against\n\"the most recent commit which was not a WIP commit\". That sort of thing\nnow possible, via commands such as:\n\n    $ git diff @^{/!-^WIP}\n\nThe leader '/!-', rather than simply '/!', to denote a negative match,\nis chosen to leave room for additional modifiers in the future.\n\nSigned-off-by: Will Palmer <wmpalmer@gmail.com>\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n\nNotes:\n    Moved modref branch from 2/2 to the 1/2 patch as discussed in [1] and\n    [2].\n    \n    [1] http://article.gmane.org/gmane.comp.version-control.git/271071\n    [2] http://article.gmane.org/gmane.comp.version-control.git/283573\n\n Documentation/revisions.txt | 11 ++++++-----\n sha1_name.c                 | 20 +++++++++++++++-----\n t/t1511-rev-parse-caret.sh  | 31 ++++++++++++++++++++++++++++++-\n 3 files changed, 51 insertions(+), 11 deletions(-)\n\ndiff --git a/Documentation/revisions.txt b/Documentation/revisions.txt\nindex d85e303..0c84d4f 100644\n--- a/Documentation/revisions.txt\n+++ b/Documentation/revisions.txt\n@@ -176,11 +176,12 @@ existing tag object.\n   A colon, followed by a slash, followed by a text, names\n   a commit whose commit message matches the specified regular expression.\n   This name returns the youngest matching commit which is\n-  reachable from any ref.  If the commit message starts with a\n-  '!' you have to repeat that;  the special sequence ':/!',\n-  followed by something else than '!', is reserved for now.\n-  The regular expression can match any part of the commit message. To\n-  match messages starting with a string, one can use e.g. ':/^foo'.\n+  reachable from any ref. The regular expression can match any part of the\n+  commit message. To match messages starting with a string, one can use\n+  e.g. ':/^foo'. The special sequence ':/!' is reserved for modifiers to what\n+  is matched. ':/!-foo' performs a negative match, while ':/!!foo' matches a\n+  literal '!' character, followed by 'foo'. Any other sequence beginning with\n+  ':/!' is reserved for now.\n \n '<rev>:<path>', e.g. 'HEAD:README', ':README', 'master:./README'::\n   A suffix ':' followed by a path names the blob or tree\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 892db21..a2c5303 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -848,8 +848,12 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned l\n  * through history and returning the first commit whose message starts\n  * the given regular expression.\n  *\n- * For future extension, ':/!' is reserved. If you want to match a message\n- * beginning with a '!', you have to repeat the exclamation mark.\n+ * For negative-matching, prefix the pattern-part with '!-', like: ':/!-WIP'.\n+ *\n+ * For a literal '!' character at the beginning of a pattern, you have to repeat\n+ * that, like: ':/!!foo'\n+ *\n+ * For future extension, all other sequences beginning with ':/!' are reserved.\n  */\n \n /* Remember to update object flag allocation in object.h */\n@@ -878,12 +882,18 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,\n {\n \tstruct commit_list *backup = NULL, *l;\n \tint found = 0;\n+\tint negative = 0;\n \tregex_t regex;\n \n \tif (prefix[0] == '!') {\n-\t\tif (prefix[1] != '!')\n-\t\t\tdie (\"Invalid search pattern: %s\", prefix);\n \t\tprefix++;\n+\n+\t\tif (prefix[0] == '-') {\n+\t\t\tprefix++;\n+\t\t\tnegative = 1;\n+\t\t} else if (prefix[0] != '!') {\n+\t\t\tdie (\"Invalid search pattern: %s\", prefix);\n+\t\t}\n \t}\n \n \tif (regcomp(&regex, prefix, REG_EXTENDED))\n@@ -903,7 +913,7 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,\n \t\t\tcontinue;\n \t\tbuf = get_commit_buffer(commit, NULL);\n \t\tp = strstr(buf, \"\\n\\n\");\n-\t\tmatches = p && !regexec(&regex, p + 2, 0, NULL, 0);\n+\t\tmatches = p && (negative ^ !regexec(&regex, p + 2, 0, NULL, 0));\n \t\tunuse_commit_buffer(commit, buf);\n \n \t\tif (matches) {\ndiff --git a/t/t1511-rev-parse-caret.sh b/t/t1511-rev-parse-caret.sh\nindex b2f90be..8a5983f 100755\n--- a/t/t1511-rev-parse-caret.sh\n+++ b/t/t1511-rev-parse-caret.sh\n@@ -26,7 +26,10 @@ test_expect_success 'setup' '\n \tgit branch expref &&\n \techo changed >>a-blob &&\n \tgit add -u &&\n-\tgit commit -m Changed\n+\tgit commit -m Changed &&\n+\techo changed-again >>a-blob &&\n+\tgit add -u &&\n+\tgit commit -m Changed-again\n '\n \n test_expect_success 'ref^{non-existent}' '\n@@ -99,4 +102,30 @@ test_expect_success 'ref^{/!!Exp}' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'ref^{/!-}' '\n+\ttest_must_fail git rev-parse master^{/!-}\n+'\n+\n+test_expect_success 'ref^{/!-.}' '\n+\ttest_must_fail git rev-parse master^{/!-.}\n+'\n+\n+test_expect_success 'ref^{/!-non-existent}' '\n+\tgit rev-parse master >expected &&\n+\tgit rev-parse master^{/!-non-existent} >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'ref^{/!-Changed}' '\n+\tgit rev-parse expref >expected &&\n+\tgit rev-parse master^{/!-Changed} >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'ref^{/!-!Exp}' '\n+\tgit rev-parse modref >expected &&\n+\tgit rev-parse expref^{/!-!Exp} >actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_done\n-- \n2.7.0-rc2\n"},{"id":"275609","messageId":"87DF51336FE74635921A8C6857125F8B@PhilipOakley","threadId":"39539","inReplyTo":"1452392429-2578-1-git-send-email-ischis2@cox.net","subject":"Re: [PATCH V3 0/2] specify commit by negative pattern","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":null,"receivedAt":"2016-01-10T11:00:46Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Stephen P. Smith\" <ischis2@cox.net>\n> Add support for negative pattern matching in  <at> ^{/<pattern>} style\n\nHas this become mangled by replacing the '@' with ' <at> ' ?\n\nWhen I look at the update to revisions.txt it doesn't look like its touching \nthe '@' description.\nIs this '@^' a new (for the documenation) combination. Or has the example \nconfused me?\n\n> revision specifiers. So now you can find the first commit whose message\n> doesn't match a pattern, complementing the existing positive matching.\n> e.g.:\n>\n>    $ git rebase -i  <at> ^{/!-^WIP}\n>\n> My use-case is in having a \"work, work, work, rebase, push\"-style\n> workflow, which generates a lot of \"WIP foo\" commits. While rebasing is\n> usually handled via \"git rebase -i origin/master\", occasionally I will\n> already have several \"good, but not yet ready to push\" commits hanging\n> around while I finish work on related commits. In these situations, the\n> ability to quickly \"git diff  <at> ^{/!-^WIP}\" to get an overview of all\n> changes \"since the last one I was happy with\", can be useful.\n>\n> This is the second version of the patch series. The previous attempt\n> used the notation  <at> ^{/!WIP}, rather than  <at> ^{/!-WIP}, so the \n> \"modifier\"\n> was the '!' character. Now, '!' is taken as an indicator that the\n> pattern is to be interpreted differently, and '-' is taken as an\n> indicator of how it is to be interpreted differently. This follows\n> recent discussion with \"Junio C Hamano\" <gitster <at> pobox.com> and \n> much-less\n> recent discussion archived at:\n>\n> http://thread.gmane.org/gmane.comp.version-control.git/40460/focus=40477\n>\n> In summary, '!' is to be used as an \"escape hatch\", for further\n> extension of the \"name commit by pattern\" functionality. Theorised future\n> extensions indicated things like \"what was to be searched\",\n> e.g.:  <at> ^{/!(a=author)}.  With only two interpretations of the '!'\n> leader, for now (including the '!!' literal notation), adding such a\n> verbose form, such as ' <at> ^{/!(negative)foo}', seemed inappropriate at \n> this\n> time. In the event that such verbose forms are ever implemented, this new\n> form may act as a shorthand, for a basic case.\n>\n> Will Palmer (2):\n>  test for '!' handling in rev-parse's named commits\n>  object name: introduce '^{/!-<negative pattern>}' notation\n>\n> Documentation/revisions.txt | 11 +++++-----\n> sha1_name.c                 | 20 ++++++++++++-----\n> t/t1511-rev-parse-caret.sh  | 53 \n> ++++++++++++++++++++++++++++++++++++++++++++-\n> 3 files changed, 73 insertions(+), 11 deletions(-)\n>\n--\nPhilip \n"},{"id":"275610","messageId":"1686181.AoEpo53h6D@thunderbird","threadId":"39539","inReplyTo":"1452392429-2578-1-git-send-email-ischis2@cox.net","subject":"Re: [PATCH V3 0/2] specify commit by negative pattern","fromName":"Stephen & Linda Smith","fromEmail":"ischis2@cox.net","sentAt":"2016-01-10T14:14:17Z","receivedAt":"2016-01-10T14:14:17Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"On Sunday, January 10, 2016 01:25:42 PM Philip Oakley wrote:\n> From: \"Stephen P. Smith\" <ischis2@cox.net>\n> > Add support for negative pattern matching in  <at> ^{/<pattern>} style\n> \n> Has this become mangled by replacing the '@' with ' <at> ' ?\nIt looks like the cover letter got mangled.  I will fix after I get any comments \non the patches themselves.\n\n> \n> When I look at the update to revisions.txt it doesn't look like its touching \n> the '@' description.\n> Is this '@^' a new (for the documenation) combination. Or has the example \n> confused me?\n> \n> > revision specifiers. So now you can find the first commit whose message\n> > doesn't match a pattern, complementing the existing positive matching.\n> > e.g.:\n> >\n> >    $ git rebase -i  <at> ^{/!-^WIP}\n> >\n> > My use-case is in having a \"work, work, work, rebase, push\"-style\n> > workflow, which generates a lot of \"WIP foo\" commits. While rebasing is\n> > usually handled via \"git rebase -i origin/master\", occasionally I will\n> > already have several \"good, but not yet ready to push\" commits hanging\n> > around while I finish work on related commits. In these situations, the\n> > ability to quickly \"git diff  <at> ^{/!-^WIP}\" to get an overview of all\n> > changes \"since the last one I was happy with\", can be useful.\n> >\n> > This is the second version of the patch series. The previous attempt\n> > used the notation  <at> ^{/!WIP}, rather than  <at> ^{/!-WIP}, so the \n> > \"modifier\"\n> > was the '!' character. Now, '!' is taken as an indicator that the\n> > pattern is to be interpreted differently, and '-' is taken as an\n> > indicator of how it is to be interpreted differently. This follows\n> > recent discussion with \"Junio C Hamano\" <gitster <at> pobox.com> and \n> > much-less\n> > recent discussion archived at:\n> >\n> > http://thread.gmane.org/gmane.comp.version-control.git/40460/focus=40477\n> >\n> > In summary, '!' is to be used as an \"escape hatch\", for further\n> > extension of the \"name commit by pattern\" functionality. Theorised future\n> > extensions indicated things like \"what was to be searched\",\n> > e.g.:  <at> ^{/!(a=author)}.  With only two interpretations of the '!'\n> > leader, for now (including the '!!' literal notation), adding such a\n> > verbose form, such as ' <at> ^{/!(negative)foo}', seemed inappropriate at \n> > this\n> > time. In the event that such verbose forms are ever implemented, this new\n> > form may act as a shorthand, for a basic case.\n> >\n> > Will Palmer (2):\n> >  test for '!' handling in rev-parse's named commits\n> >  object name: introduce '^{/!-<negative pattern>}' notation\n> >\n> > Documentation/revisions.txt | 11 +++++-----\n> > sha1_name.c                 | 20 ++++++++++++-----\n> > t/t1511-rev-parse-caret.sh  | 53 \n> > ++++++++++++++++++++++++++++++++++++++++++++-\n> > 3 files changed, 73 insertions(+), 11 deletions(-)\n> >\n> --\n> Philip \n> \n"},{"id":"275618","messageId":"72AF834F7D7B46D298EFE697EBF19E0E@PhilipOakley","threadId":"39539","inReplyTo":"1686181.AoEpo53h6D@thunderbird","subject":"Re: [PATCH V3 0/2] specify commit by negative pattern","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":null,"receivedAt":"2016-01-10T23:08:17Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Stephen & Linda Smith\" <ischis2@cox.net>\n> On Sunday, January 10, 2016 01:25:42 PM Philip Oakley wrote:\n>> From: \"Stephen P. Smith\" <ischis2@cox.net>\n>> > Add support for negative pattern matching in  <at> ^{/<pattern>} style\n>>\n>> Has this become mangled by replacing the '@' with ' <at> ' ?\n> It looks like the cover letter got mangled.  I will fix after I get any \n> comments\n> on the patches themselves.\n>\n\nI think I was also confused between the extra ways of spelling @ (listed \nfirst in revisions.txt), and the extra was of spelling <rev>, i.e. the \n<rev>^{/<text>}, and then in patch 2/2 it actually being the :/<text> \nsyntax.\n\n>>\n>> When I look at the update to revisions.txt it doesn't look like its \n>> touching\n>> the '@' description.\n>> Is this '@^' a new (for the documenation) combination. Or has the example\n>> confused me?\n>>\n>> > revision specifiers. So now you can find the first commit whose message\n>> > doesn't match a pattern, complementing the existing positive matching.\n>> > e.g.:\n>> >\n>> >    $ git rebase -i  <at> ^{/!-^WIP}\n>> >\n>> > My use-case is in having a \"work, work, work, rebase, push\"-style\n>> > workflow, which generates a lot of \"WIP foo\" commits. While rebasing is\n>> > usually handled via \"git rebase -i origin/master\", occasionally I will\n>> > already have several \"good, but not yet ready to push\" commits hanging\n>> > around while I finish work on related commits. In these situations, the\n>> > ability to quickly \"git diff  <at> ^{/!-^WIP}\" to get an overview of \n>> > all\n>> > changes \"since the last one I was happy with\", can be useful.\n>> >\n>> > This is the second version of the patch series. The previous attempt\n>> > used the notation  <at> ^{/!WIP}, rather than  <at> ^{/!-WIP}, so the\n>> > \"modifier\"\n>> > was the '!' character. Now, '!' is taken as an indicator that the\n>> > pattern is to be interpreted differently, and '-' is taken as an\n>> > indicator of how it is to be interpreted differently. This follows\n>> > recent discussion with \"Junio C Hamano\" <gitster <at> pobox.com> and\n>> > much-less\n>> > recent discussion archived at:\n>> >\n>> > http://thread.gmane.org/gmane.comp.version-control.git/40460/focus=40477\n>> >\n>> > In summary, '!' is to be used as an \"escape hatch\", for further\n>> > extension of the \"name commit by pattern\" functionality. Theorised \n>> > future\n>> > extensions indicated things like \"what was to be searched\",\n>> > e.g.:  <at> ^{/!(a=author)}.  With only two interpretations of the '!'\n>> > leader, for now (including the '!!' literal notation), adding such a\n>> > verbose form, such as ' <at> ^{/!(negative)foo}', seemed inappropriate \n>> > at\n>> > this\n>> > time. In the event that such verbose forms are ever implemented, this \n>> > new\n>> > form may act as a shorthand, for a basic case.\n>> >\n>> > Will Palmer (2):\n>> >  test for '!' handling in rev-parse's named commits\n>> >  object name: introduce '^{/!-<negative pattern>}' notation\n>> >\n>> > Documentation/revisions.txt | 11 +++++-----\n>> > sha1_name.c                 | 20 ++++++++++++-----\n>> > t/t1511-rev-parse-caret.sh  | 53\n>> > ++++++++++++++++++++++++++++++++++++++++++++-\n>> > 3 files changed, 73 insertions(+), 11 deletions(-)\n>> >\n>> --\n>> Philip\n>>\n>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n> \n"},{"id":"275619","messageId":"1452470880-8753-1-git-send-email-ischis2@cox.net","threadId":"39539","inReplyTo":"87DF51336FE74635921A8C6857125F8B@PhilipOakley","subject":"[PATCH V3 0/2] specify commit by negative pattern","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2016-01-11T00:08:00Z","receivedAt":"2016-01-11T00:08:00Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"Add support for negative pattern matching in @^{/<pattern>} style\nrevision specifiers. So now you can find the first commit whose message\ndoesn't match a pattern, complementing the existing positive matching.\ne.g.:\n\n    $ git rebase -i @^{/!-^WIP}\n\nMy use-case is in having a \"work, work, work, rebase, push\"-style\nworkflow, which generates a lot of \"WIP foo\" commits. While rebasing is\nusually handled via \"git rebase -i origin/master\", occasionally I will\nalready have several \"good, but not yet ready to push\" commits hanging\naround while I finish work on related commits. In these situations, the\nability to quickly \"git diff @^{/!-^WIP}\" to get an overview of all\nchanges \"since the last one I was happy with\", can be useful.\n\nThis is the second version of the patch series. The previous attempt\nused the notation @^{/!WIP}, rather than @^{/!-WIP}, so the \"modifier\"\nwas the '!' character. Now, '!' is taken as an indicator that the\npattern is to be interpreted differently, and '-' is taken as an\nindicator of how it is to be interpreted differently. This follows\nrecent discussion with \"Junio C Hamano\" <gitster@pobox.com> and much-less\nrecent discussion archived at:\n\nhttp://thread.gmane.org/gmane.comp.version-control.git/40460/focus=40477\n\nIn summary, '!' is to be used as an \"escape hatch\", for further\nextension of the \"name commit by pattern\" functionality. Theorised future\nextensions indicated things like \"what was to be searched\",\ne.g.: @^{/!(a=author)}.  With only two interpretations of the '!'\nleader, for now (including the '!!' literal notation), adding such a\nverbose form, such as '@^{/!(negative)foo}', seemed inappropriate at this\ntime. In the event that such verbose forms are ever implemented, this new\nform may act as a shorthand, for a basic case.\n\nWill Palmer (2):\n  test for '!' handling in rev-parse's named commits\n  object name: introduce '^{/!-<negative pattern>}' notation\n\n Documentation/revisions.txt | 11 +++++-----\n sha1_name.c                 | 20 ++++++++++++-----\n t/t1511-rev-parse-caret.sh  | 53 ++++++++++++++++++++++++++++++++++++++++++++-\n 3 files changed, 73 insertions(+), 11 deletions(-)\n\n-- \n2.7.0-rc2\n"},{"id":"275665","messageId":"xmqqpox8xcn6.fsf@gitster.mtv.corp.google.com","threadId":"39539","inReplyTo":"CACsJy8Dar9sCkTg_SQsDUOWYNQ1PHjmA0KcgrvpvmeY=yVXPMg@mail.gmail.com","subject":"Re: [PATCH v2 2/2] object name: introduce '^{/!-<negativepattern>}' notation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-11T17:13:33Z","receivedAt":"2016-01-11T17:13:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> On Fri, Jan 8, 2016 at 1:04 PM, Stephen Smith <ischis2@cox.net> wrote:\n>>> > +test_expect_success 'ref^{/!-}' '\n>>> > +   test_must_fail git rev-parse master^{/!-}\n>>> > +'\n>\n> Shouldn't it be ^{!/... instead of ^{/!... ? People could have a\n> pattern starting with \"!\" and /! will change its meaning. On the other\n> hand, anything else after { is still reserved and can safely be used.\n\nhttp://thread.gmane.org/gmane.comp.version-control.git/40460/focus=40477\nclarifies the above, I think.\n\n\nBack then we seem to have been thinking only about \":\" as the\noverall \"search the history to name an object traversing from all\ntips\" prefix, but the current one is described in terms of the more\ngenerally useful \"<committish>^{/<pattern>}\" syntax and the escape\nhatch applies--they are both handled by get_sha1_oneline() the same\nway.\n"},{"id":"275676","messageId":"9A32BC480D1F4BD38436CE498D062D0B@PhilipOakley","threadId":"39539","inReplyTo":"1452470880-8753-1-git-send-email-ischis2@cox.net","subject":"Re: [PATCH V3 0/2] specify commit by negative pattern","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":null,"receivedAt":"2016-01-11T17:59:19Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Stephen P. Smith\" <ischis2@cox.net>\n> Add support for negative pattern matching in\n\nperhaps\ns!in!in the :/<text> regex pattern style, and consequentially the!\n\nGiven that the documenation changes are there.\n\n>         @^{/<pattern>} style\n> revision specifiers. So now you can find the first commit whose message\n> doesn't match a pattern, complementing the existing positive matching.\n> e.g.:\n>\n>    $ git rebase -i @^{/!-^WIP}\n>\n> My use-case is in having a \"work, work, work, rebase, push\"-style\n> workflow, which generates a lot of \"WIP foo\" commits. While rebasing is\n> usually handled via \"git rebase -i origin/master\", occasionally I will\n> already have several \"good, but not yet ready to push\" commits hanging\n> around while I finish work on related commits. In these situations, the\n> ability to quickly \"git diff @^{/!-^WIP}\" to get an overview of all\n> changes \"since the last one I was happy with\", can be useful.\n>\n> This is the second version of the patch series. The previous attempt\n> used the notation @^{/!WIP}, rather than @^{/!-WIP}, so the \"modifier\"\n> was the '!' character. Now, '!' is taken as an indicator that the\n> pattern is to be interpreted differently, and '-' is taken as an\n> indicator of how it is to be interpreted differently. This follows\n> recent discussion with \"Junio C Hamano\" <gitster@pobox.com> and much-less\n> recent discussion archived at:\n>\n> http://thread.gmane.org/gmane.comp.version-control.git/40460/focus=40477\n>\n> In summary, '!' is to be used as an \"escape hatch\", for further\n> extension of the \"name commit by pattern\" functionality. Theorised future\n> extensions indicated things like \"what was to be searched\",\n> e.g.: @^{/!(a=author)}.  With only two interpretations of the '!'\n> leader, for now (including the '!!' literal notation), adding such a\n> verbose form, such as '@^{/!(negative)foo}', seemed inappropriate at this\n> time. In the event that such verbose forms are ever implemented, this new\n> form may act as a shorthand, for a basic case.\n>\n> Will Palmer (2):\n>  test for '!' handling in rev-parse's named commits\n>  object name: introduce '^{/!-<negative pattern>}' notation\n>\n> Documentation/revisions.txt | 11 +++++-----\n> sha1_name.c                 | 20 ++++++++++++-----\n> t/t1511-rev-parse-caret.sh  | 53 \n> ++++++++++++++++++++++++++++++++++++++++++++-\n> 3 files changed, 73 insertions(+), 11 deletions(-)\n>\n> -- \n> 2.7.0-rc2\n>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n> \n"},{"id":"275677","messageId":"ED12DDDA0C004D23BDDB14973C675800@PhilipOakley","threadId":"39539","inReplyTo":"1452392583-2708-1-git-send-email-ischis2@cox.net","subject":"Re: [PATCH V3 2/2] object name: introduce '^{/!-<negative pattern>}' notation","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":null,"receivedAt":"2016-01-11T17:59:19Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Stephen P. Smith\" <ischis2@cox.net>\n> From: Will Palmer <wmpalmer@gmail.com>\n>\n> To name a commit, you can now say\n\nperhaps\ns|say|use the :/!-<negative pattern> regex style, and consequentially, say|\n\nShould the patch subject line also be updated to reflect the change?\n\n>\n>    $ git rev-parse HEAD^{/!-foo}\n>\n> and it will return the hash of the first commit reachable from HEAD,\n> whose commit message does not contain \"foo\". This is the opposite of the\n> existing <rev>^{/<pattern>} syntax.\n>\n> The specific use-case this is intended for is to perform an operation,\n> excluding the most-recent commits containing a particular marker. For\n> example, if you tend to make \"work in progress\" commits, with messages\n> beginning with \"WIP\", you work, then it could be useful to diff against\n> \"the most recent commit which was not a WIP commit\". That sort of thing\n> now possible, via commands such as:\n>\n>    $ git diff @^{/!-^WIP}\n>\n> The leader '/!-', rather than simply '/!', to denote a negative match,\n> is chosen to leave room for additional modifiers in the future.\n>\n> Signed-off-by: Will Palmer <wmpalmer@gmail.com>\n> Signed-off-by: Stephen P. Smith <ischis2@cox.net>\n> ---\n>\n> Notes:\n>    Moved modref branch from 2/2 to the 1/2 patch as discussed in [1] and\n>    [2].\n>\n>    [1] http://article.gmane.org/gmane.comp.version-control.git/271071\n>    [2] http://article.gmane.org/gmane.comp.version-control.git/283573\n>\n> Documentation/revisions.txt | 11 ++++++-----\n> sha1_name.c                 | 20 +++++++++++++++-----\n> t/t1511-rev-parse-caret.sh  | 31 ++++++++++++++++++++++++++++++-\n> 3 files changed, 51 insertions(+), 11 deletions(-)\n>\n> diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt\n> index d85e303..0c84d4f 100644\n> --- a/Documentation/revisions.txt\n> +++ b/Documentation/revisions.txt\n> @@ -176,11 +176,12 @@ existing tag object.\n>   A colon, followed by a slash, followed by a text, names\n>   a commit whose commit message matches the specified regular expression.\n>   This name returns the youngest matching commit which is\n> -  reachable from any ref.  If the commit message starts with a\n> -  '!' you have to repeat that;  the special sequence ':/!',\n> -  followed by something else than '!', is reserved for now.\n> -  The regular expression can match any part of the commit message. To\n> -  match messages starting with a string, one can use e.g. ':/^foo'.\n> +  reachable from any ref. The regular expression can match any part of \n> the\n> +  commit message. To match messages starting with a string, one can use\n> +  e.g. ':/^foo'. The special sequence ':/!' is reserved for modifiers to \n> what\n> +  is matched. ':/!-foo' performs a negative match, while ':/!!foo' \n> matches a\n> +  literal '!' character, followed by 'foo'. Any other sequence beginning \n> with\n> +  ':/!' is reserved for now.\n>\n> '<rev>:<path>', e.g. 'HEAD:README', ':README', 'master:./README'::\n>   A suffix ':' followed by a path names the blob or tree\n> diff --git a/sha1_name.c b/sha1_name.c\n> index 892db21..a2c5303 100644\n> --- a/sha1_name.c\n> +++ b/sha1_name.c\n> @@ -848,8 +848,12 @@ static int get_sha1_1(const char *name, int len, \n> unsigned char *sha1, unsigned l\n>  * through history and returning the first commit whose message starts\n>  * the given regular expression.\n>  *\n> - * For future extension, ':/!' is reserved. If you want to match a \n> message\n> - * beginning with a '!', you have to repeat the exclamation mark.\n> + * For negative-matching, prefix the pattern-part with '!-', like: \n> ':/!-WIP'.\n> + *\n> + * For a literal '!' character at the beginning of a pattern, you have to \n> repeat\n> + * that, like: ':/!!foo'\n> + *\n> + * For future extension, all other sequences beginning with ':/!' are \n> reserved.\n>  */\n>\n> /* Remember to update object flag allocation in object.h */\n> @@ -878,12 +882,18 @@ static int get_sha1_oneline(const char *prefix, \n> unsigned char *sha1,\n> {\n>  struct commit_list *backup = NULL, *l;\n>  int found = 0;\n> + int negative = 0;\n>  regex_t regex;\n>\n>  if (prefix[0] == '!') {\n> - if (prefix[1] != '!')\n> - die (\"Invalid search pattern: %s\", prefix);\n>  prefix++;\n> +\n> + if (prefix[0] == '-') {\n> + prefix++;\n> + negative = 1;\n> + } else if (prefix[0] != '!') {\n> + die (\"Invalid search pattern: %s\", prefix);\n> + }\n>  }\n>\n>  if (regcomp(&regex, prefix, REG_EXTENDED))\n> @@ -903,7 +913,7 @@ static int get_sha1_oneline(const char *prefix, \n> unsigned char *sha1,\n>  continue;\n>  buf = get_commit_buffer(commit, NULL);\n>  p = strstr(buf, \"\\n\\n\");\n> - matches = p && !regexec(&regex, p + 2, 0, NULL, 0);\n> + matches = p && (negative ^ !regexec(&regex, p + 2, 0, NULL, 0));\n>  unuse_commit_buffer(commit, buf);\n>\n>  if (matches) {\n> diff --git a/t/t1511-rev-parse-caret.sh b/t/t1511-rev-parse-caret.sh\n> index b2f90be..8a5983f 100755\n> --- a/t/t1511-rev-parse-caret.sh\n> +++ b/t/t1511-rev-parse-caret.sh\n> @@ -26,7 +26,10 @@ test_expect_success 'setup' '\n>  git branch expref &&\n>  echo changed >>a-blob &&\n>  git add -u &&\n> - git commit -m Changed\n> + git commit -m Changed &&\n> + echo changed-again >>a-blob &&\n> + git add -u &&\n> + git commit -m Changed-again\n> '\n>\n> test_expect_success 'ref^{non-existent}' '\n> @@ -99,4 +102,30 @@ test_expect_success 'ref^{/!!Exp}' '\n>  test_cmp expected actual\n> '\n>\n> +test_expect_success 'ref^{/!-}' '\n> + test_must_fail git rev-parse master^{/!-}\n> +'\n> +\n> +test_expect_success 'ref^{/!-.}' '\n> + test_must_fail git rev-parse master^{/!-.}\n> +'\n> +\n> +test_expect_success 'ref^{/!-non-existent}' '\n> + git rev-parse master >expected &&\n> + git rev-parse master^{/!-non-existent} >actual &&\n> + test_cmp expected actual\n> +'\n> +\n> +test_expect_success 'ref^{/!-Changed}' '\n> + git rev-parse expref >expected &&\n> + git rev-parse master^{/!-Changed} >actual &&\n> + test_cmp expected actual\n> +'\n> +\n> +test_expect_success 'ref^{/!-!Exp}' '\n> + git rev-parse modref >expected &&\n> + git rev-parse expref^{/!-!Exp} >actual &&\n> + test_cmp expected actual\n> +'\n> +\n> test_done\n> -- \n> 2.7.0-rc2\n>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n> \n"},{"id":"275866","messageId":"1452660671-5512-1-git-send-email-ischis2@cox.net","threadId":"39539","inReplyTo":"ED12DDDA0C004D23BDDB14973C675800@PhilipOakley","subject":"[PATCH V4 0/2] specify commit by negative pattern","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2016-01-13T04:51:11Z","receivedAt":"2016-01-13T04:51:11Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"Add support for negative pattern matching in the @^{/<pattern>} regex\npattern style, and consequentially the style revision specifiers. So\nnow you can find the first commit whose message doesn't match a\npattern, complementing the existing positive matching.\ne.g.:\n\n    $ git rebase -i @^{/!-^WIP}\n\nMy use-case is in having a \"work, work, work, rebase, push\"-style\nworkflow, which generates a lot of \"WIP foo\" commits. While rebasing is\nusually handled via \"git rebase -i origin/master\", occasionally I will\nalready have several \"good, but not yet ready to push\" commits hanging\naround while I finish work on related commits. In these situations, the\nability to quickly \"git diff @^{/!-^WIP}\" to get an overview of all\nchanges \"since the last one I was happy with\", can be useful.\n\nThis is the forth version of the patch series. The previous attempt\nused the notation @^{/!WIP}, rather than @^{/!-WIP}, so the \"modifier\"\nwas the '!' character. Now, '!' is taken as an indicator that the\npattern is to be interpreted differently, and '-' is taken as an\nindicator of how it is to be interpreted differently. This follows\nrecent discussion with \"Junio C Hamano\" <gitster@pobox.com> and much-less\nrecent discussion archived at:\n\nhttp://thread.gmane.org/gmane.comp.version-control.git/40460/focus=40477\n\nIn summary, '!' is to be used as an \"escape hatch\", for further\nextension of the \"name commit by pattern\" functionality. Theorised future\nextensions indicated things like \"what was to be searched\",\ne.g.: @^{/!(a=author)}.  With only two interpretations of the '!'\nleader, for now (including the '!!' literal notation), adding such a\nverbose form, such as '@^{/!(negative)foo}', seemed inappropriate at this\ntime. In the event that such verbose forms are ever implemented, this new\nform may act as a shorthand, for a basic case.\n\nWill Palmer (2):\n  test for '!' handling in rev-parse's named commits\n  object name: introduce '^{/!-<negative pattern>}' notation\n\n Documentation/revisions.txt | 11 +++++-----\n sha1_name.c                 | 20 ++++++++++++-----\n t/t1511-rev-parse-caret.sh  | 53 ++++++++++++++++++++++++++++++++++++++++++++-\n 3 files changed, 73 insertions(+), 11 deletions(-)\n\n-- \n2.7.0-rc2\n"},{"id":"275867","messageId":"1452660708-5568-1-git-send-email-ischis2@cox.net","threadId":"39539","inReplyTo":"ED12DDDA0C004D23BDDB14973C675800@PhilipOakley","subject":"[PATCH V4 1/2] test for '!' handling in rev-parse's named commits","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2016-01-13T04:51:48Z","receivedAt":"2016-01-13T04:51:48Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"From: Will Palmer <wmpalmer@gmail.com>\n\nIn anticipation of extending this behaviour, add tests verifying the\nhandling of exclamation marks when looking up a commit \"by name\".\n\nSpecifically, as documented: '<rev>^{/!Message}' should fail, as the '!'\nprefix is reserved; while '<rev>^{!!Message}' should search for a commit\nwhose message contains the string \"!Message\".\n\nSigned-off-by: Will Palmer <wmpalmer@gmail.com>\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\nNotes:\n    No actual changes made to this patch.  Just re-sending to keep \n    consistent with updates to the rest of the series.\n t/t1511-rev-parse-caret.sh | 24 +++++++++++++++++++++++-\n 1 file changed, 23 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t1511-rev-parse-caret.sh b/t/t1511-rev-parse-caret.sh\nindex 15973f2..b2f90be 100755\n--- a/t/t1511-rev-parse-caret.sh\n+++ b/t/t1511-rev-parse-caret.sh\n@@ -18,7 +18,15 @@ test_expect_success 'setup' '\n \tgit checkout master &&\n \techo modified >>a-blob &&\n \tgit add -u &&\n-\tgit commit -m Modified\n+\tgit commit -m Modified &&\n+\tgit branch modref &&\n+\techo changed! >>a-blob &&\n+\tgit add -u &&\n+\tgit commit -m !Exp &&\n+\tgit branch expref &&\n+\techo changed >>a-blob &&\n+\tgit add -u &&\n+\tgit commit -m Changed\n '\n \n test_expect_success 'ref^{non-existent}' '\n@@ -77,4 +85,18 @@ test_expect_success 'ref^{/Initial}' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'ref^{/!Exp}' '\n+\ttest_must_fail git rev-parse master^{/!Exp}\n+'\n+\n+test_expect_success 'ref^{/!}' '\n+\ttest_must_fail git rev-parse master^{/!}\n+'\n+\n+test_expect_success 'ref^{/!!Exp}' '\n+\tgit rev-parse expref >expected &&\n+\tgit rev-parse master^{/!!Exp} >actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_done\n-- \n2.7.0-rc2\n"},{"id":"275868","messageId":"1452660741-5616-1-git-send-email-ischis2@cox.net","threadId":"39539","inReplyTo":"ED12DDDA0C004D23BDDB14973C675800@PhilipOakley","subject":"[PATCH V4 2/2] object name: introduce '^{/!-<negative pattern>}' notation","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2016-01-13T04:52:21Z","receivedAt":"2016-01-13T04:52:21Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"From: Will Palmer <wmpalmer@gmail.com>\n\nTo name a commit, you can now use the :/!-<negative pattern> regex\nstyle, and consequentially, say\n\n    $ git rev-parse HEAD^{/!-foo}\n\nand it will return the hash of the first commit reachable from HEAD,\nwhose commit message does not contain \"foo\". This is the opposite of the\nexisting <rev>^{/<pattern>} syntax.\n\nThe specific use-case this is intended for is to perform an operation,\nexcluding the most-recent commits containing a particular marker. For\nexample, if you tend to make \"work in progress\" commits, with messages\nbeginning with \"WIP\", you work, then it could be useful to diff against\n\"the most recent commit which was not a WIP commit\". That sort of thing\nnow possible, via commands such as:\n\n    $ git diff @^{/!-^WIP}\n\nThe leader '/!-', rather than simply '/!', to denote a negative match,\nis chosen to leave room for additional modifiers in the future.\n\nSigned-off-by: Will Palmer <wmpalmer@gmail.com>\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n\nNotes:\n    Changed |say|use the :/!-<negative pattern> regex style, and consequentially, say|.\n    \n    Chose not to chagne subject since it matches the end of\n    git rev-parse HEAD^{/!-foo}\n\n    Mailing list web interface is again not working; therefore, I don't \n    have URLs for the earlier review comments.\n\n Documentation/revisions.txt | 11 ++++++-----\n sha1_name.c                 | 20 +++++++++++++++-----\n t/t1511-rev-parse-caret.sh  | 31 ++++++++++++++++++++++++++++++-\n 3 files changed, 51 insertions(+), 11 deletions(-)\n\ndiff --git a/Documentation/revisions.txt b/Documentation/revisions.txt\nindex d85e303..0c84d4f 100644\n--- a/Documentation/revisions.txt\n+++ b/Documentation/revisions.txt\n@@ -176,11 +176,12 @@ existing tag object.\n   A colon, followed by a slash, followed by a text, names\n   a commit whose commit message matches the specified regular expression.\n   This name returns the youngest matching commit which is\n-  reachable from any ref.  If the commit message starts with a\n-  '!' you have to repeat that;  the special sequence ':/!',\n-  followed by something else than '!', is reserved for now.\n-  The regular expression can match any part of the commit message. To\n-  match messages starting with a string, one can use e.g. ':/^foo'.\n+  reachable from any ref. The regular expression can match any part of the\n+  commit message. To match messages starting with a string, one can use\n+  e.g. ':/^foo'. The special sequence ':/!' is reserved for modifiers to what\n+  is matched. ':/!-foo' performs a negative match, while ':/!!foo' matches a\n+  literal '!' character, followed by 'foo'. Any other sequence beginning with\n+  ':/!' is reserved for now.\n \n '<rev>:<path>', e.g. 'HEAD:README', ':README', 'master:./README'::\n   A suffix ':' followed by a path names the blob or tree\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 892db21..a2c5303 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -848,8 +848,12 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned l\n  * through history and returning the first commit whose message starts\n  * the given regular expression.\n  *\n- * For future extension, ':/!' is reserved. If you want to match a message\n- * beginning with a '!', you have to repeat the exclamation mark.\n+ * For negative-matching, prefix the pattern-part with '!-', like: ':/!-WIP'.\n+ *\n+ * For a literal '!' character at the beginning of a pattern, you have to repeat\n+ * that, like: ':/!!foo'\n+ *\n+ * For future extension, all other sequences beginning with ':/!' are reserved.\n  */\n \n /* Remember to update object flag allocation in object.h */\n@@ -878,12 +882,18 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,\n {\n \tstruct commit_list *backup = NULL, *l;\n \tint found = 0;\n+\tint negative = 0;\n \tregex_t regex;\n \n \tif (prefix[0] == '!') {\n-\t\tif (prefix[1] != '!')\n-\t\t\tdie (\"Invalid search pattern: %s\", prefix);\n \t\tprefix++;\n+\n+\t\tif (prefix[0] == '-') {\n+\t\t\tprefix++;\n+\t\t\tnegative = 1;\n+\t\t} else if (prefix[0] != '!') {\n+\t\t\tdie (\"Invalid search pattern: %s\", prefix);\n+\t\t}\n \t}\n \n \tif (regcomp(&regex, prefix, REG_EXTENDED))\n@@ -903,7 +913,7 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,\n \t\t\tcontinue;\n \t\tbuf = get_commit_buffer(commit, NULL);\n \t\tp = strstr(buf, \"\\n\\n\");\n-\t\tmatches = p && !regexec(&regex, p + 2, 0, NULL, 0);\n+\t\tmatches = p && (negative ^ !regexec(&regex, p + 2, 0, NULL, 0));\n \t\tunuse_commit_buffer(commit, buf);\n \n \t\tif (matches) {\ndiff --git a/t/t1511-rev-parse-caret.sh b/t/t1511-rev-parse-caret.sh\nindex b2f90be..8a5983f 100755\n--- a/t/t1511-rev-parse-caret.sh\n+++ b/t/t1511-rev-parse-caret.sh\n@@ -26,7 +26,10 @@ test_expect_success 'setup' '\n \tgit branch expref &&\n \techo changed >>a-blob &&\n \tgit add -u &&\n-\tgit commit -m Changed\n+\tgit commit -m Changed &&\n+\techo changed-again >>a-blob &&\n+\tgit add -u &&\n+\tgit commit -m Changed-again\n '\n \n test_expect_success 'ref^{non-existent}' '\n@@ -99,4 +102,30 @@ test_expect_success 'ref^{/!!Exp}' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'ref^{/!-}' '\n+\ttest_must_fail git rev-parse master^{/!-}\n+'\n+\n+test_expect_success 'ref^{/!-.}' '\n+\ttest_must_fail git rev-parse master^{/!-.}\n+'\n+\n+test_expect_success 'ref^{/!-non-existent}' '\n+\tgit rev-parse master >expected &&\n+\tgit rev-parse master^{/!-non-existent} >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'ref^{/!-Changed}' '\n+\tgit rev-parse expref >expected &&\n+\tgit rev-parse master^{/!-Changed} >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'ref^{/!-!Exp}' '\n+\tgit rev-parse modref >expected &&\n+\tgit rev-parse expref^{/!-!Exp} >actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_done\n-- \n2.7.0-rc2\n"},{"id":"275960","messageId":"xmqqh9ihnveu.fsf@gitster.mtv.corp.google.com","threadId":"39539","inReplyTo":"1452660741-5616-1-git-send-email-ischis2@cox.net","subject":"Re: [PATCH V4 2/2] object name: introduce '^{/!-<negative pattern>}' notation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-01-13T19:15:05Z","receivedAt":"2016-01-13T19:15:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Stephen P. Smith\" <ischis2@cox.net> writes:\n\n> From: Will Palmer <wmpalmer@gmail.com>\n>\n> To name a commit, you can now use the :/!-<negative pattern> regex\n> style, and consequentially, say\n>\n>     $ git rev-parse HEAD^{/!-foo}\n>\n> and it will return the hash of the first commit reachable from HEAD,\n> whose commit message does not contain \"foo\". This is the opposite of the\n> existing <rev>^{/<pattern>} syntax.\n>\n> The specific use-case this is intended for is to perform an operation,\n> excluding the most-recent commits containing a particular marker. For\n> example, if you tend to make \"work in progress\" commits, with messages\n> beginning with \"WIP\", you work, then it could be useful to diff against\n> \"the most recent commit which was not a WIP commit\". That sort of thing\n> now possible, via commands such as:\n>\n>     $ git diff @^{/!-^WIP}\n>\n> The leader '/!-', rather than simply '/!', to denote a negative match,\n> is chosen to leave room for additional modifiers in the future.\n>\n> Signed-off-by: Will Palmer <wmpalmer@gmail.com>\n> Signed-off-by: Stephen P. Smith <ischis2@cox.net>\n> ---\n>\n> Notes:\n>     Changed |say|use the :/!-<negative pattern> regex style, and consequentially, say|.\n>     \n>     Chose not to chagne subject since it matches the end of\n>     git rev-parse HEAD^{/!-foo}\n>\n>     Mailing list web interface is again not working; therefore, I don't \n>     have URLs for the earlier review comments.\n\nThanks, this looks good (and it looked good already at the previous\nround).\n\n> diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt\n> index d85e303..0c84d4f 100644\n> --- a/Documentation/revisions.txt\n> +++ b/Documentation/revisions.txt\n> @@ -176,11 +176,12 @@ existing tag object.\n>    A colon, followed by a slash, followed by a text, names\n>    a commit whose commit message matches the specified regular expression.\n>    This name returns the youngest matching commit which is\n> -  reachable from any ref.  If the commit message starts with a\n> -  '!' you have to repeat that;  the special sequence ':/!',\n> -  followed by something else than '!', is reserved for now.\n> -  The regular expression can match any part of the commit message. To\n> -  match messages starting with a string, one can use e.g. ':/^foo'.\n> +  reachable from any ref. The regular expression can match any part of the\n> +  commit message. To match messages starting with a string, one can use\n> +  e.g. ':/^foo'. The special sequence ':/!' is reserved for modifiers to what\n> +  is matched. ':/!-foo' performs a negative match, while ':/!!foo' matches a\n> +  literal '!' character, followed by 'foo'. Any other sequence beginning with\n> +  ':/!' is reserved for now.\n\nThe original text reads as if \":/foo\" looks for 'foo' anywhere in\nthe log message while \":/!!foo\" looks for '!foo' at the beginning,\nwhich was incorrect as far as I can tell, but the updated text\ncorrects it.  Good.\n\n> @@ -903,7 +913,7 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,\n>  \t\t\tcontinue;\n>  \t\tbuf = get_commit_buffer(commit, NULL);\n>  \t\tp = strstr(buf, \"\\n\\n\");\n> -\t\tmatches = p && !regexec(&regex, p + 2, 0, NULL, 0);\n> +\t\tmatches = p && (negative ^ !regexec(&regex, p + 2, 0, NULL, 0));\n>  \t\tunuse_commit_buffer(commit, buf);\n\nHmph, without \"negative pattern match\", if you asked for \":/foo\" and\nthe commit did not have any body (which I do not think the current\nversion of Git allows to create by default, but there may be such\ncommits created by older versions of Git or reimplementation of Git\nmade by others), p could be NULL.  In such a case, any regex would\nnot match, so I would expect that commit to be shown.\n\nIn other words, I wonder if the above should be\n\n\t\tmatches = negative ^ (p && !regexec(&regex, p + 2, 0, NULL, 0));\n\nThis would not make practical difference, but I would expect any\nchange to introduce \"negative patch\" to an original logic that is\n\n\tmatches = ORIGINAL_LOGIC_TO_COMPUTE_MATCH\n\nto become\n\n\tmatches = negative ^ ORIGINAL_LOGIC_TO_COMPUTE_MATCH\n"},{"id":"277103","messageId":"1454198761-27357-1-git-send-email-ischis2@cox.net","threadId":"39539","inReplyTo":"xmqqh9ihnveu.fsf@gitster.mtv.corp.google.com","subject":"[PATCH V5 2/2] object name: introduce '^{/!-<negative pattern>}' notation","fromName":"Stephen P. Smith","fromEmail":"ischis2@cox.net","sentAt":"2016-01-31T00:06:01Z","receivedAt":"2016-01-31T00:06:01Z","isPatch":true,"sender":{"key":"ishchis2@gmail.com","avatar":null},"body":"From: Will Palmer <wmpalmer@gmail.com>\n\nTo name a commit, you can now use the :/!-<negative pattern> regex\nstyle, and consequentially, say\n\n    $ git rev-parse HEAD^{/!-foo}\n\nand it will return the hash of the first commit reachable from HEAD,\nwhose commit message does not contain \"foo\". This is the opposite of the\nexisting <rev>^{/<pattern>} syntax.\n\nThe specific use-case this is intended for is to perform an operation,\nexcluding the most-recent commits containing a particular marker. For\nexample, if you tend to make \"work in progress\" commits, with messages\nbeginning with \"WIP\", you work, then it could be useful to diff against\n\"the most recent commit which was not a WIP commit\". That sort of thing\nnow possible, via commands such as:\n\n    $ git diff @^{/!-^WIP}\n\nThe leader '/!-', rather than simply '/!', to denote a negative match,\nis chosen to leave room for additional modifiers in the future.\n\nSigned-off-by: Will Palmer <wmpalmer@gmail.com>\nSigned-off-by: Stephen P. Smith <ischis2@cox.net>\n---\n\nNotes:\n    I agree that there may be commits that have an empty body which were made\n    with older git releases.\n    \n    Even if the current git does check for empty bodied commits (by\n    default), the git plumbing should be able to still create such\n    commits.\n    \n    The tests show that the change from:\n        matches = p && (negative ^ !regexec(&regex, p + 2, 0, NULL, 0));\n    to\n        matches = negative ^ (p && !regexec(&regex, p + 2, 0, NULL, 0));\n    did not break the proposed patch.\n\n Documentation/revisions.txt | 11 ++++++-----\n sha1_name.c                 | 20 +++++++++++++++-----\n t/t1511-rev-parse-caret.sh  | 31 ++++++++++++++++++++++++++++++-\n 3 files changed, 51 insertions(+), 11 deletions(-)\n\ndiff --git a/Documentation/revisions.txt b/Documentation/revisions.txt\nindex d85e303..0c84d4f 100644\n--- a/Documentation/revisions.txt\n+++ b/Documentation/revisions.txt\n@@ -176,11 +176,12 @@ existing tag object.\n   A colon, followed by a slash, followed by a text, names\n   a commit whose commit message matches the specified regular expression.\n   This name returns the youngest matching commit which is\n-  reachable from any ref.  If the commit message starts with a\n-  '!' you have to repeat that;  the special sequence ':/!',\n-  followed by something else than '!', is reserved for now.\n-  The regular expression can match any part of the commit message. To\n-  match messages starting with a string, one can use e.g. ':/^foo'.\n+  reachable from any ref. The regular expression can match any part of the\n+  commit message. To match messages starting with a string, one can use\n+  e.g. ':/^foo'. The special sequence ':/!' is reserved for modifiers to what\n+  is matched. ':/!-foo' performs a negative match, while ':/!!foo' matches a\n+  literal '!' character, followed by 'foo'. Any other sequence beginning with\n+  ':/!' is reserved for now.\n \n '<rev>:<path>', e.g. 'HEAD:README', ':README', 'master:./README'::\n   A suffix ':' followed by a path names the blob or tree\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 892db21..89918ca 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -848,8 +848,12 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned l\n  * through history and returning the first commit whose message starts\n  * the given regular expression.\n  *\n- * For future extension, ':/!' is reserved. If you want to match a message\n- * beginning with a '!', you have to repeat the exclamation mark.\n+ * For negative-matching, prefix the pattern-part with '!-', like: ':/!-WIP'.\n+ *\n+ * For a literal '!' character at the beginning of a pattern, you have to repeat\n+ * that, like: ':/!!foo'\n+ *\n+ * For future extension, all other sequences beginning with ':/!' are reserved.\n  */\n \n /* Remember to update object flag allocation in object.h */\n@@ -878,12 +882,18 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,\n {\n \tstruct commit_list *backup = NULL, *l;\n \tint found = 0;\n+\tint negative = 0;\n \tregex_t regex;\n \n \tif (prefix[0] == '!') {\n-\t\tif (prefix[1] != '!')\n-\t\t\tdie (\"Invalid search pattern: %s\", prefix);\n \t\tprefix++;\n+\n+\t\tif (prefix[0] == '-') {\n+\t\t\tprefix++;\n+\t\t\tnegative = 1;\n+\t\t} else if (prefix[0] != '!') {\n+\t\t\tdie (\"Invalid search pattern: %s\", prefix);\n+\t\t}\n \t}\n \n \tif (regcomp(&regex, prefix, REG_EXTENDED))\n@@ -903,7 +913,7 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1,\n \t\t\tcontinue;\n \t\tbuf = get_commit_buffer(commit, NULL);\n \t\tp = strstr(buf, \"\\n\\n\");\n-\t\tmatches = p && !regexec(&regex, p + 2, 0, NULL, 0);\n+\t\tmatches = negative ^ (p && !regexec(&regex, p + 2, 0, NULL, 0));\n \t\tunuse_commit_buffer(commit, buf);\n \n \t\tif (matches) {\ndiff --git a/t/t1511-rev-parse-caret.sh b/t/t1511-rev-parse-caret.sh\nindex b2f90be..8a5983f 100755\n--- a/t/t1511-rev-parse-caret.sh\n+++ b/t/t1511-rev-parse-caret.sh\n@@ -26,7 +26,10 @@ test_expect_success 'setup' '\n \tgit branch expref &&\n \techo changed >>a-blob &&\n \tgit add -u &&\n-\tgit commit -m Changed\n+\tgit commit -m Changed &&\n+\techo changed-again >>a-blob &&\n+\tgit add -u &&\n+\tgit commit -m Changed-again\n '\n \n test_expect_success 'ref^{non-existent}' '\n@@ -99,4 +102,30 @@ test_expect_success 'ref^{/!!Exp}' '\n \ttest_cmp expected actual\n '\n \n+test_expect_success 'ref^{/!-}' '\n+\ttest_must_fail git rev-parse master^{/!-}\n+'\n+\n+test_expect_success 'ref^{/!-.}' '\n+\ttest_must_fail git rev-parse master^{/!-.}\n+'\n+\n+test_expect_success 'ref^{/!-non-existent}' '\n+\tgit rev-parse master >expected &&\n+\tgit rev-parse master^{/!-non-existent} >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'ref^{/!-Changed}' '\n+\tgit rev-parse expref >expected &&\n+\tgit rev-parse master^{/!-Changed} >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'ref^{/!-!Exp}' '\n+\tgit rev-parse modref >expected &&\n+\tgit rev-parse expref^{/!-!Exp} >actual &&\n+\ttest_cmp expected actual\n+'\n+\n test_done\n-- \n2.7.0-rc2\n"},{"id":"277188","messageId":"xmqq4mdsumz9.fsf@gitster.mtv.corp.google.com","threadId":"39539","inReplyTo":"1454198761-27357-1-git-send-email-ischis2@cox.net","subject":"Re: [PATCH V5 2/2] object name: introduce '^{/!-<negative pattern>}' notation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-02-01T21:42:02Z","receivedAt":"2016-02-01T21:42:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thanks.\n"}]}