.gitignore文件中的path差异?

我一直在使用git,但仍然对.gitignore文件path感到困惑。

那么, .gitignore文件中以下两个path有什么区别?

 TMP / *
公共/文件/ ** / *

我可以理解, tmp/*将忽略其中的所有文件和文件夹。 我对吗? 但是,第二条线路是什么意思?

这取决于你的shell的行为。 Git没有做任何工作来确定如何扩展这些。 通常, *匹配任何单个文件或文件夹:

 /a/*/z matches /a/b/z matches /a/c/z doesn't match /a/b/c/z 

**匹配任何string的文件夹:

 /a/**/z matches /a/b/z matches /a/b/c/z matches /a/b/c/d/e/f/g/h/i/z doesn't match /a/b/c/z/d.pr0n 

***结合以匹配整个文件夹树中的文件:

 /a/**/z/*.pr0n matches /a/b/c/z/d.pr0n matches /a/b/z/foo.pr0n doesn't match /a/b/z/bar.txt 

如果你使用的是诸如Bash 4之类的shell,那么**本质上就是*的recursion版本,它将匹配任意数量的子目录。

如果你添加一个文件扩展名到你的例子,这样做更有意义。 要在tmp内部立即匹配日志文件,可以input:

 /tmp/*.log 

要在tmp的任何子目录中的任何地方匹配日志文件,你应该input:

 /tmp/**/*.log 

但使用git版本1.6.0.4和bash版本3.2.17(1)进行testing,发现git根本不支持** globs。 gitignore的最新手册页也没有提到**,所以这个或者是(1)非常新的,(2)不被支持的,或者(3)依赖于你的系统的globbing实现。

另外,在你的例子中还有一些微妙之处。 这个expression式:

 tmp/* 

实际上意味着“忽略源树中任何位置的tmp目录中的任何文件,但不要忽略tmp目录本身”。 在正常情况下,你可能只会写:

 /tmp 

…将忽略单个顶级tmp目录。 如果你需要保留tmp目录,而忽略它们的内容,你应该在每个tmp目录中放置一个空的.gitignore文件,以确保git实际创build目录。

更新(08-Mar-2016)

今天,我无法find一台机器**没有声称工作。 包括OSX-10.11.3(El Capitan)和Ubuntu-14.04.1(Trusty)。 可能是git-ignore被更新,或者可能是最近的fnmatch句柄** 。 所以现在接受的答案在实践中似乎是正确的。


原帖

这个**git中没有特别的意义。 这是bash> = 4.0的一个特性,通过

shopt -s globstar

但是git不使用bash 。 要看看git实际上做了什么,可以尝试使用git add -nv和几个级别的子目录中的文件。

对于OP,我已经试过了我能想到的.gitignore文件的所有组合,没有什么比这更好的了:

public/documents/

以下不是每个人都想到的:

public/documents/**/*.obj

无论我尝试什么,我都无法工作,但至less与git文档是一致的。 我怀疑当人们把它添加到.gitignore ,它是偶然的,只是因为它们的.obj文件恰好是一个子目录。 他们可能从bash脚本中复制了双星号。 但也许有一些系统, fnmatch(3)可以像bash一样处理双星号。

请注意, ** 和子目录**/bar结合在一起时 ,必须改变其默认行为,因为git1.8.2的发行说明现在提到:

.gitignore.gitattributes文件中的模式可以具有**/ ,作为匹配0或更多级子目录的模式。

例如“ foo/**/bar ”与“ foo ”本身或“ foo ”的子目录中的“ foo/**/bar ”相匹配。


参见提交4c251e5cb5c245ee3bb98c7cedbe944df93e45f4 :

foo/**/bar ”匹配“ foo/x/bar ”,“ foo/x/y/bar ”…但不是“ foo/bar ”。
我们做一个特例,当foo/**/被检测到(和“ foo/ ”部分已经匹配)时,尝试将“ bar ”与其余的string进行匹配。

“匹配一个或多个目录”语义可以使用“ foo/*/**/bar ”轻松实现。

这也使得“ **/foo ”除了“ x/foo ”,“ x/y/foo ”之外还匹配“ x/y/foo ”。

签名:NguyễnTháiNgọcDuy <pclouds@gmail.com>


Simon Buchan也评论道 :

当前文档( .gitignore手册页 )很清楚,不需要子目录, x/**匹配所有文件(可能是空的) x

.gitignore手册页确实提到:

尾随“ /** ”匹配里面的所有内容。 例如,“ abc/** ”匹配目录“ abc ”内的所有文件,相对于.gitignore文件的位置,具有无限深度。

斜杠后跟两个连续的星号,则斜线匹配零个或多个目录。 例如,“ a/**/b ”匹配“ a/b ”,“ a/x/b ”,“ a/x/y/b ”等等。

当**不被支持时,“/”基本上是通配符的终止字符,所以当你有这样的东西时:

 public/documents/**/* 

它基本上是在两个斜杠之间寻找两个通配符,并且不会自己去掉斜线。 因此,这将是相同的:

 public/documents/*/* 

它不适用于我,但你可以在该子目录中创build一个新的.gitignore

 tmp/**/*.log 

可以在tmp中用.gitignorereplace:

 *.log