{"thread":{"id":"35078","subject":"Feature Request: gitignore recursion","startedAt":"2013-10-06T22:23:09Z","lastAt":"2013-10-10T16:22:44Z","messageCount":7,"participants":["AJ","Duy Nguyen","Jeff King","Karsten Blees"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"228593","messageId":"loom.20131007T000517-673@post.gmane.org","threadId":"35078","inReplyTo":null,"subject":"Feature Request: gitignore recursion","fromName":"AJ","fromEmail":"alljeep@gmail.com","sentAt":"2013-10-06T22:23:09Z","receivedAt":"2013-10-06T22:23:09Z","isPatch":false,"sender":{"key":"alljeep@gmail.com","avatar":null},"body":"I'm hoping to get the following feature implemented into git.\n\nAdd the ability to recursively include using:\n!/my_dir/**/*\n\nCurrently, in order to include a directory with multiple sub-directories\nwithin a excluded directory, you must do the following:\n!/my_dir/\n!/my_dir/*\n!/my_dir/*/*\n!/my_dir/*/*/*\n!/my_dir/*/*/*/*\n!/my_dir/*/*/*/*/*\n\nHere is a use case:\nWhen developing a WordPress site you typically only place the wp-content/themes\ndirectory under version control. Once you start adding custom plugins, README\nfiles, and a task manager like Grunt JS, you then have to starting getting\ncreative with your .gitignore if your .git directory is in the web root\ndirectory.\n\nHere is an example:\nhttps://gist.github.com/AJ-Acevedo/6859779\n\nThanks for taking the time to consider this feature\nAJ\n"},{"id":"228594","messageId":"CACsJy8CHcyDrzieX1Ps3LU2UxCP+QJdv9+5BXZj9Mw2bMs5v3w@mail.gmail.com","threadId":"35078","inReplyTo":"loom.20131007T000517-673@post.gmane.org","subject":"Re: Feature Request: gitignore recursion","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-10-07T10:26:17Z","receivedAt":"2013-10-07T10:26:17Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Oct 7, 2013 at 5:23 AM, AJ <alljeep@gmail.com> wrote:\n> I'm hoping to get the following feature implemented into git.\n>\n> Add the ability to recursively include using:\n> !/my_dir/**/*\n\nYou can do that since v1.8.2. Actually the pattern should be\n\n!/my_dir/**\n\nCheckout gitignore man page for more information.\n\n> Currently, in order to include a directory with multiple sub-directories\n> within a excluded directory, you must do the following:\n> !/my_dir/\n> !/my_dir/*\n> !/my_dir/*/*\n> !/my_dir/*/*/*\n> !/my_dir/*/*/*/*\n> !/my_dir/*/*/*/*/*\n>\n> Here is a use case:\n> When developing a WordPress site you typically only place the wp-content/themes\n> directory under version control. Once you start adding custom plugins, README\n> files, and a task manager like Grunt JS, you then have to starting getting\n> creative with your .gitignore if your .git directory is in the web root\n> directory.\n>\n> Here is an example:\n> https://gist.github.com/AJ-Acevedo/6859779\n>\n> Thanks for taking the time to consider this feature\n> AJ\n>\n> --\n> To unsubscribe from this list: send the line \"unsubscribe git\" in\n> the body of a message to majordomo@vger.kernel.org\n> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n\n\n\n-- \nDuy\n"},{"id":"228596","messageId":"20131007112411.GA5792@sigill.intra.peff.net","threadId":"35078","inReplyTo":"CACsJy8CHcyDrzieX1Ps3LU2UxCP+QJdv9+5BXZj9Mw2bMs5v3w@mail.gmail.com","subject":"Re: Feature Request: gitignore recursion","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2013-10-07T11:24:11Z","receivedAt":"2013-10-07T11:24:11Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Oct 07, 2013 at 05:26:17PM +0700, Nguyen Thai Ngoc Duy wrote:\n\n> On Mon, Oct 7, 2013 at 5:23 AM, AJ <alljeep@gmail.com> wrote:\n> > I'm hoping to get the following feature implemented into git.\n> >\n> > Add the ability to recursively include using:\n> > !/my_dir/**/*\n> \n> You can do that since v1.8.2. Actually the pattern should be\n> \n> !/my_dir/**\n> \n> Checkout gitignore man page for more information.\n\nI think that is a reasonable approach to doing what the OP wants.\n\nHowever, one thing I expected to work but didn't is:\n\n  echo '*' >.gitignore\n  echo '!*' >my_dir/.gitignore\n\nThat _does_ work for attributes, like:\n\n  echo '* foo=one' >.gitattributes\n  echo '* foo=two' >my_dir/.gitattributes\n\nwhere the more-specific file takes precedence. It works because we keep\nan attribute stack, and look from most-specific directory to least.\n\nThe directory traversal code, however, tries to avoid entering\ndirectories that are ignored. So if you have told it to ignore \"my_dir\",\nwe will not even look at \"my_dir/.gitignore\".\n\nThis is arguably a bug, as the documentation says that more specific\npaths should take precedence over toplevel ones. But the optimization of\npruning ignored paths is very important for performance; otherwise, we\nwould end up enumerating entire ignored subdirectories on the off chance\nthat they have a negative .gitignore entry buried deep inside them.\n\nSo I don't think it is worth fixing, but it might be worth mentioning in\nthe documentation. Or is it mentioned somewhere that I missed?\n\n-Peff\n"},{"id":"228599","messageId":"20131007134141.GA23026@lanh","threadId":"35078","inReplyTo":"20131007112411.GA5792@sigill.intra.peff.net","subject":"Re: Feature Request: gitignore recursion","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2013-10-07T13:41:42Z","receivedAt":"2013-10-07T13:41:42Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Oct 07, 2013 at 07:24:11AM -0400, Jeff King wrote:\n> However, one thing I expected to work but didn't is:\n> \n>   echo '*' >.gitignore\n>   echo '!*' >my_dir/.gitignore\n> \n> That _does_ work for attributes, like:\n> \n>   echo '* foo=one' >.gitattributes\n>   echo '* foo=two' >my_dir/.gitattributes\n> \n> where the more-specific file takes precedence. It works because we keep\n> an attribute stack, and look from most-specific directory to least.\n>\n> ...\n\nYeah. I'm still bugged about that because we could at least make your\ncase work (deep/down/.gitignore will never ever, of course) but I\nprobably won't do anything about it for the next few months. So how\nabout this.\n\nThe first use of footnote:[] is already in git-notes.txt. The second\ninstance should not cause any issues with supported asciidoc versions.\n\n-- 8< --\nSubject: [PATCH] gitignore.txt: note about a behavior not so obvious much to users\n\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/gitignore.txt | 5 ++++-\n 1 file changed, 4 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt\nindex 54e334e..cd59f6e 100644\n--- a/Documentation/gitignore.txt\n+++ b/Documentation/gitignore.txt\n@@ -21,7 +21,10 @@ Each line in a `gitignore` file specifies a pattern.\n When deciding whether to ignore a path, Git normally checks\n `gitignore` patterns from multiple sources, with the following\n order of precedence, from highest to lowest (within one level of\n-precedence, the last matching pattern decides the outcome):\n+precedence, the last matching pattern decides the outcome\n+footnote:[Due to optimizations Git will not look further into ignored\n+directories. So if you have a rule to ignore directory `foo`,\n+`.gitignore` in `foo` and its subdirectories are all ignored]):\n \n  * Patterns read from the command line for those commands that support\n    them.\n-- \n1.8.2.83.gc99314b\n-- 8< --\n"},{"id":"228687","messageId":"52565E51.7050401@gmail.com","threadId":"35078","inReplyTo":"CACsJy8CHcyDrzieX1Ps3LU2UxCP+QJdv9+5BXZj9Mw2bMs5v3w@mail.gmail.com","subject":"Re: Feature Request: gitignore recursion","fromName":"Karsten Blees","fromEmail":"karsten.blees@gmail.com","sentAt":"2013-10-10T07:59:13Z","receivedAt":"2013-10-10T07:59:13Z","isPatch":false,"sender":{"key":"karsten.blees@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1111200?v=4"},"body":"> On Mon, Oct 7, 2013 at 5:23 AM, AJ <allj...@gmail.com> wrote:\n>> I'm hoping to get the following feature implemented into git.\n>>\n>> Add the ability to recursively include using:\n>> !/my_dir/**/*\n> \n> \n> You can do that since v1.8.2. Actually the pattern should be\n> \n> !/my_dir/**\n> \n\nAnother solution to include just one specific directory:\n\n  /*\n  !/wp-content\n  /wp-content/*\n  !/wp-content/themes\n\nNote the \"/*\", instead of \"*\" which matches everything everywhere.\n\n\n> Checkout gitignore man page for more information.\n> \n\nThe compiled version reads like this:\n\n\"A trailing \"/\" matches everything inside. For example, \"abc/\" matches all files inside directory \"abc\"...\"\n\n\n--- 8< ---\nSubject: [PATCH] gitignore.txt: fix documentation of \"**\" patterns\n\n\"**\" means bold in ASCIIDOC, so we need to escape it.\n\nSigned-off-by: Karsten Blees <blees@dcon.de>\n---\n Documentation/gitignore.txt | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt\nindex 54e334e..f971960 100644\n--- a/Documentation/gitignore.txt\n+++ b/Documentation/gitignore.txt\n@@ -113,12 +113,12 @@ full pathname may have special meaning:\n \n  - A leading \"`**`\" followed by a slash means match in all\n    directories. For example, \"`**/foo`\" matches file or directory\n-   \"`foo`\" anywhere, the same as pattern \"`foo`\". \"**/foo/bar\"\n+   \"`foo`\" anywhere, the same as pattern \"`foo`\". \"`**/foo/bar`\"\n    matches file or directory \"`bar`\" anywhere that is directly\n    under directory \"`foo`\".\n \n- - A trailing \"/**\" matches everything inside. For example,\n-   \"abc/**\" matches all files inside directory \"abc\", relative\n+ - A trailing \"`/**`\" matches everything inside. For example,\n+   \"`abc/**`\" matches all files inside directory \"`abc`\", relative\n    to the location of the `.gitignore` file, with infinite depth.\n \n  - A slash followed by two consecutive asterisks then a slash\n-- \n1.8.4.msysgit.1\n"},{"id":"228688","messageId":"52565E6A.2020907@gmail.com","threadId":"35078","inReplyTo":"20131007134141.GA23026@lanh","subject":"Re: Feature Request: gitignore recursion","fromName":"Karsten Blees","fromEmail":"karsten.blees@gmail.com","sentAt":"2013-10-10T07:59:38Z","receivedAt":"2013-10-10T07:59:38Z","isPatch":false,"sender":{"key":"karsten.blees@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1111200?v=4"},"body":"> On Mon, Oct 07, 2013 at 07:24:11AM -0400, Jeff King wrote:\n>> However, one thing I expected to work but didn't is:\n>> \n>>   echo '*' >.gitignore\n>>   echo '!*' >my_dir/.gitignore\n>> \n>> That _does_ work for attributes, like:\n>> \n>>   echo '* foo=one' >.gitattributes\n>>   echo '* foo=two' >my_dir/.gitattributes\n>> \n>> where the more-specific file takes precedence. It works because we keep\n>> an attribute stack, and look from most-specific directory to least.\n\nNote that this doesn't work either:\n\n  echo '*' >.gitignore\n  echo '!my_dir/*' >>.gitignore\n\nThe problem isn't that git doesn't read 'my_dir/.gitignore'. Git simply doesn't recurse into excluded directories, so patterns on excluded content have no effect.\n\nIMO this behavior is reasonable, as there is no way to check whether a negative pattern will match within an excluded untracked directory without scanning the directory.\n\nWhat about this instead?\n\n--- 8< ---\nSubject: [PATCH] gitignore.txt: clarify recursive nature of excluded directories\n\nAdditionally, precedence of negated patterns is exactly as outlined in\nthe description, we don't need to repeat this.\n\nSigned-off-by: Karsten Blees <blees@dcon.de>\n---\n Documentation/gitignore.txt | 5 +++--\n 1 file changed, 3 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/gitignore.txt b/Documentation/gitignore.txt\nindex f971960..a64a65d 100644\n--- a/Documentation/gitignore.txt\n+++ b/Documentation/gitignore.txt\n@@ -79,8 +79,9 @@ PATTERN FORMAT\n \n  - An optional prefix \"`!`\" which negates the pattern; any\n    matching file excluded by a previous pattern will become\n-   included again.  If a negated pattern matches, this will\n-   override lower precedence patterns sources.\n+   included again. It is not possible to re-include a file if a parent\n+   directory of that file is excluded (i.e. excluding a directory\n+   will recursively and irrevocably exclude the entire content).\n    Put a backslash (\"`\\`\") in front of the first \"`!`\" for patterns\n    that begin with a literal \"`!`\", for example, \"`\\!important!.txt`\".\n \n-- \n1.8.4.msysgit.1\n"},{"id":"228700","messageId":"20131010162244.GA21489@sigill.intra.peff.net","threadId":"35078","inReplyTo":"52565E6A.2020907@gmail.com","subject":"Re: Feature Request: gitignore recursion","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2013-10-10T16:22:44Z","receivedAt":"2013-10-10T16:22:44Z","isPatch":false,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Oct 10, 2013 at 09:59:38AM +0200, Karsten Blees wrote:\n\n> > On Mon, Oct 07, 2013 at 07:24:11AM -0400, Jeff King wrote:\n> >> However, one thing I expected to work but didn't is:\n> >> \n> >>   echo '*' >.gitignore\n> >>   echo '!*' >my_dir/.gitignore\n> >> \n> >> That _does_ work for attributes, like:\n> >> \n> >>   echo '* foo=one' >.gitattributes\n> >>   echo '* foo=two' >my_dir/.gitattributes\n> >> \n> >> where the more-specific file takes precedence. It works because we keep\n> >> an attribute stack, and look from most-specific directory to least.\n> \n> Note that this doesn't work either:\n> \n>   echo '*' >.gitignore\n>   echo '!my_dir/*' >>.gitignore\n> \n> The problem isn't that git doesn't read 'my_dir/.gitignore'. Git\n> simply doesn't recurse into excluded directories, so patterns on\n> excluded content have no effect.\n\nGood point. To make it work you need to un-ignore the subdir, like:\n\n  *\n  !my_dir/\n\nat which point \"!my_dir/*\" will work. But then so will a child\n.gitignore in subdir. In fact, I think the only reason that \"!my_dir/**\"\nis needed in the first place is that the \"*\" is too over-reaching; it\nignores both the top-level directories _and_ all of the individual files\nin included directories.\n\nSo I think the best solution for the original problem, which is to\nignore everything except for a particular directory, is:\n\n  # ignore everything at the top-level...\n  /*\n  # ...but specifically include one directory\n  !/my_dir/\n\nand then we do not even need to use \"**\" matching at all (which was\nreally about overriding the over-reaching \"*\").\n\n> IMO this behavior is reasonable, as there is no way to check whether a\n> negative pattern will match within an excluded untracked directory\n> without scanning the directory.\n\nRight. I was focused on not reading the .gitignore, but not descending\ninto the ignore subdir affects patterns we already know about, too.\n\n> --- 8< ---\n> Subject: [PATCH] gitignore.txt: clarify recursive nature of excluded directories\n> \n> Additionally, precedence of negated patterns is exactly as outlined in\n> the description, we don't need to repeat this.\n> \n> Signed-off-by: Karsten Blees <blees@dcon.de>\n\nYeah, I think your update improves things.\n\nI wonder if it is worth adding the \"exclude everything except one\ndirectory\" case above to the EXAMPLES section, too.\n\n-Peff\n"}]}