{"thread":{"id":"49664","subject":"Re: bug?: git grep HEAD with exclude in pathspec not taken into account","startedAt":"2018-10-24T14:54:04Z","lastAt":"2018-11-05T01:50:08Z","messageCount":10,"participants":["Christophe Bliard","Duy Nguyen","Nguyễn Thái Ngọc Duy","Eric Sunshine","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"361414","messageId":"CAGOLd-5Gbt6fQTvm+7018uX+8WF7NUWpa1sFWAg3-5bxtmOt-Q@mail.gmail.com","threadId":"49664","inReplyTo":"CAGOLd-7Hi+tssj4ozKPd04squ-PuFwtt6f2nhbZp-zKwy62pVQ@mail.gmail.com","subject":"Re: bug?: git grep HEAD with exclude in pathspec not taken into account","fromName":"Christophe Bliard","fromEmail":"christophe.bliard@trux.info","sentAt":"2018-10-24T14:53:49Z","receivedAt":"2018-10-24T14:54:04Z","isPatch":false,"sender":{"key":"christophe.bliard@trux.info","avatar":null},"body":"Hi,\n\nI observed an unexpected behavior while using git grep with both git\n2.19.1 and 2.14.3. Here is how to reproduce it:\n\n> git init\nInitialized empty Git repository in /private/tmp/hello/.git/\n> echo foo > fileA\n> echo 'foo is false+' > fileB\n> git add fileA\n> git commit -m fileA\n[master (root-commit) f2c83e7] fileA\n 1 file changed, 1 insertion(+)\n create mode 100644 fileA\n> git add fileB\n> git commit -m fileB\n[master e35df26] fileB\n 1 file changed, 1 insertion(+)\n create mode 100644 fileB\n> git --no-pager grep foo HEAD -- ':!fileA'\nHEAD:fileB:foo is false+\n> git --no-pager grep foo HEAD -- ':!fileB'\nHEAD:fileA:foo\nHEAD:fileB:foo is false+\n\nIn the last command, fileB appears in grep results but it should have\nbeen excluded.\n\nIf the HEAD parameter is removed, it works as expected:\n\n> git --no-pager grep foo -- ':!fileB'\nfileA:foo\n\nIf giving the revision, it does not work either\n\n> git --no-pager grep foo e35df26 -- ':!fileB'\ne35df26:fileA:foo\ne35df26:fileB:foo is false+\n\nThe same behavior can be seen with git archive:\n\n> git archive --verbose master ':(top)'\nfileA\nfileB\npax_global_header00006660000000000000000000000064133641017230014512gustar00rootroot0000000000000052\ncomment=e35df26c65f3c0b303e78743496598b8b6a566e9\nfileA000066400000000000000000000000041336410172300120130ustar00rootroot00000000000000foo\nfileB000066400000000000000000000000161336410172300120170ustar00rootroot00000000000000foo\nis false+\n> /usr/local/bin/git archive --verbose master ':(top)' ':(exclude)fileA'\nfileB\npax_global_header00006660000000000000000000000064133641017230014512gustar00rootroot0000000000000052\ncomment=e35df26c65f3c0b303e78743496598b8b6a566e9\nfileB000066400000000000000000000000161336410172300120170ustar00rootroot00000000000000foo\nis false+\n> /usr/local/bin/git archive --verbose master ':(top)' ':(exclude)fileB'\nfileA\nfileB\npax_global_header00006660000000000000000000000064133641017230014512gustar00rootroot0000000000000052\ncomment=e35df26c65f3c0b303e78743496598b8b6a566e9\nfileA000066400000000000000000000000041336410172300120130ustar00rootroot00000000000000foo\nfileB000066400000000000000000000000161336410172300120170ustar00rootroot00000000000000foo\nis false+\n\nfileA can be excluded, but not fileB.\n\nIs it a bug?\n\nThanks\n\n--\nChristophe Bliard\n"},{"id":"361417","messageId":"CACsJy8C7pArdayQu9Kh5z6dczCqV_=XJP4wzR_dcm_W3MgG+Jg@mail.gmail.com","threadId":"49664","inReplyTo":"CAGOLd-5Gbt6fQTvm+7018uX+8WF7NUWpa1sFWAg3-5bxtmOt-Q@mail.gmail.com","subject":"Re: bug?: git grep HEAD with exclude in pathspec not taken into account","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-10-24T15:14:26Z","receivedAt":"2018-10-24T15:14:55Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Oct 24, 2018 at 4:55 PM Christophe Bliard\n<christophe.bliard@trux.info> wrote:\n>\n> Hi,\n>\n> I observed an unexpected behavior while using git grep with both git\n> 2.19.1 and 2.14.3. Here is how to reproduce it:\n>\n> > git init\n> Initialized empty Git repository in /private/tmp/hello/.git/\n> > echo foo > fileA\n> > echo 'foo is false+' > fileB\n> > git add fileA\n> > git commit -m fileA\n> [master (root-commit) f2c83e7] fileA\n>  1 file changed, 1 insertion(+)\n>  create mode 100644 fileA\n> > git add fileB\n> > git commit -m fileB\n> [master e35df26] fileB\n>  1 file changed, 1 insertion(+)\n>  create mode 100644 fileB\n> > git --no-pager grep foo HEAD -- ':!fileA'\n> HEAD:fileB:foo is false+\n> > git --no-pager grep foo HEAD -- ':!fileB'\n> HEAD:fileA:foo\n> HEAD:fileB:foo is false+\n>\n> In the last command, fileB appears in grep results but it should have\n> been excluded.\n>\n> If the HEAD parameter is removed, it works as expected:\n\nIt's probably a bug. We have different code paths for matching things\nwith or without HEAD, roughly speaking. I'll look into to this more on\nthe weekend, unless somebody (is welcome to) beats me first.\n\nAnother thing that might also be a problem is, negative patterns are\nsupposed to exclude stuff from \"something\" but you don't specify that\n\"something\" (i.e. positive patterns) in your grep commands above. If\n\"grep foo HEAD -- :/ ':!fileB'\" works, then you probably just run into\nsome undefined corner case.\n-- \nDuy\n"},{"id":"361420","messageId":"CAGOLd-5J7+idqoREg0CHNcC0t6Mx3_bC_qbQaLgRLcssO+kxjQ@mail.gmail.com","threadId":"49664","inReplyTo":"CACsJy8C7pArdayQu9Kh5z6dczCqV_=XJP4wzR_dcm_W3MgG+Jg@mail.gmail.com","subject":"Re: bug?: git grep HEAD with exclude in pathspec not taken into account","fromName":"Christophe Bliard","fromEmail":"christophe.bliard@trux.info","sentAt":"2018-10-24T15:39:35Z","receivedAt":"2018-10-24T15:39:49Z","isPatch":false,"sender":{"key":"christophe.bliard@trux.info","avatar":null},"body":"In fact, per https://github.com/git/git/commit/859b7f1d0e742493d2a9396794cd9040213ad846,\nhaving only a negative pattern is like having a catch-all positive\npattern and the negative pattern (since git 2.13.0).\n\nThus, adding the positive pattern yields the same results:\n\n> git --no-pager grep foo HEAD -- ':!fileA' .\nHEAD:fileB:foo is false+\n> git --no-pager grep foo HEAD -- ':!fileB' .\nHEAD:fileA:foo\nHEAD:fileB:foo is false+\n\nLe mer. 24 oct. 2018 à 17:14, Duy Nguyen <pclouds@gmail.com> a écrit :\n>\n> On Wed, Oct 24, 2018 at 4:55 PM Christophe Bliard\n> <christophe.bliard@trux.info> wrote:\n> >\n> > Hi,\n> >\n> > I observed an unexpected behavior while using git grep with both git\n> > 2.19.1 and 2.14.3. Here is how to reproduce it:\n> >\n> > > git init\n> > Initialized empty Git repository in /private/tmp/hello/.git/\n> > > echo foo > fileA\n> > > echo 'foo is false+' > fileB\n> > > git add fileA\n> > > git commit -m fileA\n> > [master (root-commit) f2c83e7] fileA\n> >  1 file changed, 1 insertion(+)\n> >  create mode 100644 fileA\n> > > git add fileB\n> > > git commit -m fileB\n> > [master e35df26] fileB\n> >  1 file changed, 1 insertion(+)\n> >  create mode 100644 fileB\n> > > git --no-pager grep foo HEAD -- ':!fileA'\n> > HEAD:fileB:foo is false+\n> > > git --no-pager grep foo HEAD -- ':!fileB'\n> > HEAD:fileA:foo\n> > HEAD:fileB:foo is false+\n> >\n> > In the last command, fileB appears in grep results but it should have\n> > been excluded.\n> >\n> > If the HEAD parameter is removed, it works as expected:\n>\n> It's probably a bug. We have different code paths for matching things\n> with or without HEAD, roughly speaking. I'll look into to this more on\n> the weekend, unless somebody (is welcome to) beats me first.\n>\n> Another thing that might also be a problem is, negative patterns are\n> supposed to exclude stuff from \"something\" but you don't specify that\n> \"something\" (i.e. positive patterns) in your grep commands above. If\n> \"grep foo HEAD -- :/ ':!fileB'\" works, then you probably just run into\n> some undefined corner case.\n> --\n> Duy\n"},{"id":"361789","messageId":"CACsJy8A83_Jh4GmVYXS-zk_6Yro6eeB9i_J7xh3VMTkr8JVDvA@mail.gmail.com","threadId":"49664","inReplyTo":"CAGOLd-5Gbt6fQTvm+7018uX+8WF7NUWpa1sFWAg3-5bxtmOt-Q@mail.gmail.com","subject":"Re: bug?: git grep HEAD with exclude in pathspec not taken into account","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-10-27T14:57:14Z","receivedAt":"2018-10-27T14:57:43Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Oct 24, 2018 at 4:55 PM Christophe Bliard\n<christophe.bliard@trux.info> wrote:\n>\n> Hi,\n>\n> I observed an unexpected behavior while using git grep with both git\n> 2.19.1 and 2.14.3.\n\nQuick note. I confirm this is a bug in tree_entry_interesting()\nperhaps being over-optimistic. It'll take me more time to familiarize\nmyself with this negative matching in the function before I come up\nwith a fix for it. Thanks for reporting.\n-- \nDuy\n"},{"id":"362365","messageId":"20181103153049.22850-1-pclouds@gmail.com","threadId":"49664","inReplyTo":"CAGOLd-5Gbt6fQTvm+7018uX+8WF7NUWpa1sFWAg3-5bxtmOt-Q@mail.gmail.com","subject":"[PATCH] tree-walk.c: fix overoptimistic inclusion in :(exclude) matching","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-11-03T15:30:49Z","receivedAt":"2018-11-03T15:31:04Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"tree_entry_interesting() is used for matching pathspec on a tree. The\ninteresting thing about this function is that, because the tree\nentries are known to be sorted, this function can return more than\njust \"yes, matched\" and \"no, not matched\". It can also say \"yes, this\nentry is matched and so is the remaining entries in the tree\".\n\nThis is where I made a mistake when matching exclude pathspec. For\nexclude pathspec, we do matching twice, one with positive patterns and\none with negative ones, then a rule table is applied to determine the\nfinal \"include or exclude\" result. Note that \"matched\" does not\nnecessarily mean include. For negative patterns, \"matched\" means\nexclude.\n\nThis particular rule is too eager to include everything. Rule 8 says\nthat \"if all entries are positively matched\" and the current entry is\nnot negatively matched (i.e. not excluded), then all entries are\npositively matched and therefore included. But this is not true. If\nthe _current_ entry is not negatively matched, it does not mean the\nnext one will not be and we cannot conclude right away that all\nremaining entries are positively matched and can be included.\n\nRules 8 and 18 are now updated to be less eager. We conclude that the\ncurrent entry is positively matched and included. But we say nothing\nabout remaining entries. tree_entry_interesting() will be called again\nfor those entries where we will determine entries individually.\n\nReported-by: Christophe Bliard <christophe.bliard@trux.info>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n t/t6132-pathspec-exclude.sh | 17 +++++++++++++++++\n tree-walk.c                 | 11 ++++++++---\n 2 files changed, 25 insertions(+), 3 deletions(-)\n\ndiff --git a/t/t6132-pathspec-exclude.sh b/t/t6132-pathspec-exclude.sh\nindex eb829fce97..393b29f205 100755\n--- a/t/t6132-pathspec-exclude.sh\n+++ b/t/t6132-pathspec-exclude.sh\n@@ -194,4 +194,21 @@ test_expect_success 'multiple exclusions' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 't_e_i() exclude case #8' '\n+\tgit init case8 &&\n+\t(\n+\t\tcd case8 &&\n+\t\techo file >file1 &&\n+\t\techo file >file2 &&\n+\t\tgit add . &&\n+\t\tgit commit -m twofiles &&\n+\t\tgit grep -l file HEAD :^file2 >actual &&\n+\t\techo HEAD:file1 >expected &&\n+\t\ttest_cmp expected actual &&\n+\t\tgit grep -l file HEAD :^file1 >actual &&\n+\t\techo HEAD:file2 >expected &&\n+\t\ttest_cmp expected actual\n+\t)\n+'\n+\n test_done\ndiff --git a/tree-walk.c b/tree-walk.c\nindex 77b37f36fa..79bafbd1a2 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -1107,7 +1107,7 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,\n \t *   5  |  file |    1     |    1     |   0\n \t *   6  |  file |    1     |    2     |   0\n \t *   7  |  file |    2     |   -1     |   2\n-\t *   8  |  file |    2     |    0     |   2\n+\t *   8  |  file |    2     |    0     |   1\n \t *   9  |  file |    2     |    1     |   0\n \t *  10  |  file |    2     |    2     |  -1\n \t * -----+-------+----------+----------+-------\n@@ -1118,7 +1118,7 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,\n \t *  15  |  dir  |    1     |    1     |   1 (*)\n \t *  16  |  dir  |    1     |    2     |   0\n \t *  17  |  dir  |    2     |   -1     |   2\n-\t *  18  |  dir  |    2     |    0     |   2\n+\t *  18  |  dir  |    2     |    0     |   1\n \t *  19  |  dir  |    2     |    1     |   1 (*)\n \t *  20  |  dir  |    2     |    2     |  -1\n \t *\n@@ -1134,7 +1134,12 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,\n \n \tnegative = do_match(entry, base, base_offset, ps, 1);\n \n-\t/* #3, #4, #7, #8, #13, #14, #17, #18 */\n+\t/* #8, #18 */\n+\tif (positive == all_entries_interesting &&\n+\t    negative == entry_not_interesting)\n+\t\treturn entry_interesting;\n+\n+\t/* #3, #4, #7, #13, #14, #17 */\n \tif (negative <= entry_not_interesting)\n \t\treturn positive;\n \n-- \n2.19.1.1005.gac84295441\n\n"},{"id":"362378","messageId":"CAPig+cS7b0nenb0+0jyXE=-bDkhapmYE8Yr6VfyAWRq3ydjPOg@mail.gmail.com","threadId":"49664","inReplyTo":"20181103153049.22850-1-pclouds@gmail.com","subject":"Re: [PATCH] tree-walk.c: fix overoptimistic inclusion in :(exclude) matching","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-11-04T00:25:14Z","receivedAt":"2018-11-04T00:25:28Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, Nov 3, 2018 at 11:31 AM Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> Rules 8 and 18 are now updated to be less eager. We conclude that the\n> current entry is positively matched and included. But we say nothing\n> about remaining entries. tree_entry_interesting() will be called again\n> for those entries where we will determine entries individually.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n> diff --git a/t/t6132-pathspec-exclude.sh b/t/t6132-pathspec-exclude.sh\n> @@ -194,4 +194,21 @@ test_expect_success 'multiple exclusions' '\n> +test_expect_success 't_e_i() exclude case #8' '\n> +       git init case8 &&\n> +       (\n> +               cd case8 &&\n> +               echo file >file1 &&\n> +               echo file >file2 &&\n> +               git add . &&\n\nWon't this loose git-add invocation end up adding all the junk files\nfrom earlier tests? One might have expected to see the more restricted\ninvocation:\n\n    git add file1 file2 &&\n\nto make it easier to reason about the test and not worry about someone\nlater inserting tests above this one which might interfere with it.\n\n> +               git commit -m twofiles &&\n> +               git grep -l file HEAD :^file2 >actual &&\n> +               echo HEAD:file1 >expected &&\n> +               test_cmp expected actual &&\n> +               git grep -l file HEAD :^file1 >actual &&\n> +               echo HEAD:file2 >expected &&\n> +               test_cmp expected actual\n> +       )\n> +'\n"},{"id":"362385","messageId":"20181104052851.12584-1-pclouds@gmail.com","threadId":"49664","inReplyTo":"20181103153049.22850-1-pclouds@gmail.com","subject":"[PATCH v2] tree-walk.c: fix overoptimistic inclusion in :(exclude) matching","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-11-04T05:28:51Z","receivedAt":"2018-11-04T05:31:47Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"tree_entry_interesting() is used for matching pathspec on a tree. The\ninteresting thing about this function is that, because the tree\nentries are known to be sorted, this function can return more than\njust \"yes, matched\" and \"no, not matched\". It can also say \"yes, this\nentry is matched and so is the remaining entries in the tree\".\n\nThis is where I made a mistake when matching exclude pathspec. For\nexclude pathspec, we do matching twice, one with positive patterns and\none with negative ones, then a rule table is applied to determine the\nfinal \"include or exclude\" result. Note that \"matched\" does not\nnecessarily mean include. For negative patterns, \"matched\" means\nexclude.\n\nThis particular rule is too eager to include everything. Rule 8 says\nthat \"if all entries are positively matched\" and the current entry is\nnot negatively matched (i.e. not excluded), then all entries are\npositively matched and therefore included. But this is not true. If\nthe _current_ entry is not negatively matched, it does not mean the\nnext one will not be and we cannot conclude right away that all\nremaining entries are positively matched and can be included.\n\nRules 8 and 18 are now updated to be less eager. We conclude that the\ncurrent entry is positively matched and included. But we say nothing\nabout remaining entries. tree_entry_interesting() will be called again\nfor those entries where we will determine entries individually.\n\nReported-by: Christophe Bliard <christophe.bliard@trux.info>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n v2 fixes the too broad \"git add .\" in the test\n\n t/t6132-pathspec-exclude.sh | 17 +++++++++++++++++\n tree-walk.c                 | 11 ++++++++---\n 2 files changed, 25 insertions(+), 3 deletions(-)\n\ndiff --git a/t/t6132-pathspec-exclude.sh b/t/t6132-pathspec-exclude.sh\nindex eb829fce97..2462b19ddd 100755\n--- a/t/t6132-pathspec-exclude.sh\n+++ b/t/t6132-pathspec-exclude.sh\n@@ -194,4 +194,21 @@ test_expect_success 'multiple exclusions' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 't_e_i() exclude case #8' '\n+\tgit init case8 &&\n+\t(\n+\t\tcd case8 &&\n+\t\techo file >file1 &&\n+\t\techo file >file2 &&\n+\t\tgit add file1 file2 &&\n+\t\tgit commit -m twofiles &&\n+\t\tgit grep -l file HEAD :^file2 >actual &&\n+\t\techo HEAD:file1 >expected &&\n+\t\ttest_cmp expected actual &&\n+\t\tgit grep -l file HEAD :^file1 >actual &&\n+\t\techo HEAD:file2 >expected &&\n+\t\ttest_cmp expected actual\n+\t)\n+'\n+\n test_done\ndiff --git a/tree-walk.c b/tree-walk.c\nindex 77b37f36fa..79bafbd1a2 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -1107,7 +1107,7 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,\n \t *   5  |  file |    1     |    1     |   0\n \t *   6  |  file |    1     |    2     |   0\n \t *   7  |  file |    2     |   -1     |   2\n-\t *   8  |  file |    2     |    0     |   2\n+\t *   8  |  file |    2     |    0     |   1\n \t *   9  |  file |    2     |    1     |   0\n \t *  10  |  file |    2     |    2     |  -1\n \t * -----+-------+----------+----------+-------\n@@ -1118,7 +1118,7 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,\n \t *  15  |  dir  |    1     |    1     |   1 (*)\n \t *  16  |  dir  |    1     |    2     |   0\n \t *  17  |  dir  |    2     |   -1     |   2\n-\t *  18  |  dir  |    2     |    0     |   2\n+\t *  18  |  dir  |    2     |    0     |   1\n \t *  19  |  dir  |    2     |    1     |   1 (*)\n \t *  20  |  dir  |    2     |    2     |  -1\n \t *\n@@ -1134,7 +1134,12 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,\n \n \tnegative = do_match(entry, base, base_offset, ps, 1);\n \n-\t/* #3, #4, #7, #8, #13, #14, #17, #18 */\n+\t/* #8, #18 */\n+\tif (positive == all_entries_interesting &&\n+\t    negative == entry_not_interesting)\n+\t\treturn entry_interesting;\n+\n+\t/* #3, #4, #7, #13, #14, #17 */\n \tif (negative <= entry_not_interesting)\n \t\treturn positive;\n \n-- \n2.19.1.1005.gac84295441\n\n"},{"id":"362386","messageId":"CAPig+cQTaG=pTQ_fQp8gv-4+bzJrSGCy8zK_iDeJsFNeX+4Cpg@mail.gmail.com","threadId":"49664","inReplyTo":"CAPig+cS7b0nenb0+0jyXE=-bDkhapmYE8Yr6VfyAWRq3ydjPOg@mail.gmail.com","subject":"Re: [PATCH] tree-walk.c: fix overoptimistic inclusion in :(exclude) matching","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-11-04T06:27:31Z","receivedAt":"2018-11-04T06:27:45Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, Nov 3, 2018 at 8:25 PM Eric Sunshine <sunshine@sunshineco.com> wrote:\n> On Sat, Nov 3, 2018 at 11:31 AM Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> > +test_expect_success 't_e_i() exclude case #8' '\n> > +       git init case8 &&\n> > +       (\n> > +               cd case8 &&\n> > +               echo file >file1 &&\n> > +               echo file >file2 &&\n> > +               git add . &&\n>\n> Won't this loose git-add invocation end up adding all the junk files\n> from earlier tests? One might have expected to see the more restricted\n> invocation:\n>     git add file1 file2 &&\n> to make it easier to reason about the test and not worry about someone\n> later inserting tests above this one which might interfere with it.\n\nUpon reflection, there shouldn't be any junk files since this test is\ncreating a new repository and \"file1\" and \"file2\" are the only files\npresent. Apparently, I wasn't paying close enough attention when I\nmade the earlier observation.\n\nAnyhow, the more restricted git-add invocation you used in the re-roll\nis still preferable since it makes the intention obvious. Thanks.\n"},{"id":"362387","messageId":"CACsJy8DPF8XFCkppnh6iyY3noQG-OMbqq3+LNm1iaotCSr-znw@mail.gmail.com","threadId":"49664","inReplyTo":"CAPig+cQTaG=pTQ_fQp8gv-4+bzJrSGCy8zK_iDeJsFNeX+4Cpg@mail.gmail.com","subject":"Re: [PATCH] tree-walk.c: fix overoptimistic inclusion in :(exclude) matching","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-11-04T06:29:16Z","receivedAt":"2018-11-04T06:29:45Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, Nov 4, 2018 at 7:27 AM Eric Sunshine <sunshine@sunshineco.com> wrote:\n>\n> On Sat, Nov 3, 2018 at 8:25 PM Eric Sunshine <sunshine@sunshineco.com> wrote:\n> > On Sat, Nov 3, 2018 at 11:31 AM Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> > > +test_expect_success 't_e_i() exclude case #8' '\n> > > +       git init case8 &&\n> > > +       (\n> > > +               cd case8 &&\n> > > +               echo file >file1 &&\n> > > +               echo file >file2 &&\n> > > +               git add . &&\n> >\n> > Won't this loose git-add invocation end up adding all the junk files\n> > from earlier tests? One might have expected to see the more restricted\n> > invocation:\n> >     git add file1 file2 &&\n> > to make it easier to reason about the test and not worry about someone\n> > later inserting tests above this one which might interfere with it.\n>\n> Upon reflection, there shouldn't be any junk files since this test is\n> creating a new repository and \"file1\" and \"file2\" are the only files\n> present. Apparently, I wasn't paying close enough attention when I\n> made the earlier observation.\n\nYup.\n\n> Anyhow, the more restricted git-add invocation you used in the re-roll\n> is still preferable since it makes the intention obvious. Thanks.\n\nWhich is why I did it anyway :)\n-- \nDuy\n"},{"id":"362441","messageId":"xmqq36sgl2d2.fsf@gitster-ct.c.googlers.com","threadId":"49664","inReplyTo":"20181104052851.12584-1-pclouds@gmail.com","subject":"Re: [PATCH v2] tree-walk.c: fix overoptimistic inclusion in :(exclude) matching","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-11-05T01:50:01Z","receivedAt":"2018-11-05T01:50:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> tree_entry_interesting() is used for matching pathspec on a tree. The\n> interesting thing about this function is that, because the tree\n> entries are known to be sorted, this function can return more than\n> just \"yes, matched\" and \"no, not matched\". It can also say \"yes, this\n> entry is matched and so is the remaining entries in the tree\".\n>\n> This is where I made a mistake when matching exclude pathspec. For\n> exclude pathspec, we do matching twice, one with positive patterns and\n> one with negative ones, then a rule table is applied to determine the\n> final \"include or exclude\" result. Note that \"matched\" does not\n> necessarily mean include. For negative patterns, \"matched\" means\n> exclude.\n>\n> This particular rule is too eager to include everything. Rule 8 says\n> that \"if all entries are positively matched\" and the current entry is\n> not negatively matched (i.e. not excluded), then all entries are\n> positively matched and therefore included. But this is not true. If\n> the _current_ entry is not negatively matched, it does not mean the\n> next one will not be and we cannot conclude right away that all\n> remaining entries are positively matched and can be included.\n>\n> Rules 8 and 18 are now updated to be less eager. We conclude that the\n> current entry is positively matched and included. But we say nothing\n> about remaining entries. tree_entry_interesting() will be called again\n> for those entries where we will determine entries individually.\n\nThanks.  Will queue.\n\n> Reported-by: Christophe Bliard <christophe.bliard@trux.info>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  v2 fixes the too broad \"git add .\" in the test\n>\n>  t/t6132-pathspec-exclude.sh | 17 +++++++++++++++++\n>  tree-walk.c                 | 11 ++++++++---\n>  2 files changed, 25 insertions(+), 3 deletions(-)\n>\n> diff --git a/t/t6132-pathspec-exclude.sh b/t/t6132-pathspec-exclude.sh\n> index eb829fce97..2462b19ddd 100755\n> --- a/t/t6132-pathspec-exclude.sh\n> +++ b/t/t6132-pathspec-exclude.sh\n> @@ -194,4 +194,21 @@ test_expect_success 'multiple exclusions' '\n>  \ttest_cmp expect actual\n>  '\n>  \n> +test_expect_success 't_e_i() exclude case #8' '\n> +\tgit init case8 &&\n> +\t(\n> +\t\tcd case8 &&\n> +\t\techo file >file1 &&\n> +\t\techo file >file2 &&\n> +\t\tgit add file1 file2 &&\n> +\t\tgit commit -m twofiles &&\n> +\t\tgit grep -l file HEAD :^file2 >actual &&\n> +\t\techo HEAD:file1 >expected &&\n> +\t\ttest_cmp expected actual &&\n> +\t\tgit grep -l file HEAD :^file1 >actual &&\n> +\t\techo HEAD:file2 >expected &&\n> +\t\ttest_cmp expected actual\n> +\t)\n> +'\n> +\n>  test_done\n> diff --git a/tree-walk.c b/tree-walk.c\n> index 77b37f36fa..79bafbd1a2 100644\n> --- a/tree-walk.c\n> +++ b/tree-walk.c\n> @@ -1107,7 +1107,7 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,\n>  \t *   5  |  file |    1     |    1     |   0\n>  \t *   6  |  file |    1     |    2     |   0\n>  \t *   7  |  file |    2     |   -1     |   2\n> -\t *   8  |  file |    2     |    0     |   2\n> +\t *   8  |  file |    2     |    0     |   1\n>  \t *   9  |  file |    2     |    1     |   0\n>  \t *  10  |  file |    2     |    2     |  -1\n>  \t * -----+-------+----------+----------+-------\n> @@ -1118,7 +1118,7 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,\n>  \t *  15  |  dir  |    1     |    1     |   1 (*)\n>  \t *  16  |  dir  |    1     |    2     |   0\n>  \t *  17  |  dir  |    2     |   -1     |   2\n> -\t *  18  |  dir  |    2     |    0     |   2\n> +\t *  18  |  dir  |    2     |    0     |   1\n>  \t *  19  |  dir  |    2     |    1     |   1 (*)\n>  \t *  20  |  dir  |    2     |    2     |  -1\n>  \t *\n> @@ -1134,7 +1134,12 @@ enum interesting tree_entry_interesting(const struct name_entry *entry,\n>  \n>  \tnegative = do_match(entry, base, base_offset, ps, 1);\n>  \n> -\t/* #3, #4, #7, #8, #13, #14, #17, #18 */\n> +\t/* #8, #18 */\n> +\tif (positive == all_entries_interesting &&\n> +\t    negative == entry_not_interesting)\n> +\t\treturn entry_interesting;\n> +\n> +\t/* #3, #4, #7, #13, #14, #17 */\n>  \tif (negative <= entry_not_interesting)\n>  \t\treturn positive;\n"}]}