{"thread":{"id":"41605","subject":"Change in .gitignore handling: intended or bug?","startedAt":"2016-03-04T02:11:56Z","lastAt":"2016-03-10T10:56:12Z","messageCount":28,"participants":["Charles Strahan","Duy Nguyen","Kevin Daudt","Junio C Hamano","Nguyễn Thái Ngọc Duy"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"280165","messageId":"1457057516.1962831.539160698.3C8B30BC@webmail.messagingengine.com","threadId":"41605","inReplyTo":null,"subject":"Change in .gitignore handling: intended or bug?","fromName":"Charles Strahan","fromEmail":"charles@cstrahan.com","sentAt":"2016-03-04T02:11:56Z","receivedAt":"2016-03-04T02:11:56Z","isPatch":false,"sender":{"key":"charles@cstrahan.com","avatar":"https://gravatar.com/avatar/bc62fe057ea576649ad0a85405c7d3c32c6a28ee55d1d5d1b9cf62efc6080f4b?d=mp&s=160"},"body":"Hello,\n\nI've found a change in the way .gitignore works, and I'm not sure if\nit's a bug\nor intended.\n\nPreviously, one could use the following .gitignore:\n\n    *\n    !/foo\n    !/foo/bar.txt\n    !/baz\n    !/baz/quux\n    !/baz/quux/**/*\n\nAnd these files would be seen by git:\n\n    foo/bar.txt\n    baz/quux/grault.txt\n    baz/quux/corge/wibble.txt\n\nAnd these files would be ignored:\n\n    foo/garply.txt\n    baz/waldo.txt\n\nAt some point (between git 2.6.0 and 2.7.0, I think), the behavior\nchanged such\nthat _none_ of the files above would be ignored. Previously, git would\ntreat\n!/foo as an indication that it should not prune /foo, but that\n_wouldn't_ be\nsufficient to un-ignore the contents thereof. Now, it seems the new\nscheme\ntreats !/foo as functionally equivalent to !/foo followed by !/foo/**/*\nin the\nold scheme.\n\nI manage my home directory by making it a git repo, and using\n~/.gitignore to\nselectively permit certain files or subdirectories to be seen by git.\nThe recent\nchange in behavior has resulted in sensitive directories like ~/.gpg\nbeing\nun-ignored. For reference, I've appended my .gitignore to the end of\nthis email.\n\nSo, is this behavior intended, or is this a bug? If the former, is there\nan\nannouncement explaining this change?\n\n-Charles\n\n(.gitignore is as follows)\n\n*\n!/.Xdefaults\n!/.Xresources\n!/.ackrc\n!/.bash_profile\n!/.config\n!/.config/dunst\n!/.config/dunst/dunstrc\n!/.config/taffybar\n!/.config/taffybar/taffybar.hs\n!/.config/taffybar/taffybar.rc\n!/.ctags\n!/.gdb\n!/.gdb/**/*\n!/.gdbinit\n!/.gemrc\n!/.ghci\n!/.git_template\n!/.git_template/**/*\n!/.gitexcludes\n!/.gitignore\n!/.gnupg\n!/.gnupg/dirmngr.conf\n!/.gnupg/gpg.conf\n!/.goobook/\n!/.goobook/decipher\n!/.goobook/decipher/goobookrc\n!/.inputrc\n!/.irbrc\n!/.irssi\n!/.irssi/**/*\n!/.mbsyncrc\n!/.msmtprc\n!/.mutt\n!/.mutt/accounts\n!/.mutt/accounts/*\n!/.mutt/gpg.rc\n!/.mutt/mailcap\n!/.mutt/muttrc\n!/.mutt/signature\n!/.mutt/theme/*\n!/.nixpkgs\n!/.nixpkgs/**/*\n!/.notmuch-config\n!/.pystartup\n!/.tmux\n!/.tmux.conf\n!/.tmux/**/*\n!/.vim\n!/.vim/**/*\n!/.vimrc\n!/.xmonad\n!/.xmonad/xmonad.hs\n!/.xsession\n!/.zlogin\n!/.zprofile\n!/.zsh\n!/.zsh/**/*\n!/.zshenv\n!/.zshrc\n!/osx\n"},{"id":"280166","messageId":"CACsJy8Csx5ZBQqp0cP0YE-b==Uwfj+fPa6EfHi-fht9oCHTK=A@mail.gmail.com","threadId":"41605","inReplyTo":"1457057516.1962831.539160698.3C8B30BC@webmail.messagingengine.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-03-04T03:09:05Z","receivedAt":"2016-03-04T03:09:05Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, Mar 4, 2016 at 9:11 AM, Charles Strahan <charles@cstrahan.com> wrote:\n> Hello,\n>\n> I've found a change in the way .gitignore works, and I'm not sure if\n> it's a bug\n> or intended.\n\nCan't look into this just yet. Quick question, what's the git version\nyou're currently running?\n-- \nDuy\n"},{"id":"280170","messageId":"20160304055117.GB26609@ikke.info","threadId":"41605","inReplyTo":"1457057516.1962831.539160698.3C8B30BC@webmail.messagingengine.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Kevin Daudt","fromEmail":"me@ikke.info","sentAt":"2016-03-04T05:51:17Z","receivedAt":"2016-03-04T05:51:17Z","isPatch":false,"sender":{"key":"me@ikke.info","avatar":"https://avatars.githubusercontent.com/u/135698?v=4"},"body":"On Thu, Mar 03, 2016 at 09:11:56PM -0500, Charles Strahan wrote:\n> Hello,\n> \n> I've found a change in the way .gitignore works, and I'm not sure if\n> it's a bug\n> or intended.\n> \n> Previously, one could use the following .gitignore:\n> \n>     *\n>     !/foo\n>     !/foo/bar.txt\n>     !/baz\n>     !/baz/quux\n>     !/baz/quux/**/*\n> \n> And these files would be seen by git:\n> \n>     foo/bar.txt\n>     baz/quux/grault.txt\n>     baz/quux/corge/wibble.txt\n> \n> And these files would be ignored:\n> \n>     foo/garply.txt\n>     baz/waldo.txt\n> \n> At some point (between git 2.6.0 and 2.7.0, I think), the behavior\n> changed such\n> that _none_ of the files above would be ignored. Previously, git would\n> treat\n> !/foo as an indication that it should not prune /foo, but that\n> _wouldn't_ be\n> sufficient to un-ignore the contents thereof. Now, it seems the new\n> scheme\n> treats !/foo as functionally equivalent to !/foo followed by !/foo/**/*\n> in the\n> old scheme.\n> \n> I manage my home directory by making it a git repo, and using\n> ~/.gitignore to\n> selectively permit certain files or subdirectories to be seen by git.\n> The recent\n> change in behavior has resulted in sensitive directories like ~/.gpg\n> being\n> un-ignored. For reference, I've appended my .gitignore to the end of\n> this email.\n> \n> So, is this behavior intended, or is this a bug? If the former, is there\n> an\n> announcement explaining this change?\n> \n> -Charles\n> \n> [snip]\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\nWorks as intended for me:\n\n├── baz\n│   ├── quux\n│   │   ├── corge\n│   │   │   └── wibble.txt\n│   │   └── grault.txt\n│   └── waldo.txt\n└── foo\n    ├── bar.txt\n    └── garply.txt\n\n$ git status -s -uall\n?? baz/quux/corge/wibble.txt\n?? baz/quux/grault.txt\n?? foo/bar.txt\n\ngarply.txt and waldo.txt are ignore, but the rest is still tracked.\n\nI'm on 2.7.2.\n"},{"id":"280171","messageId":"1457071957.2027843.539286050.10CF8D0A@webmail.messagingengine.com","threadId":"41605","inReplyTo":"20160304055117.GB26609@ikke.info","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Charles Strahan","fromEmail":"charles@cstrahan.com","sentAt":"2016-03-04T06:12:37Z","receivedAt":"2016-03-04T06:12:37Z","isPatch":false,"sender":{"key":"charles@cstrahan.com","avatar":"https://gravatar.com/avatar/bc62fe057ea576649ad0a85405c7d3c32c6a28ee55d1d5d1b9cf62efc6080f4b?d=mp&s=160"},"body":"I'm on 2.7.0.\n\nHere's a quick sanity check:\n\n├── baz\n│   ├── quux\n│   │   ├── corge\n│   │   │   └── wibble.txt\n│   │   └── grault.txt\n│   └── waldo.txt\n└── foo\n    ├── bar.txt\n    └── garply.txt\n\n$ git --version\ngit version 2.7.0\n\n$ git status -sb -uall\n## Initial commit on master\n?? baz/quux/corge/wibble.txt\n?? baz/quux/grault.txt\n?? baz/waldo.txt\n?? foo/bar.txt\n?? foo/garply.txt\n\n\nFor the lazy (such as myself), this will set up an identical tree:\n\nmkdir -p foo\nmkdir -p baz/quux/corge\ntouch foo/bar.txt\ntouch foo/garply.txt\ntouch baz/waldo.txt\ntouch baz/quux/grault.txt\ntouch baz/quux/corge/wibble.txt\ncat <<\"EOF\" > .gitignore\n*\n!/foo\n!/foo/bar.txt\n!/baz\n!/baz/quux\n!/baz/quux/**/*\nEOF\n\n\nI just checked https://git-scm.com/docs/gitignore and the example at the\nbottom\nsuggests that this behavior may be expected:\n\n    $ cat .gitignore\n    # exclude everything except directory foo/bar\n    /*\n    !/foo\n    /foo/*\n    !/foo/bar\n\nNote the /foo/*, explicitly ignoring the entries below /foo.\n\nThis wasn't always the case, though, so I'd love to hear if it was\nintentional\n(or if I've lost my mind, which is quite possible).\n\n-Charles\n\n\n\nOn Fri, Mar 4, 2016, at 12:51 AM, Kevin Daudt wrote:\n> On Thu, Mar 03, 2016 at 09:11:56PM -0500, Charles Strahan wrote:\n> > Hello,\n> > \n> > I've found a change in the way .gitignore works, and I'm not sure if\n> > it's a bug\n> > or intended.\n> > \n> > Previously, one could use the following .gitignore:\n> > \n> >     *\n> >     !/foo\n> >     !/foo/bar.txt\n> >     !/baz\n> >     !/baz/quux\n> >     !/baz/quux/**/*\n> > \n> > And these files would be seen by git:\n> > \n> >     foo/bar.txt\n> >     baz/quux/grault.txt\n> >     baz/quux/corge/wibble.txt\n> > \n> > And these files would be ignored:\n> > \n> >     foo/garply.txt\n> >     baz/waldo.txt\n> > \n> > At some point (between git 2.6.0 and 2.7.0, I think), the behavior\n> > changed such\n> > that _none_ of the files above would be ignored. Previously, git would\n> > treat\n> > !/foo as an indication that it should not prune /foo, but that\n> > _wouldn't_ be\n> > sufficient to un-ignore the contents thereof. Now, it seems the new\n> > scheme\n> > treats !/foo as functionally equivalent to !/foo followed by !/foo/**/*\n> > in the\n> > old scheme.\n> > \n> > I manage my home directory by making it a git repo, and using\n> > ~/.gitignore to\n> > selectively permit certain files or subdirectories to be seen by git.\n> > The recent\n> > change in behavior has resulted in sensitive directories like ~/.gpg\n> > being\n> > un-ignored. For reference, I've appended my .gitignore to the end of\n> > this email.\n> > \n> > So, is this behavior intended, or is this a bug? If the former, is there\n> > an\n> > announcement explaining this change?\n> > \n> > -Charles\n> > \n> > [snip]\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> Works as intended for me:\n> \n> ├── baz\n> │   ├── quux\n> │   │   ├── corge\n> │   │   │   └── wibble.txt\n> │   │   └── grault.txt\n> │   └── waldo.txt\n> └── foo\n>     ├── bar.txt\n>     └── garply.txt\n> \n> $ git status -s -uall\n> ?? baz/quux/corge/wibble.txt\n> ?? baz/quux/grault.txt\n> ?? foo/bar.txt\n> \n> garply.txt and waldo.txt are ignore, but the rest is still tracked.\n> \n> I'm on 2.7.2.\n"},{"id":"280187","messageId":"20160304115634.GC26609@ikke.info","threadId":"41605","inReplyTo":"1457071957.2027843.539286050.10CF8D0A@webmail.messagingengine.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Kevin Daudt","fromEmail":"me@ikke.info","sentAt":"2016-03-04T11:56:34Z","receivedAt":"2016-03-04T11:56:34Z","isPatch":false,"sender":{"key":"me@ikke.info","avatar":"https://avatars.githubusercontent.com/u/135698?v=4"},"body":"On Fri, Mar 04, 2016 at 01:12:37AM -0500, Charles Strahan wrote:\n> I'm on 2.7.0.\n> \n> Here's a quick sanity check:\n> \n> ├── baz\n> │   ├── quux\n> │   │   ├── corge\n> │   │   │   └── wibble.txt\n> │   │   └── grault.txt\n> │   └── waldo.txt\n> └── foo\n>     ├── bar.txt\n>     └── garply.txt\n> \n> $ git --version\n> git version 2.7.0\n> \n> $ git status -sb -uall\n> ## Initial commit on master\n> ?? baz/quux/corge/wibble.txt\n> ?? baz/quux/grault.txt\n> ?? baz/waldo.txt\n> ?? foo/bar.txt\n> ?? foo/garply.txt\n> \n> \n> For the lazy (such as myself), this will set up an identical tree:\n> \n> mkdir -p foo\n> mkdir -p baz/quux/corge\n> touch foo/bar.txt\n> touch foo/garply.txt\n> touch baz/waldo.txt\n> touch baz/quux/grault.txt\n> touch baz/quux/corge/wibble.txt\n> cat <<\"EOF\" > .gitignore\n> *\n> !/foo\n> !/foo/bar.txt\n> !/baz\n> !/baz/quux\n> !/baz/quux/**/*\n> EOF\n> \n> \n> I just checked https://git-scm.com/docs/gitignore and the example at the\n> bottom\n> suggests that this behavior may be expected:\n> \n>     $ cat .gitignore\n>     # exclude everything except directory foo/bar\n>     /*\n>     !/foo\n>     /foo/*\n>     !/foo/bar\n> \n> Note the /foo/*, explicitly ignoring the entries below /foo.\n> \n> This wasn't always the case, though, so I'd love to hear if it was\n> intentional\n> (or if I've lost my mind, which is quite possible).\n> \n> -Charles\n> \n> \n> \n> On Fri, Mar 4, 2016, at 12:51 AM, Kevin Daudt wrote:\n> > On Thu, Mar 03, 2016 at 09:11:56PM -0500, Charles Strahan wrote:\n> > > Hello,\n> > > \n> > > I've found a change in the way .gitignore works, and I'm not sure if\n> > > it's a bug\n> > > or intended.\n> > > \n> > > Previously, one could use the following .gitignore:\n> > > \n> > >     *\n> > >     !/foo\n> > >     !/foo/bar.txt\n> > >     !/baz\n> > >     !/baz/quux\n> > >     !/baz/quux/**/*\n> > > \n> > > And these files would be seen by git:\n> > > \n> > >     foo/bar.txt\n> > >     baz/quux/grault.txt\n> > >     baz/quux/corge/wibble.txt\n> > > \n> > > And these files would be ignored:\n> > > \n> > >     foo/garply.txt\n> > >     baz/waldo.txt\n> > > \n> > > At some point (between git 2.6.0 and 2.7.0, I think), the behavior\n> > > changed such\n> > > that _none_ of the files above would be ignored. Previously, git would\n> > > treat\n> > > !/foo as an indication that it should not prune /foo, but that\n> > > _wouldn't_ be\n> > > sufficient to un-ignore the contents thereof. Now, it seems the new\n> > > scheme\n> > > treats !/foo as functionally equivalent to !/foo followed by !/foo/**/*\n> > > in the\n> > > old scheme.\n> > > \n> > > I manage my home directory by making it a git repo, and using\n> > > ~/.gitignore to\n> > > selectively permit certain files or subdirectories to be seen by git.\n> > > The recent\n> > > change in behavior has resulted in sensitive directories like ~/.gpg\n> > > being\n> > > un-ignored. For reference, I've appended my .gitignore to the end of\n> > > this email.\n> > > \n> > > So, is this behavior intended, or is this a bug? If the former, is there\n> > > an\n> > > announcement explaining this change?\n> > > \n> > > -Charles\n> > > \n> > > [snip]\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> > Works as intended for me:\n> > \n> > ├── baz\n> > │   ├── quux\n> > │   │   ├── corge\n> > │   │   │   └── wibble.txt\n> > │   │   └── grault.txt\n> > │   └── waldo.txt\n> > └── foo\n> >     ├── bar.txt\n> >     └── garply.txt\n> > \n> > $ git status -s -uall\n> > ?? baz/quux/corge/wibble.txt\n> > ?? baz/quux/grault.txt\n> > ?? foo/bar.txt\n> > \n> > garply.txt and waldo.txt are ignore, but the rest is still tracked.\n> > \n> > I'm on 2.7.2.\n> --\n\nVerified that it's different in 2.7.0, but 2.7.2 gives expected output.\n"},{"id":"280190","messageId":"CACsJy8AN7xxFuVX4c6aR_RdDiuDRPjqbXS8Y2+xD4pV8G2onfg@mail.gmail.com","threadId":"41605","inReplyTo":"20160304115634.GC26609@ikke.info","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-03-04T12:36:46Z","receivedAt":"2016-03-04T12:36:46Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, Mar 4, 2016 at 6:56 PM, Kevin Daudt <me@ikke.info> wrote:\n> Verified that it's different in 2.7.0, but 2.7.2 gives expected output.\n\nThanks. 2.7.1 reverts the faulty commit from 2.7.0 that generated two\nother regression reports before this one. I guess it's all good then\n(except for the people still on 2.7.0)\n-- \nDuy\n"},{"id":"280200","messageId":"xmqq4mcm17b4.fsf@gitster.mtv.corp.google.com","threadId":"41605","inReplyTo":"CACsJy8AN7xxFuVX4c6aR_RdDiuDRPjqbXS8Y2+xD4pV8G2onfg@mail.gmail.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-04T17:28:31Z","receivedAt":"2016-03-04T17:28:31Z","isPatch":false,"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, Mar 4, 2016 at 6:56 PM, Kevin Daudt <me@ikke.info> wrote:\n>> Verified that it's different in 2.7.0, but 2.7.2 gives expected output.\n>\n> Thanks. 2.7.1 reverts the faulty commit from 2.7.0 that generated two\n> other regression reports before this one. I guess it's all good then\n> (except for the people still on 2.7.0)\n\nAre we good at 2.8.0-rc0, too?  Somehow I had an impression that we\nqueued \"another attempt to do it differently\" or something.\n\n ... goes and looks ...\n\n    $ rungit maint status -suall\n    ?? baz/quux/corge/wibble.txt\n    ?? baz/quux/grault.txt\n    ?? foo/bar.txt\n    $ rungit master status -suall\n    ?? baz/quux/corge/wibble.txt\n    ?? baz/quux/grault.txt\n    ?? baz/waldo.txt\n    ?? foo/bar.txt\n    ?? foo/garply.txt\n"},{"id":"280210","messageId":"xmqqbn6uys4o.fsf@gitster.mtv.corp.google.com","threadId":"41605","inReplyTo":"xmqq4mcm17b4.fsf@gitster.mtv.corp.google.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-04T19:12:23Z","receivedAt":"2016-03-04T19:12:23Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Duy Nguyen <pclouds@gmail.com> writes:\n>\n>> On Fri, Mar 4, 2016 at 6:56 PM, Kevin Daudt <me@ikke.info> wrote:\n>>> Verified that it's different in 2.7.0, but 2.7.2 gives expected output.\n>>\n>> Thanks. 2.7.1 reverts the faulty commit from 2.7.0 that generated two\n>> other regression reports before this one. I guess it's all good then\n>> (except for the people still on 2.7.0)\n>\n> Are we good at 2.8.0-rc0, too?  Somehow I had an impression that we\n> queued \"another attempt to do it differently\" or something.\n>\n>  ... goes and looks ...\n>\n>     $ rungit maint status -suall\n>     ?? baz/quux/corge/wibble.txt\n>     ?? baz/quux/grault.txt\n>     ?? foo/bar.txt\n>     $ rungit master status -suall\n>     ?? baz/quux/corge/wibble.txt\n>     ?? baz/quux/grault.txt\n>     ?? baz/waldo.txt\n>     ?? foo/bar.txt\n>     ?? foo/garply.txt\n\nIt seems to bisect down to this one between maint..master:\n\ncommit a60ea8fb66945a886ea53fd3f41e61cc5fb3201e\nAuthor: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\nDate:   Mon Feb 15 16:03:36 2016 +0700\n\n    dir.c: fix match_pathname()\n    \n    Given the pattern \"1/2/3/4\" and the path \"1/2/3/4/f\", the pattern\n    prefix is \"1/2/3/4\". We will compare and remove the prefix from both\n    pattern and path and come to this code\n    \n        /*\n         * If the whole pattern did not have a wildcard,\n         * then our prefix match is all we need; we\n         * do not need to call fnmatch at all.\n         */\n        if (!patternlen && !namelen)\n                return 1;\n    \n    where patternlen is zero (full pattern consumed) and the remaining\n    path in \"name\" is \"/f\". We fail to realize it's matched in this case\n    and fall back to fnmatch(), which also fails to catch it. Fix it.\n    \n    Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n    Signed-off-by: Junio C Hamano <gitster@pobox.com>\n\nBut I do not think this change alone is the culprit; the change\nitself does make sense in the context of the series.\n\nAt this point, we have two choices.  Either we revert the merge of\nthe whole series:\n\n    commit 5e57f9c3dfe7dd44a1b56bb5b3327d7a1356ec7c\n    Merge: e79112d d589a67\n    Author: Junio C Hamano <gitster@pobox.com>\n    Date:   Wed Feb 24 13:25:59 2016 -0800\n\n        Merge branch 'nd/exclusion-regression-fix'\n\n        Another try to add support to the ignore mechanism that lets you\n        say \"this is excluded\" and then later say \"oh, no, this part (that\n        is a subset of the previous part) is not excluded\".\n\n        * nd/exclusion-regression-fix:\n          dir.c: don't exclude whole dir prematurely\n          dir.c: support marking some patterns already matched\n          dir.c: support tracing exclude\n          dir.c: fix match_pathname()\n\nto go back to the 2.7.2 behaviour, or add a follow-on change to the\nnd/exclusion-regression-fix topic to fix what it wanted to fix\nwithout breaking Charles's use case.  I am inclined to go for the\nformer (unless the follow-on fix is really trivial), but I haven't\ndug into the codebase myself yet, so...\n"},{"id":"280221","messageId":"CACsJy8BZm9pFdR+Njst7qZ1UnHUL9XpigM5pW+CLEicOc7ra8g@mail.gmail.com","threadId":"41605","inReplyTo":"xmqq4mcm17b4.fsf@gitster.mtv.corp.google.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-03-05T00:43:37Z","receivedAt":"2016-03-05T00:43:37Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sat, Mar 5, 2016 at 12:28 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Duy Nguyen <pclouds@gmail.com> writes:\n>\n>> On Fri, Mar 4, 2016 at 6:56 PM, Kevin Daudt <me@ikke.info> wrote:\n>>> Verified that it's different in 2.7.0, but 2.7.2 gives expected output.\n>>\n>> Thanks. 2.7.1 reverts the faulty commit from 2.7.0 that generated two\n>> other regression reports before this one. I guess it's all good then\n>> (except for the people still on 2.7.0)\n>\n> Are we good at 2.8.0-rc0, too?  Somehow I had an impression that we\n> queued \"another attempt to do it differently\" or something.\n>\n>  ... goes and looks ...\n>\n>     $ rungit maint status -suall\n>     ?? baz/quux/corge/wibble.txt\n>     ?? baz/quux/grault.txt\n>     ?? foo/bar.txt\n>     $ rungit master status -suall\n>     ?? baz/quux/corge/wibble.txt\n>     ?? baz/quux/grault.txt\n>     ?? baz/waldo.txt\n>     ?? foo/bar.txt\n>     ?? foo/garply.txt\n\nIf you swap a60ea8f and bac65a2 so that we can have tracing even\nwithout the problematic commit a60ea8f (dir.c: fix match_pathname() -\n2016-02-15). Without a60ea8f I got\n\nGIT_TRACE_EXCLUDE=1 ~/w/git/temp/git status -suall 2>&1 >/dev/null\n|grep waldo\n07:25:05.639445 dir.c:952               exclude: baz/waldo.txt vs * at\nline 1 => yes\n\n(meaning, baz/waldo.txt matches \"*\" rule and is decided to be excluded)\n\nwith a60ea8f\n\n> /tmp/abc $ GIT_TRACE_EXCLUDE=1 ~/w/git/temp/git status -suall 2>&1 >/dev/null |grep waldo\n07:25:24.425125 dir.c:952               exclude: baz/waldo.txt vs /baz\nat line 4 => no\n\nthe decision is not taken earlier from line \"!/baz\" and it's decided\nto be re-included. Which I would argue is the correct thing because\nyou ask to re-include the whole directory \"baz\". It should behave this\nway because exclude rules without '!' behave this way.\n\nBecause positive any negative rules can be nested, by adding a rule to\nreinclude what's inside baz..\n\n    *\n    !/foo\n    !/foo/bar.txt\n    !/baz\n    /baz/*\n    !/baz/quux\n    !/baz/quux/**/*\n\nyou'll get baz/waldo.txt excluded.\n\nYes it's a behavior change. I think the old behavior is unintended.\nBut it's probably out there long enough that many .gitignore files may\nrely on it and by making it right, I break them. Whether to revert the\nseries is up to you. Let me know if I should send the revert patch.\n-- \nDuy\n"},{"id":"280222","messageId":"CACsJy8CcwaZ-zLX3iBKPDNkpMv5vRU=hHYFeBK7o0tnOq6uDJA@mail.gmail.com","threadId":"41605","inReplyTo":"CACsJy8BZm9pFdR+Njst7qZ1UnHUL9XpigM5pW+CLEicOc7ra8g@mail.gmail.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-03-05T00:50:15Z","receivedAt":"2016-03-05T00:50:15Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"typo fixes\n\nOn Sat, Mar 5, 2016 at 7:43 AM, Duy Nguyen <pclouds@gmail.com> wrote:\n> On Sat, Mar 5, 2016 at 12:28 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Duy Nguyen <pclouds@gmail.com> writes:\n>>\n>>> On Fri, Mar 4, 2016 at 6:56 PM, Kevin Daudt <me@ikke.info> wrote:\n>>>> Verified that it's different in 2.7.0, but 2.7.2 gives expected output.\n>>>\n>>> Thanks. 2.7.1 reverts the faulty commit from 2.7.0 that generated two\n>>> other regression reports before this one. I guess it's all good then\n>>> (except for the people still on 2.7.0)\n>>\n>> Are we good at 2.8.0-rc0, too?  Somehow I had an impression that we\n>> queued \"another attempt to do it differently\" or something.\n>>\n>>  ... goes and looks ...\n>>\n>>     $ rungit maint status -suall\n>>     ?? baz/quux/corge/wibble.txt\n>>     ?? baz/quux/grault.txt\n>>     ?? foo/bar.txt\n>>     $ rungit master status -suall\n>>     ?? baz/quux/corge/wibble.txt\n>>     ?? baz/quux/grault.txt\n>>     ?? baz/waldo.txt\n>>     ?? foo/bar.txt\n>>     ?? foo/garply.txt\n>\n> If you swap a60ea8f and bac65a2 so that we can have tracing even\n> without the problematic commit a60ea8f (dir.c: fix match_pathname() -\n> 2016-02-15). Without a60ea8f I got\n>\n> GIT_TRACE_EXCLUDE=1 ~/w/git/temp/git status -suall 2>&1 >/dev/null\n> |grep waldo\n> 07:25:05.639445 dir.c:952               exclude: baz/waldo.txt vs * at\n> line 1 => yes\n>\n> (meaning, baz/waldo.txt matches \"*\" rule and is decided to be excluded)\n>\n> with a60ea8f\n>\n>> /tmp/abc $ GIT_TRACE_EXCLUDE=1 ~/w/git/temp/git status -suall 2>&1 >/dev/null |grep waldo\n> 07:25:24.425125 dir.c:952               exclude: baz/waldo.txt vs /baz\n> at line 4 => no\n>\n> the decision is not taken earlier from line \"!/baz\" and it's decided\n\ns/not taken/taken/\n\n> to be re-included. Which I would argue is the correct thing because\n> you ask to re-include the whole directory \"baz\". It should behave this\n> way because exclude rules without '!' behave this way.\n>\n> Because positive any negative rules can be nested, by adding a rule to\n\ns/any/and/\n\n> reinclude what's inside baz..\n>\n>     *\n>     !/foo\n>     !/foo/bar.txt\n>     !/baz\n>     /baz/*\n>     !/baz/quux\n>     !/baz/quux/**/*\n>\n> you'll get baz/waldo.txt excluded.\n>\n> Yes it's a behavior change. I think the old behavior is unintended.\n> But it's probably out there long enough that many .gitignore files may\n> rely on it and by making it right, I break them. Whether to revert the\n> series is up to you. Let me know if I should send the revert patch.\n> --\n> Duy\n\n\n\n-- \nDuy\n"},{"id":"280223","messageId":"1457139624.4135861.540124922.0A8B3F69@webmail.messagingengine.com","threadId":"41605","inReplyTo":"CACsJy8CcwaZ-zLX3iBKPDNkpMv5vRU=hHYFeBK7o0tnOq6uDJA@mail.gmail.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Charles Strahan","fromEmail":"charles@cstrahan.com","sentAt":"2016-03-05T01:00:24Z","receivedAt":"2016-03-05T01:00:24Z","isPatch":false,"sender":{"key":"charles@cstrahan.com","avatar":"https://gravatar.com/avatar/bc62fe057ea576649ad0a85405c7d3c32c6a28ee55d1d5d1b9cf62efc6080f4b?d=mp&s=160"},"body":"The fix on my side was quite easy (and my .gitignore is probably a _lot_\nhairier\nthan most), and as Duy suggests, I think the new behavior makes a bit\nmore\nsense. Personally, I would be pleased with keeping the new behavior, and\nchalking it up to an unintentional bug fix (the best kind).\n\nEither way, of course, I'd like for it to not change back and forth\nbetween\nreleases :).\n\nPerhaps just an announcement of the new behavior would suffice - 2.7.0\nhas been\nout for a while anyway. If people were going to complain, I figure they\nwould\nhave done so by now.\n\n-Charles\n\n\nOn Fri, Mar 4, 2016, at 07:50 PM, Duy Nguyen wrote:\n> typo fixes\n> \n> On Sat, Mar 5, 2016 at 7:43 AM, Duy Nguyen <pclouds@gmail.com> wrote:\n> > On Sat, Mar 5, 2016 at 12:28 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> >> Duy Nguyen <pclouds@gmail.com> writes:\n> >>\n> >>> On Fri, Mar 4, 2016 at 6:56 PM, Kevin Daudt <me@ikke.info> wrote:\n> >>>> Verified that it's different in 2.7.0, but 2.7.2 gives expected output.\n> >>>\n> >>> Thanks. 2.7.1 reverts the faulty commit from 2.7.0 that generated two\n> >>> other regression reports before this one. I guess it's all good then\n> >>> (except for the people still on 2.7.0)\n> >>\n> >> Are we good at 2.8.0-rc0, too?  Somehow I had an impression that we\n> >> queued \"another attempt to do it differently\" or something.\n> >>\n> >>  ... goes and looks ...\n> >>\n> >>     $ rungit maint status -suall\n> >>     ?? baz/quux/corge/wibble.txt\n> >>     ?? baz/quux/grault.txt\n> >>     ?? foo/bar.txt\n> >>     $ rungit master status -suall\n> >>     ?? baz/quux/corge/wibble.txt\n> >>     ?? baz/quux/grault.txt\n> >>     ?? baz/waldo.txt\n> >>     ?? foo/bar.txt\n> >>     ?? foo/garply.txt\n> >\n> > If you swap a60ea8f and bac65a2 so that we can have tracing even\n> > without the problematic commit a60ea8f (dir.c: fix match_pathname() -\n> > 2016-02-15). Without a60ea8f I got\n> >\n> > GIT_TRACE_EXCLUDE=1 ~/w/git/temp/git status -suall 2>&1 >/dev/null\n> > |grep waldo\n> > 07:25:05.639445 dir.c:952               exclude: baz/waldo.txt vs * at\n> > line 1 => yes\n> >\n> > (meaning, baz/waldo.txt matches \"*\" rule and is decided to be excluded)\n> >\n> > with a60ea8f\n> >\n> >> /tmp/abc $ GIT_TRACE_EXCLUDE=1 ~/w/git/temp/git status -suall 2>&1 >/dev/null |grep waldo\n> > 07:25:24.425125 dir.c:952               exclude: baz/waldo.txt vs /baz\n> > at line 4 => no\n> >\n> > the decision is not taken earlier from line \"!/baz\" and it's decided\n> \n> s/not taken/taken/\n> \n> > to be re-included. Which I would argue is the correct thing because\n> > you ask to re-include the whole directory \"baz\". It should behave this\n> > way because exclude rules without '!' behave this way.\n> >\n> > Because positive any negative rules can be nested, by adding a rule to\n> \n> s/any/and/\n> \n> > reinclude what's inside baz..\n> >\n> >     *\n> >     !/foo\n> >     !/foo/bar.txt\n> >     !/baz\n> >     /baz/*\n> >     !/baz/quux\n> >     !/baz/quux/**/*\n> >\n> > you'll get baz/waldo.txt excluded.\n> >\n> > Yes it's a behavior change. I think the old behavior is unintended.\n> > But it's probably out there long enough that many .gitignore files may\n> > rely on it and by making it right, I break them. Whether to revert the\n> > series is up to you. Let me know if I should send the revert patch.\n> > --\n> > Duy\n> \n> \n> \n> -- \n> Duy\n"},{"id":"280226","messageId":"xmqq60x1yae5.fsf@gitster.mtv.corp.google.com","threadId":"41605","inReplyTo":"1457139624.4135861.540124922.0A8B3F69@webmail.messagingengine.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-05T01:35:30Z","receivedAt":"2016-03-05T01:35:30Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Charles Strahan <charles@cstrahan.com> writes:\n\n> ...as Duy suggests, I think the new behavior makes a bit\n> more sense.\n\nAfter re-reading your original example, I am inclined to agree with\nthis.\n\n> Either way, of course, I'd like for it to not change back and\n> forth between releases :).\n>\n> Perhaps just an announcement of the new behavior would suffice -\n> 2.7.0 has been out for a while anyway. If people were going to\n> complain, I figure they would have done so by now.\n\nYup, I think a documentation update to clarify how positive and\nnegative ignore patterns interact with each other may be necessary,\nwith some examples.\n\nCare to work on a patch?\n\nThanks.\n"},{"id":"280335","messageId":"xmqqlh5ungct.fsf@gitster.mtv.corp.google.com","threadId":"41605","inReplyTo":"CACsJy8BZm9pFdR+Njst7qZ1UnHUL9XpigM5pW+CLEicOc7ra8g@mail.gmail.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-07T21:11:14Z","receivedAt":"2016-03-07T21:11:14Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> On Sat, Mar 5, 2016 at 12:28 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>\n>> Are we good at 2.8.0-rc0, too?  Somehow I had an impression that we\n>> queued \"another attempt to do it differently\" or something.\n>>\n>>  ... goes and looks ...\n>>\n>>     $ rungit maint status -suall\n>>     ?? baz/quux/corge/wibble.txt\n>>     ?? baz/quux/grault.txt\n>>     ?? foo/bar.txt\n>>     $ rungit master status -suall\n>>     ?? baz/quux/corge/wibble.txt\n>>     ?? baz/quux/grault.txt\n>>     ?? baz/waldo.txt\n>>     ?? foo/bar.txt\n>>     ?? foo/garply.txt\n> ...\n> the decision is not taken earlier from line \"!/baz\" and it's decided\n> to be re-included. Which I would argue is the correct thing because\n> you ask to re-include the whole directory \"baz\". It should behave this\n> way because exclude rules without '!' behave this way.\n\nWe need documentation update to settle this one before 2.8 final\nships, as we seem to be seeing more and more end-user confusion on\nthe list.  I tried to come up with a trimmed-down example, which is\nshown below, but I suspect that the code is not exactly working the\nway it is described in that (1) dir/file1 is ignored and (3)\n!dir/file3 entry makes difference.\n\nWhere did my example go wrong?\n\nFYI, if I prefix '/' to all the .gitignore entries in the example, i.e.\nmaking it\n\n    *\n    !/dir\n    /dir/file2\n    !/dir/file3\n\ninstead, then dir/file1 and dir/file3 do get shown as unignored.\n\nIf it is documented somewhere, then I can update the example and\ndeclare victory (but then the text that accompanies the example\nstill needs to remind the readers why the leading '/' matters.\n\nThanks.\n\n\n\n Documentation/gitignore.txt | 34 ++++++++++++++++++++++++++++++++++\n 1 file changed, 34 insertions(+)\n\ndiff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt\nindex 3ded6fd..b841233 100644\n--- a/Documentation/gitignore.txt\n+++ b/Documentation/gitignore.txt\n@@ -150,6 +150,40 @@ excluded, the following conditions must be met:\n  - The directory part in the re-include rules must be literal (i.e. no\n    wildcards)\n \n+A re-inclusion of a directory makes all files in the directory\n+unignored.  For example, suppose you have files `.gitignore`,\n+`dir/file1`, `dir/file2`, and `dir/file3`, and have the following in\n+your `.gitignore`:\n+\n+----------------\n+*\n+!dir\n+# dir/file1 is not mentioned in .gitignore\n+dir/file2\n+!dir/file3\n+----------------\n+\n+Then:\n+\n+ - `.gitignore` gets ignored, because it matches the `*` at the top\n+   level;\n+\n+ - `dir/file1` gets unignored, because `dir` marks everything\n+   underneath `dir/` to be unignored unless otherwise specified;\n+\n+ - `dir/file2` gets ignored, because `dir/file2` is listed to be\n+   ignored;\n+\n+ - `dir/file3` gets unignored, because `dir/file3` is listed to be\n+   ignored.  Note that the entry `!dir/file3` is redundant because\n+   everything underneath `dir/` is marked to be unignored already.\n+\n+Some earlier versions of Git treated `!dir` differently in that it\n+did not cause the paths under it unignored, but this has been\n+corrected to be consistent with `dir` that says \"`dir` and everything\n+below are ignored.\"\n+\n+\n EXAMPLES\n --------\n \n"},{"id":"280354","messageId":"xmqq8u1tmr6l.fsf@gitster.mtv.corp.google.com","threadId":"41605","inReplyTo":"xmqqlh5ungct.fsf@gitster.mtv.corp.google.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-08T06:14:58Z","receivedAt":"2016-03-08T06:14:58Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> We need documentation update to settle this one before 2.8 final\n> ships, as we seem to be seeing more and more end-user confusion on\n> the list.  I tried to come up with a trimmed-down example, which is\n> shown below, but I suspect that the code is not exactly working the\n> way it is described in that (1) dir/file1 is ignored and (3)\n> !dir/file3 entry makes difference.\n>\n> Where did my example go wrong?\n>\n> FYI, if I prefix '/' to all the .gitignore entries in the example, i.e.\n> making it\n>\n>     *\n>     !/dir\n>     /dir/file2\n>     !/dir/file3\n>\n> instead, then dir/file1 and dir/file3 do get shown as unignored.\n>\n> If it is documented somewhere, then I can update the example and\n> declare victory (but then the text that accompanies the example\n> still needs to remind the readers why the leading '/' matters.\n\nI also found that having an extra slash at the end of the\n\"everything underneath 'dir' directory is included\", i.e.\n\n     *\n     !/dir/\n     /dir/file2\n     !/dir/file3\n\nbreaks it.  dir/file1 is ignored, dir/file3 isn't but the latter is\nonly because there is an explicit !/dir/file3.  This is contrary to\nthis rule in the documentation:\n\n - If the pattern ends with a slash, it is removed for the\n   purpose of the following description, but it would only find\n   a match with a directory.  In other words, `foo/` will match a\n   directory `foo` and paths underneath it, but will not match a\n   regular file or a symbolic link `foo` (this is consistent\n   with the way how pathspec works in general in Git).\n\nIn other words, '!/dir/' does not seem to match the directory dir\nand paths underneath it.\n\nThanks.\n\n>  Documentation/gitignore.txt | 34 ++++++++++++++++++++++++++++++++++\n>  1 file changed, 34 insertions(+)\n>\n> diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt\n> index 3ded6fd..b841233 100644\n> --- a/Documentation/gitignore.txt\n> +++ b/Documentation/gitignore.txt\n> @@ -150,6 +150,40 @@ excluded, the following conditions must be met:\n>   - The directory part in the re-include rules must be literal (i.e. no\n>     wildcards)\n>  \n> +A re-inclusion of a directory makes all files in the directory\n> +unignored.  For example, suppose you have files `.gitignore`,\n> +`dir/file1`, `dir/file2`, and `dir/file3`, and have the following in\n> +your `.gitignore`:\n> +\n> +----------------\n> +*\n> +!dir\n> +# dir/file1 is not mentioned in .gitignore\n> +dir/file2\n> +!dir/file3\n> +----------------\n> +\n> +Then:\n> +\n> + - `.gitignore` gets ignored, because it matches the `*` at the top\n> +   level;\n> +\n> + - `dir/file1` gets unignored, because `dir` marks everything\n> +   underneath `dir/` to be unignored unless otherwise specified;\n> +\n> + - `dir/file2` gets ignored, because `dir/file2` is listed to be\n> +   ignored;\n> +\n> + - `dir/file3` gets unignored, because `dir/file3` is listed to be\n> +   ignored.  Note that the entry `!dir/file3` is redundant because\n> +   everything underneath `dir/` is marked to be unignored already.\n> +\n> +Some earlier versions of Git treated `!dir` differently in that it\n> +did not cause the paths under it unignored, but this has been\n> +corrected to be consistent with `dir` that says \"`dir` and everything\n> +below are ignored.\"\n> +\n> +\n>  EXAMPLES\n>  --------\n>  \n"},{"id":"280358","messageId":"CACsJy8C5r2f76p3oq5oX_1P5Vqt9qd7TAafuKxJ=Y8baELbJog@mail.gmail.com","threadId":"41605","inReplyTo":"xmqq8u1tmr6l.fsf@gitster.mtv.corp.google.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-03-08T10:19:23Z","receivedAt":"2016-03-08T10:19:23Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Mar 8, 2016 at 1:14 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Junio C Hamano <gitster@pobox.com> writes:\n>\n>> We need documentation update to settle this one before 2.8 final\n>> ships, as we seem to be seeing more and more end-user confusion on\n>> the list.  I tried to come up with a trimmed-down example, which is\n>> shown below, but I suspect that the code is not exactly working the\n>> way it is described in that (1) dir/file1 is ignored and (3)\n>> !dir/file3 entry makes difference.\n>>\n>> Where did my example go wrong?\n>>\n>> FYI, if I prefix '/' to all the .gitignore entries in the example, i.e.\n>> making it\n>>\n>>     *\n>>     !/dir\n>>     /dir/file2\n>>     !/dir/file3\n>>\n>> instead, then dir/file1 and dir/file3 do get shown as unignored.\n\nArghhh.. bug!!!\n\nThe difference between \"dir\" and \"/dir\" is, the former is basename\nmatching while the latter is pathname matching. When we check\ndir/file1 after we enter \"dir\", we do try to check rule \"!/dir\" (or\n\"!dir\") before rule \"*\". In the pathname matching case, it works\nthanks to a60ea8f.\n\nIn the basename matching case (i.e. rule \"!dir\"), the code does not do\nthe right thing. It blindly checks the base name of dir/file1, which\nis \"file1\", against the pattern \"dir\". The right thing to do is check\nthe \"dir\" in \"dir/file1\" part against pattern \"dir\". Failing that, we\nfall back to pattern \"*\" and excludes dir/file1 as well.\n\n>> If it is documented somewhere, then I can update the example and\n>> declare victory (but then the text that accompanies the example\n>> still needs to remind the readers why the leading '/' matters.\n>\n> I also found that having an extra slash at the end of the\n> \"everything underneath 'dir' directory is included\", i.e.\n>\n>      *\n>      !/dir/\n>      /dir/file2\n>      !/dir/file3\n>\n> breaks it.  dir/file1 is ignored, dir/file3 isn't but the latter is\n> only because there is an explicit !/dir/file3.  This is contrary to\n> this rule in the documentation:\n\nThis is pretty much the same. But instead basename matching unable to\ndeal with nested rules, the trailing slash means \"check if it is a\ndirectory\". Again, the code tries to check if \"dir/file1\" is a\ndirectory instead of \"dir\".\n\nI haven't dug back in history, but my impression is it has been so\nprobably from the beginning of \"!\" introduction. This has nothing to\ndo with nd/exclusion-regression-fix, which is more about\n\n    dir\n    !dir/file\n\nthan\n\n    !dir\n    dir/file\n\nAlthough the first patch in that series happens to fix the pathname\nmatching case in this example.\n\nI don't know. It seems to me I should fix this anyway, by making both\n\"NODIR\" and \"MUSTBEDIR\" code work well inside a directory. That should\nfix it. I hope I don't have to turn dir.c up side down for that. Last\ntime I looked, it wasn't easy, which led to hack/avoid it with 57534ee\nand that was eventually reverted.\n-- \nDuy\n"},{"id":"280378","messageId":"xmqqbn6olu1w.fsf@gitster.mtv.corp.google.com","threadId":"41605","inReplyTo":"CACsJy8C5r2f76p3oq5oX_1P5Vqt9qd7TAafuKxJ=Y8baELbJog@mail.gmail.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-08T18:10:35Z","receivedAt":"2016-03-08T18:10:35Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> On Tue, Mar 8, 2016 at 1:14 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Junio C Hamano <gitster@pobox.com> writes:\n>>\n>>> We need documentation update to settle this one before 2.8 final\n>>> ships, as we seem to be seeing more and more end-user confusion on\n>>> the list.  I tried to come up with a trimmed-down example, which is\n>>> shown below, but I suspect that the code is not exactly working the\n>>> way it is described in that (1) dir/file1 is ignored and (3)\n>>> !dir/file3 entry makes difference.\n>>>\n>>> Where did my example go wrong?\n>>>\n>>> FYI, if I prefix '/' to all the .gitignore entries in the example, i.e.\n>>> making it\n>>>\n>>>     *\n>>>     !/dir\n>>>     /dir/file2\n>>>     !/dir/file3\n>>>\n>>> instead, then dir/file1 and dir/file3 do get shown as unignored.\n>\n> Arghhh.. bug!!!\n>\n> The difference between \"dir\" and \"/dir\" is, the former is basename\n> matching while the latter is pathname matching. When we check\n> dir/file1 after we enter \"dir\", we do try to check rule \"!/dir\" (or\n> \"!dir\") before rule \"*\". In the pathname matching case, it works\n> thanks to a60ea8f.\n\nSo what do we want to do for the upcoming release?  I am OK to leave\nthe code as-is for now and describe it as a known bug that is still\nbeing worked on (as long as it indeed is being worked on, that is),\nas the desired endgame of making \"!dir\" act in a way more similar to\nhow \"dir\" acts does sound sensible.\n\nIf we are going that route, perhaps something like this is the\nminimum we would need before 2.8 final.\n\nThoughts?\n\n\n Documentation/gitignore.txt | 38 +++++++++++++++++++++++++++++++++++++-\n 1 file changed, 37 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt\nindex 3ded6fd..91d1ce2 100644\n--- a/Documentation/gitignore.txt\n+++ b/Documentation/gitignore.txt\n@@ -148,7 +148,43 @@ excluded, the following conditions must be met:\n    be in the same .gitignore file.\n \n  - The directory part in the re-include rules must be literal (i.e. no\n-   wildcards)\n+   wildcards and has to start with a `/`).\n+\n+A re-inclusion of a directory makes all files in the directory\n+unignored.  For example, suppose you have files `.gitignore`,\n+`dir/file1`, `dir/file2`, and `dir/file3`, and have the following in\n+your `.gitignore`:\n+\n+----------------\n+# .gitignore is not mentioned in .gitignore\n+*\n+!/dir\n+# dir/file1 is not mentioned in .gitignore\n+dir/file2\n+!dir/file3\n+----------------\n+\n+Then:\n+\n+ - `.gitignore` gets ignored, because it matches the `*` at the top\n+   level;\n+\n+ - `dir/file1` does not get ignored, because `/dir` marks everything\n+   underneath `dir/` directory to be 're-included' unless otherwise\n+   specified;\n+\n+ - `dir/file2` gets ignored, because `dir/file2` matches it.\n+\n+ - `dir/file3` does not get ignored, because `!dir/file3` matches it.\n+   Note that the entry `!dir/file3` is redundant because everything\n+   underneath `dir/` is marked to be 're-included' already.\n+\n+Some earlier versions of Git treated `!/dir` above differently in\n+that it did not cause the paths under it unignored (but merely told\n+Git that patterns that begin with dir/ should not be ignored), but\n+this has been corrected to be consistent with `/dir` that says \"the\n+directory `dir/` and everything below are ignored.\"\n+\n \n EXAMPLES\n --------\n"},{"id":"280397","messageId":"CACsJy8AgPQ__aVgoJc860yapWs_rTbXfBuGSBNRG-FT+v+rK1w@mail.gmail.com","threadId":"41605","inReplyTo":"xmqqbn6olu1w.fsf@gitster.mtv.corp.google.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-03-09T00:18:31Z","receivedAt":"2016-03-09T00:18:31Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Mar 9, 2016 at 1:10 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> So what do we want to do for the upcoming release?\n\nI don't know. Befoire 2.8.0, all three matching cases are broken. With\nthe current changes on 2.8.0, one case is fixed with the other cases\nbroken. I guess it can create even more confusion. Yeah documentation\nhelps a bit.\n\n> I am OK to leave\n> the code as-is for now and describe it as a known bug that is still\n> being worked on (as long as it indeed is being worked on, that is),\n\nI do want to fix it. I don't know how much code is impacted yet (and\nhow many more bugs I'll be introducing while attempting to fix it). It\nmay take a few cycles before the fix can be released.\n-- \nDuy\n"},{"id":"280403","messageId":"xmqq7fhcjxt8.fsf@gitster.mtv.corp.google.com","threadId":"41605","inReplyTo":"CACsJy8AgPQ__aVgoJc860yapWs_rTbXfBuGSBNRG-FT+v+rK1w@mail.gmail.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-09T00:32:19Z","receivedAt":"2016-03-09T00:32:19Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> On Wed, Mar 9, 2016 at 1:10 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> So what do we want to do for the upcoming release?\n>\n> I don't know. Befoire 2.8.0, all three matching cases are broken. With\n> the current changes on 2.8.0, one case is fixed with the other cases\n> broken. I guess it can create even more confusion. Yeah documentation\n> helps a bit.\n>\n>> I am OK to leave\n>> the code as-is for now and describe it as a known bug that is still\n>> being worked on (as long as it indeed is being worked on, that is),\n>\n> I do want to fix it. I don't know how much code is impacted yet (and\n> how many more bugs I'll be introducing while attempting to fix it). It\n> may take a few cycles before the fix can be released.\n\nSorry, but I should have been more clear.  At this point in the\nrelease cycle, I do not think it is an option to pile on more\n\"fixes\" to risk destabilizing the end-user experience even more\nbefore 2.8.0 final happens.\n\nIt is between (1) the current code is good enough that with a\n(temporary) limitation clearly described in the documentation users\ncan work around the implementation deficiency and get a benaviour\nthat is closer than 2.7.2, or (2) the half-way implementation we\nhave does not give enough advancement toward the final goal\n(i.e. the !dir re-inclusion behaves consistently with the dir\nthat ignores the whole thing underneath, while allowing subpaths\nignored with follow-on entries in the same .gitignore file), and we\nare better off reverting the whole thing to go back to 2.7.2\nbehaviour, planning to do a better job in the next cycle.\n\nI was hoping that (1) would be the case.\n"},{"id":"280400","messageId":"xmqqy49siin2.fsf@gitster.mtv.corp.google.com","threadId":"41605","inReplyTo":"xmqq7fhcjxt8.fsf@gitster.mtv.corp.google.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-09T00:45:21Z","receivedAt":"2016-03-09T00:45:21Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> It is between (1) the current code is good enough ...\n> or (2) the half-way implementation we\n> have does not give enough advancement ... and we\n> are better off reverting the whole thing to go back to 2.7.2\n> behaviour, planning to do a better job in the next cycle.\n>\n> I was hoping that (1) would be the case.\n\nOh and of course I still am--otherwise I wouldn't have been\nattempting these documentation updates.  I just wanted to make sure\nthat I covered most (if not all) of the corner cases that we know\nthe current code does not work by documenting workarounds.\n"},{"id":"280411","messageId":"CACsJy8AUs-DAo-GceO9ND9RPVeDOfm_UM4ZuaeNWDwBVMu+dnQ@mail.gmail.com","threadId":"41605","inReplyTo":"xmqqbn6olu1w.fsf@gitster.mtv.corp.google.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-03-09T09:48:34Z","receivedAt":"2016-03-09T09:48:34Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Wed, Mar 9, 2016 at 1:10 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt\n> index 3ded6fd..91d1ce2 100644\n> --- a/Documentation/gitignore.txt\n> +++ b/Documentation/gitignore.txt\n> @@ -148,7 +148,43 @@ excluded, the following conditions must be met:\n>     be in the same .gitignore file.\n>\n>   - The directory part in the re-include rules must be literal (i.e. no\n> -   wildcards)\n> +   wildcards and has to start with a `/`).\n\nTechnically '/' can just appear anywhere in the pattern, except at the\nend. But because the patterns in question must look like this\n\n    dir # or any pattern, even \"*\"\n    !dir/someth*ng\n\neven if there is a slash at the end (and is ignored), we are still\ngood. Not sure how to phrase that though.\n\n> +\n> +A re-inclusion of a directory makes all files in the directory\n> +unignored.  For example, suppose you have files `.gitignore`,\n> +`dir/file1`, `dir/file2`, and `dir/file3`, and have the following in\n> +your `.gitignore`:\n> +\n> +----------------\n> +# .gitignore is not mentioned in .gitignore\n> +*\n> +!/dir\n> +# dir/file1 is not mentioned in .gitignore\n> +dir/file2\n> +!dir/file3\n> +----------------\n> +\n> +Then:\n> +\n> + - `.gitignore` gets ignored, because it matches the `*` at the top\n> +   level;\n> +\n> + - `dir/file1` does not get ignored, because `/dir` marks everything\n> +   underneath `dir/` directory to be 're-included' unless otherwise\n> +   specified;\n> +\n> + - `dir/file2` gets ignored, because `dir/file2` matches it.\n> +\n> + - `dir/file3` does not get ignored, because `!dir/file3` matches it.\n> +   Note that the entry `!dir/file3` is redundant because everything\n> +   underneath `dir/` is marked to be 're-included' already.\n> +\n> +Some earlier versions of Git treated `!/dir` above differently in\n> +that it did not cause the paths under it unignored (but merely told\n> +Git that patterns that begin with dir/ should not be ignored), but\n> +this has been corrected to be consistent with `/dir` that says \"the\n> +directory `dir/` and everything below are ignored.\"\n> +\n\nLooks good.\n-- \nDuy\n"},{"id":"280413","messageId":"1457521693-26141-1-git-send-email-pclouds@gmail.com","threadId":"41605","inReplyTo":"xmqqy49siin2.fsf@gitster.mtv.corp.google.com","subject":"[PATCH] dir.c: fix dir re-inclusion rules with \"NODIR\" and \"MUSTBEDIR\"","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2016-03-09T11:08:13Z","receivedAt":"2016-03-09T11:08:13Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"For NODIR case, the patterns look like this\n\n    *          # exclude dir, dir/file1 and dir/file2..\n    !dir       # ..except that dir and everything inside is re-included..\n    dir/file2  # ..except (again!) that dir/file2 is excluded\n               # ..which means dir/file1 stays included\n\nWhen we stay at topdir and test \"dir\", everything is hunky dory, current\ncode returns \"re-include dir\" as expected. When we stay in \"dir\" and\nexamine \"dir/file1\", however, match_basename() checks if the base name\ncomponent, which is \"file1\", matches \"dir\" from the second rule.\n\nThis is wrong. We contradict ourselves because earlier we decided to\nre-include dir/file1 (from the second rule) when we were at toplevel.\nBecause the second rule is ignored, we hit the first one and return\n\"excluded\" even though \"dir/file1\" should be re-included.\n\nSide note, it's probably a bad idea to use basename matching on a\nnegative rule (ie. no slashes in the pattern) because what the pattern\nsays is \"re-include _any_ directory named 'dir'\", not just the directory\n\"dir\" at right below this directory.\n\nIn the MUSTBEDIR case, the patterns look like this\n\n    *          # exclude dir, dir/file1 and dir/file2..\n    !dir/      #  ..except that dir and everything inside is re-included..\n    dir/file2  # ..except (again!) that dir/file2 is excluded\n               # ..which means dir/file1 stays included\n\nAgain, we're ok at the toplevel, then we enter \"dir\" and test\n\"dir/file1\". The MUSTBEDIR code tests if the _full_ path (ie. \"dir/file1\")\nis a directory. We want it to test the \"dir\" part from \"dir/file1\"\ninstead.\n\nIn both cases, we want to test if the pattern matches a parent\ndirectory. match_dir_component() is for this purpose.\n\nWe do want to be careful not to get back too far. Given the file\nfoo/bar/.gitignore, we should only check as far back as foo/bar because\nthis .gitignore file can never match outside that directory, which is\n\"toplevel\" in the above paragraphs, to begin with.\n\nThe remaining matching case (neither NODIR nor MUSTBEDIR is set) is\nalready fixed in a60ea8f (dir.c: fix match_pathname() - 2016-02-15)\n\nReported-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n The fix may look like this (I didn't think about the \"**\" trick in\n wildmatch, which makes things simpler).\n\n No it's not meant for 2.8.0. I didn't even optimize for the\n no-wildcard case, or add tests. But we can still stare at it in the\n meantime to see if I analyzed anything wrong. I almost thought I was\n wrong to the declare the bug while I was on my ride back home..\n\n dir.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++--\n 1 file changed, 49 insertions(+), 2 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 69e0be6..5123483 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -992,6 +992,51 @@ static struct exclude *should_descend(const char *pathname, int pathlen,\n }\n \n /*\n+ * Given a \"NODIR\" pattern, check if it matches any directory\n+ * component after the x->base part.\n+ *\n+ * If the pattern is not NODIR (ie. pathname matching) _and_ is\n+ * MUSTBE, check if it matches a directory as well.\n+ *\n+ * Note that \"path\" and \"len\" must cover the basename part as well,\n+ * looking from last_exclude_matching_from_list(), not just the dirname.\n+ */\n+static int match_dir_component(const char *path, int len, struct exclude *x)\n+{\n+\tstruct strbuf new_pattern = STRBUF_INIT;\n+\tint ret;\n+\n+\tif (x->flags & EXC_FLAG_NODIR) {\n+\t\tif (!x->baselen) {\n+\t\t\tstrbuf_addf(&new_pattern, \"%s/**\", x->pattern);\n+\t\t\tret = !fnmatch_icase_mem(new_pattern.buf, new_pattern.len,\n+\t\t\t\t\t\t path, strlen(path),\n+\t\t\t\t\t\t WM_PATHNAME);\n+\t\t\tstrbuf_reset(&new_pattern);\n+\t\t\tif (ret)\n+\t\t\t\treturn ret;\n+\t\t}\n+\n+\t\tstrbuf_addf(&new_pattern, \"%.*s**/%s/**\", x->baselen, x->base, x->pattern);\n+\t\tret = !fnmatch_icase_mem(new_pattern.buf, new_pattern.len,\n+\t\t\t\t\t path, strlen(path),\n+\t\t\t\t\t WM_PATHNAME);\n+\t\tstrbuf_reset(&new_pattern);\n+\t\treturn ret;\n+\t}\n+\n+\tassert(x->flags & EXC_FLAG_MUSTBEDIR);\n+\tstrbuf_addf(&new_pattern, \"%.*s%s/**\",\n+\t\t    x->baselen, x->base,\n+\t\t    *x->pattern == '/' ? x->pattern+1 : x->pattern);\n+\tret = !fnmatch_icase_mem(new_pattern.buf, new_pattern.len,\n+\t\t\t\t path, strlen(path),\n+\t\t\t\t WM_PATHNAME);\n+\tstrbuf_release(&new_pattern);\n+\treturn ret;\n+}\n+\n+/*\n  * Scan the given exclude list in reverse to see whether pathname\n  * should be ignored.  The first match (i.e. the last on the list), if\n  * any, determines the fate.  Returns the exclude_list element which\n@@ -1033,7 +1078,8 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,\n \t\tif (x->flags & EXC_FLAG_MUSTBEDIR) {\n \t\t\tif (*dtype == DT_UNKNOWN)\n \t\t\t\t*dtype = get_dtype(NULL, pathname, pathlen);\n-\t\t\tif (*dtype != DT_DIR)\n+\t\t\tif (*dtype != DT_DIR &&\n+\t\t\t    !match_dir_component(pathname, strlen(pathname), x))\n \t\t\t\tcontinue;\n \t\t}\n \n@@ -1041,7 +1087,8 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,\n \t\t\tif (match_basename(basename,\n \t\t\t\t\t   pathlen - (basename - pathname),\n \t\t\t\t\t   exclude, prefix, x->patternlen,\n-\t\t\t\t\t   x->flags)) {\n+\t\t\t\t\t   x->flags) ||\n+\t\t\t    match_dir_component(pathname, strlen(pathname), x)) {\n \t\t\t\texc = x;\n \t\t\t\tbreak;\n \t\t\t}\n-- \n2.8.0.rc0.208.g69d9f93\n"},{"id":"280472","messageId":"xmqqoaanilia.fsf@gitster.mtv.corp.google.com","threadId":"41605","inReplyTo":"1457521693-26141-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH] dir.c: fix dir re-inclusion rules with \"NODIR\" and \"MUSTBEDIR\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-09T17:55:41Z","receivedAt":"2016-03-09T17:55:41Z","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> Side note, it's probably a bad idea to use basename matching on a\n> negative rule (ie. no slashes in the pattern) because what the pattern\n> says is \"re-include _any_ directory named 'dir'\", not just the directory\n> \"dir\" at right below this directory.\n\nI am not sure I agree with this comment.  When we say '.depend/' in\nour .gitignore file, we do want to ignore everything in the\ndirectory with that name anywhere in that tree.  Perhaps '!include/'\nfollowed by '*' may be a good way to pick only the header files that\nare found in any directory with that name anywhere in the tree in a\nsimilar fashion.  It certainly is a disappointing comment if made by\nsomebody who wants to make 'dir' and '!dir' behave in a more similar\nway, I'd have to say.\n\n> In the MUSTBEDIR case, the patterns look like this\n>\n>     *          # exclude dir, dir/file1 and dir/file2..\n>     !dir/      #  ..except that dir and everything inside is re-included..\n>     dir/file2  # ..except (again!) that dir/file2 is excluded\n>                # ..which means dir/file1 stays included\n>\n> Again, we're ok at the toplevel, then we enter \"dir\" and test\n> \"dir/file1\". The MUSTBEDIR code tests if the _full_ path (ie. \"dir/file1\")\n> is a directory. We want it to test the \"dir\" part from \"dir/file1\"\n> instead.\n\nThat certainly sounds like a breakage worth fixing.\n\n> In both cases, we want to test if the pattern matches a parent\n> directory. match_dir_component() is for this purpose.\n\nI do not follow.  I would understand \"In all cases, we want to\nbehave as if we are testing the _full_ path against the pattern\",\nthough.\n\nIOW, \"dir/file1\" matches '*' (because 'file1' and '*' matches),\n'!dir/' (because the pattern is \"everything under dir/ directory),\nand nothing else in the pattern list, and the last match\nwins---which happens to be negative ignore, hence dir/file1 is not\nignored.\n\n> We do want to be careful not to get back too far. Given the file\n> foo/bar/.gitignore, we should only check as far back as foo/bar because\n> this .gitignore file can never match outside that directory, which is\n> \"toplevel\" in the above paragraphs, to begin with.\n\nYes.  But isn't that what exclude_stack mechanism already gives us?\nThat is, when you are not looking at a path inside foo/bar/, entries\nstored in foo/bar/.gitignore will not participate the determination\nof the fate of the path.\n\nI am not sure why you have to say this.  Puzzled...\n"},{"id":"280474","messageId":"xmqqk2lbil7k.fsf@gitster.mtv.corp.google.com","threadId":"41605","inReplyTo":"CACsJy8AUs-DAo-GceO9ND9RPVeDOfm_UM4ZuaeNWDwBVMu+dnQ@mail.gmail.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-09T18:02:07Z","receivedAt":"2016-03-09T18:02:07Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> On Wed, Mar 9, 2016 at 1:10 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>> diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt\n>> index 3ded6fd..91d1ce2 100644\n>> --- a/Documentation/gitignore.txt\n>> +++ b/Documentation/gitignore.txt\n>> @@ -148,7 +148,43 @@ excluded, the following conditions must be met:\n>>     be in the same .gitignore file.\n>>\n>>   - The directory part in the re-include rules must be literal (i.e. no\n>> -   wildcards)\n>> +   wildcards and has to start with a `/`).\n>\n> Technically '/' can just appear anywhere in the pattern, except at the\n> end. But because the patterns in question must look like this\n>\n>     dir # or any pattern, even \"*\"\n>     !dir/someth*ng\n>\n> even if there is a slash at the end (and is ignored), we are still\n> good. Not sure how to phrase that though.\n\nPost 2.8, we'd be correcting this properly anyway, we should aim for\nthe simplest-to-explain way to work around the limitation in the\ncurrent code, that will still work once the bug is fixed.  I am not\nsure if \"Technically it can be other things\" helps, unless it makes\nit a lot easier to use.\n\nWith that in mind, do you think we need to find a better phrase to\nloosen what I wrote that is overly-strict?  That is, is \"must begin\nwith '/' to anchor it to the level .gitignore appears\" too strict to\nmake it too hard to use?\n"},{"id":"280523","messageId":"CACsJy8D=OjLBN-EXyKM4NnGhSGftYX+RAaR9fg8ML3QWAAb+iQ@mail.gmail.com","threadId":"41605","inReplyTo":"xmqqk2lbil7k.fsf@gitster.mtv.corp.google.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-03-10T00:26:00Z","receivedAt":"2016-03-10T00:26:00Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Mar 10, 2016 at 1:02 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Duy Nguyen <pclouds@gmail.com> writes:\n>\n>> On Wed, Mar 9, 2016 at 1:10 AM, Junio C Hamano <gitster@pobox.com> wrote:\n>>> diff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt\n>>> index 3ded6fd..91d1ce2 100644\n>>> --- a/Documentation/gitignore.txt\n>>> +++ b/Documentation/gitignore.txt\n>>> @@ -148,7 +148,43 @@ excluded, the following conditions must be met:\n>>>     be in the same .gitignore file.\n>>>\n>>>   - The directory part in the re-include rules must be literal (i.e. no\n>>> -   wildcards)\n>>> +   wildcards and has to start with a `/`).\n>>\n>> Technically '/' can just appear anywhere in the pattern, except at the\n>> end. But because the patterns in question must look like this\n>>\n>>     dir # or any pattern, even \"*\"\n>>     !dir/someth*ng\n>>\n>> even if there is a slash at the end (and is ignored), we are still\n>> good. Not sure how to phrase that though.\n>\n> Post 2.8, we'd be correcting this properly anyway, we should aim for\n> the simplest-to-explain way to work around the limitation in the\n> current code, that will still work once the bug is fixed.  I am not\n> sure if \"Technically it can be other things\" helps, unless it makes\n> it a lot easier to use.\n>\n> With that in mind, do you think we need to find a better phrase to\n> loosen what I wrote that is overly-strict?  That is, is \"must begin\n> with '/' to anchor it to the level .gitignore appears\" too strict to\n> make it too hard to use?\n>\n\nIf we can name rules from the syntax part, then we can simply say\n\"patterns that meet rules x and y\".\n\nA bit off topic, but these two paragraphs may need rephrasing, I don't\nreally understand what it's trying to say\n\n - If the pattern does not contain a slash '/', Git treats it as\n   a shell glob pattern and checks for a match against the\n   pathname relative to the location of the `.gitignore` file\n   (relative to the toplevel of the work tree if not from a\n   `.gitignore` file).\n\nNot sure why \"relative to the location of .gitignore file\" matters. We\nbasically just take `basename $path` out and try to match it.\n\n - Otherwise, Git treats the pattern as a shell glob suitable\n   for consumption by fnmatch(3) with the FNM_PATHNAME flag:\n   wildcards in the pattern will not match a / in the pathname.\n   For example, \"Documentation/{asterisk}.html\" matches\n   \"Documentation/git.html\" but not \"Documentation/ppc/ppc.html\"\n   or \"tools/perf/Documentation/perf.html\".\n\nPerhaps \"Otherwise\" can be stated explicitly that \"if the pattern does\ncontain any slash, besides the trailing one\". The \"wildcards not\nmatching /\" is also true for the \"pattern does not contain a slash\"\nrule above. We can make it a generic note about wildcards and remove\nthis \"otherwise\" rule, maybe...\n-- \nDuy\n"},{"id":"280524","messageId":"xmqqd1r3f9rc.fsf@gitster.mtv.corp.google.com","threadId":"41605","inReplyTo":"CACsJy8D=OjLBN-EXyKM4NnGhSGftYX+RAaR9fg8ML3QWAAb+iQ@mail.gmail.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-10T00:37:43Z","receivedAt":"2016-03-10T00:37:43Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n> A bit off topic, but these two paragraphs may need rephrasing, I don't\n> really understand what it's trying to say\n>\n>  - If the pattern does not contain a slash '/', Git treats it as\n>    a shell glob pattern and checks for a match against the\n>    pathname relative to the location of the `.gitignore` file\n>    (relative to the toplevel of the work tree if not from a\n>    `.gitignore` file).\n>\n> Not sure why \"relative to the location of .gitignore file\" matters. We\n> basically just take `basename $path` out and try to match it.\n\nThat is because the documentation was written with a single\nconsistent matching mode in mind: you match various patterns against\nthe FULL path in the repository, no matter where you find the path.\nIf you find a pattern \"*.c\" in d/.gitignore file, a path d/hello.c\nmatches, even though '*.c' does not match 'd/hello.c' in the shell\nglob sense, and the rule needs to clarify that the leading directory\npart \"d/\" in the path \"d/hello.c\" does not participate when matching\nit against the pattern \"*.c\" taken from \"d/.gitignore\" file.\n\nIf you start from a mindset to match hello.c part with *.c when you\nfind both in d/ directory, \"relative to the location\" part would\nsound redundant or even confusing.\n\n>  - Otherwise, Git treats the pattern as a shell glob suitable\n>    for consumption by fnmatch(3) with the FNM_PATHNAME flag:\n>    wildcards in the pattern will not match a / in the pathname.\n>    For example, \"Documentation/{asterisk}.html\" matches\n>    \"Documentation/git.html\" but not \"Documentation/ppc/ppc.html\"\n>    or \"tools/perf/Documentation/perf.html\".\n>\n> Perhaps \"Otherwise\" can be stated explicitly that \"if the pattern does\n> contain any slash, besides the trailing one\". \n\nYeah, I think there originally was just two (it has slasn or it\ndoesn't) and \"If ...\" followed by \"Otherwise\" was clear enough, but\nspellin it out would not hurt.\n"},{"id":"280525","messageId":"CACsJy8CbxyJQ7HYy6GaqRhemeSz_upB6jQ7HMX0Vk+tr7bBz3w@mail.gmail.com","threadId":"41605","inReplyTo":"xmqqoaanilia.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH] dir.c: fix dir re-inclusion rules with \"NODIR\" and \"MUSTBEDIR\"","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-03-10T00:39:46Z","receivedAt":"2016-03-10T00:39:46Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Mar 10, 2016 at 12:55 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n>\n>> Side note, it's probably a bad idea to use basename matching on a\n>> negative rule (ie. no slashes in the pattern) because what the pattern\n>> says is \"re-include _any_ directory named 'dir'\", not just the directory\n>> \"dir\" at right below this directory.\n>\n> I am not sure I agree with this comment.  When we say '.depend/' in\n> our .gitignore file, we do want to ignore everything in the\n> directory with that name anywhere in that tree.  Perhaps '!include/'\n> followed by '*' may be a good way to pick only the header files that\n> are found in any directory with that name anywhere in the tree in a\n> similar fashion.  It certainly is a disappointing comment if made by\n> somebody who wants to make 'dir' and '!dir' behave in a more similar\n> way, I'd have to say.\n\nHmm.. yeah personal view. I'll take this out.\n\n>> In both cases, we want to test if the pattern matches a parent\n>> directory. match_dir_component() is for this purpose.\n>\n> I do not follow.  I would understand \"In all cases, we want to\n> behave as if we are testing the _full_ path against the pattern\",\n> though.\n>\n> IOW, \"dir/file1\" matches '*' (because 'file1' and '*' matches),\n> '!dir/' (because the pattern is \"everything under dir/ directory),\n> and nothing else in the pattern list, and the last match\n> wins---which happens to be negative ignore, hence dir/file1 is not\n> ignored.\n\nYep, bad phrasing.\n\n>> We do want to be careful not to get back too far. Given the file\n>> foo/bar/.gitignore, we should only check as far back as foo/bar because\n>> this .gitignore file can never match outside that directory, which is\n>> \"toplevel\" in the above paragraphs, to begin with.\n>\n> Yes.  But isn't that what exclude_stack mechanism already gives us?\n> That is, when you are not looking at a path inside foo/bar/, entries\n> stored in foo/bar/.gitignore will not participate the determination\n> of the fate of the path.\n>\n> I am not sure why you have to say this.  Puzzled...\n\nNaively speaking, in order to fix this without reorganizing a lot of\ncode, when given path 'foo/bar/dir/file1' and the pattern '!dir/', we\nfirst still test if the full path \"foo/bar/dir/file1\" is a directory,\nthen we cut \"file1\" out (pretend that we are in foo/bar instead of in\nfoo/bar/dir) and test again the full path, which is just foo/bar/dir,\nif it's a directory. Repeat again and again. This trick does not go\nthrough the normal prep_exclude(), so patterns are not popping out\nwhen .gitignore should not be used any more.\n\nThe implementation is a bit different. Instead of going up one level,\ntest, and go up again, I construct the new pattern \"foo/bar/**/dir/**\"\nand match it (only once) against the original full path\nfoo/bar/dir/file1. The note was there because I would have just\nconstructed \"**/dir/**\" instead and matched too much.\n-- \nDuy\n"},{"id":"280527","messageId":"xmqq60wvf8qm.fsf@gitster.mtv.corp.google.com","threadId":"41605","inReplyTo":"xmqqd1r3f9rc.fsf@gitster.mtv.corp.google.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-03-10T00:59:45Z","receivedAt":"2016-03-10T00:59:45Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Duy Nguyen <pclouds@gmail.com> writes:\n>\n>> A bit off topic, but these two paragraphs may need rephrasing, I don't\n>> really understand what it's trying to say\n>>\n>>  - If the pattern does not contain a slash '/', Git treats it as\n>>    a shell glob pattern and checks for a match against the\n>>    pathname relative to the location of the `.gitignore` file\n>>    (relative to the toplevel of the work tree if not from a\n>>    `.gitignore` file).\n>>\n>> Not sure why \"relative to the location of .gitignore file\" matters. We\n>> basically just take `basename $path` out and try to match it.\n>\n> That is because the documentation was written with ...\n> matches, even though '*.c' does not match 'd/hello.c' in the shell\n> glob sense,...\n\nSorry, this does not make much sense, as d/e/hello.c would still\nmatch '*.c' in d/.gitignore.  So it is a straight-forward match\nagainst the basename, and there is nothing relative to the location\nof .gitignore.  If anything, relative to where the pattern is found\nshould be relevant to a pattern _with_ slash in it.\n\nI should have been more careful and thought things through, but as\nthis was an \"off topic\" comment, I didn't.  Sorry about that.\n\nIn any case, back to \"on topic\" part again; I couldn't come up with\na better rewrite using named rules (partly because you need to\nclearly define each rule before referring them, and some of the\nrules are temporary workarounds for the 2.8 regression that will\nhopefully disappear in near future).  I think you understand the bug\nand the limitation of the current code a lot better than I do, so if\nyou can please send a final version of the documentation update in\nthe coming 18 hours (I have an option of using what is already\nqueued on 'pu' as a fall-back-good-enough version but I want to keep\nthe last-resort option as that--if I know a potential source of a\nbetter version, I'd choose to ask first ;-).\n\nThanks.\n"},{"id":"280544","messageId":"CACsJy8A8ZUpsc+=65u8Rg7jksCFM1RYh0fvWNS99QTmm01_ktg@mail.gmail.com","threadId":"41605","inReplyTo":"xmqq60wvf8qm.fsf@gitster.mtv.corp.google.com","subject":"Re: Change in .gitignore handling: intended or bug?","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2016-03-10T10:56:12Z","receivedAt":"2016-03-10T10:56:12Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Mar 10, 2016 at 7:59 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> In any case, back to \"on topic\" part again; I couldn't come up with\n> a better rewrite using named rules (partly because you need to\n> clearly define each rule before referring them, and some of the\n> rules are temporary workarounds for the 2.8 regression that will\n> hopefully disappear in near future).  I think you understand the bug\n> and the limitation of the current code a lot better than I do, so if\n> you can please send a final version of the documentation update in\n> the coming 18 hours (I have an option of using what is already\n> queued on 'pu' as a fall-back-good-enough version but I want to keep\n> the last-resort option as that--if I know a potential source of a\n> better version, I'd choose to ask first ;-).\n\nI'm never good with words, especially in a rush. Let's merge yours.\nI'll fix the bug and update gitignore.txt in one go.\n-- \nDuy\n"}]}