.gitignore语法:bin vs bin / vs bin / * vs bin / **
在我的.gitignore文件中添加bin
, bin/
, bin/*
和bin/**
什么区别? 我一直在使用bin/
,但是看着其他的 .gitignore文件 (在eclipse文件中 ,双精度和单精度精度都是这样一起使用的: tmp/**/*
这是怎么回事?)我看到前两个模式也被广泛使用。 有人可以解释三者之间的区别吗?
bin
匹配任何名为“bin”的文件或目录。
bin/
匹配任何名为“bin”的目录 ,这实际上意味着它的所有内容,因为Git不会单独跟踪目录。
bin/*
直接在任何bin/
匹配所有文件和目录。 这样可以防止Git在其子目录中自动查找任何文件,但是如果创build了bin/foo
子目录,则该规则将与foo
的内容不匹配。
bin/**
匹配任何bin/
目录及其所有子目录中的所有文件和目录。
“any”这个词在这里至关重要,因为规则不是相对于版本库的根,而是应用在文件系统树的任何地方 。 您必须使用/
(或!/
取消忽略)开始规则,这意味着存储库的根目录,而不是系统的根目录,以便仅匹配预期的目标。
警告:你不应该单独使用像dir/*
, /dir/**
等规则, 除非你也不要忽略该目录内存在的东西 。 省略星号,或者你可能会永久失去一些git gc
, git stash
等的调用的大量数据 。
我真的不知道tmp/**/*
是做什么的。 我最初认为它可以用来匹配tmp/
的子目录中的文件,而不是直接存在于tmp/
本身中的文件。 但是一个简单的testing似乎表明这忽略了tmp/
所有文件。
bin
和bin/
区别只在于后者只能匹配一个目录。
bin/**/*
与bin/**
相同(从1.8.2开始,根据@ VonC的回答)。
那个棘手的问题,就是我花了一个小时左右的时间把我的头发拉出来,是bin/
和bin/**
不太一样! 由于之前忽略了整个目录,后者忽略了其中的每个文件,git几乎在所有情况下都不关心目录,通常没有区别。 但是,如果您尝试使用!
要忽略子path,那么你会发现,如果忽略父目录,git(ahem)会忽略它! (再次,而不是目录内容)
这个例子是最清楚的,所以对于一个新创build的仓库来说:
$ cat .gitignore ignored-file or-dir dir-only/ !dir-only/cant-reinclude dir-contents/** !dir-contents/can-reinclude $ mkdir or-dir dir-only dir-contents $ touch file ignored-file or-dir/ignored-file dir-only/cant-reinclude dir-contents/can-reinclude
存在以下未跟踪的文件:
$ git ls-files --other .gitignore dir-contents/can-reinclude dir-only/cant-reinclude file ignored-file or-dir/ignored-file
但是您可以看到以下文件不被忽略:
$ git ls-files --other --exclude-standard .gitignore dir-contents/can-reinclude file
如果你尝试添加,你会得到:
$ git add dir-only/cant-reinclude The following paths are ignored by one of your .gitignore files: dir-only/cant-reinclude Use -f if you really want to add them. fatal: no files added
我认为这是一个错误。 (这是所有的git version 1.8.4.msysgit.0
)
请注意,严格来说,git不会跟踪目录,只会跟踪文件。 因此不可能添加一个目录,只有其内容 。
然而在.gitignore
的背景下,git假装理解目录是唯一的原因
如果排除该文件的父目录,则不可能重新包含文件。
https://git-scm.com/docs/gitignore#_pattern_format
这对排除模式意味着什么? 我们来详细的介绍一下:
bin
这忽略了
- 名为
bin
文件。 - 名为
bin
的文件夹的内容
您可以通过添加随后的白名单来忽略bin
文件和文件夹!
条目,但无法将名为bin
的文件夹的内容列入白名单
bin !bin/file_in_bin # has no effect, since bin/ is blacklisted! !bin/* # has no effect, since bin/ is blacklisted! !file_in_bin # has no effect, since bin/ is blacklisted! !bin # this works
bin/
与上面相同,只是它不匹配名为bin
文件 。 添加尾随/
告诉GIT只匹配目录。
bin/*
这忽略了
- 包含在名为
bin
的文件夹中的文件 -
bin
文件夹的直接子文件夹的内容
bin/* # blacklists bin/file_in_bin and bin/subfolder/ !bin/subfolder/file_in_sub # has no effect, since bin/subfolder is blacklisted! !bin # whitelists files named bin/bin, since bin/ itself is not blacklisted !bin/ # has no effect, since bin/ itself is not blacklisted !bin/file_in_bin # works since bin/ itself is not blacklisted !file_in_bin # works too !bin/subfolder # works (so implicitly whitelists bin/subfolder/file_in_sub) !bin/subfolder/ # works just as well !bin/* # works for file_in_bin and subfolder/
bin/**
这忽略了
-
bin
内容 -
bin
中子文件夹的内容(嵌套的任何级别)
bin/** # blacklists bin/file_in_bin and # bin/subfolder/ and bin/subfolder/file_in_sub and # bin/subfolder/2/ and bin/subfolder/2/file_in_sub_2 !bin/subfolder/file_in_sub # has no effect, since bin/subfolder is blacklisted !bin/subfolder/2/ # has no effect, since bin/subfolder is blacklisted !bin/subfolder/2/file_in_sub_2 # has no effect, since bin/subfolder is blacklisted !bin/subfolder # works only in combinations with other whitelist entries, # since all contents of subfolder are blacklisted (1) !bin/file_in_bin # works since bin itself is not blacklisted !bin/* # works for file_in_bin and subfolder; see (1)
我刚刚做了一个新的回购,并尝试了一些东西。 这是我的结果:
新的结果
git版本2.10.1.windows.1
- 初始化几乎空的回购。 只有README文件
- 将
bin
目录填充几层-
bin.txt
-
Test.txt
-
bin/a/b/bin.txt
-
bin/a/b/Test.txt
-
bin/a/bin/bin.txt
-
bin/a/bin/Test.txt
-
bin/a/bin.txt
-
bin/a/Test.txt
-
bin/bin.txt
-
bin/Test.txt
-
- 添加
bin
到gitignore:结果-
bin
目录下(和更深)的所有内容现在都被忽略了 - 根级别不被忽略(/bin.txt和/Test.txt仍然显示)
-
- 编辑
bin
到bin/
gitignore:结果- 不用找了
- 编辑
bin/
到bin/*
- 不用找了
- 编辑
bin/*
到bin/**
- 不用找了
- 编辑
bin/**
到bin/**/
-
bin/bin.txt
和bin/Test.txt
不再被忽略
-
- 编辑
bin/**/
到bin/**/*
-
bin/bin.txt
和bin/Test.txt
重新被忽略
-
老结果
git版本:2.7.0.windows.1
- 初始化几乎空的回购。 只有README文件
- 将
bin
目录填充几层-
bin/a/b/Test.txt
-
bin/a/bin/Test.txt
-
bin/a/Test.txt
-
bin/Test.txt
-
- 添加
bin
到gitignore:结果-
bin
目录下(和更深)的所有内容现在都被忽略了
-
- 编辑
bin
到bin/
gitignore:结果-
bin
目录下的所有东西(还有更深的)仍然被忽略(没有改变)
-
- 编辑
bin/
到bin/*
-
bin
目录下的所有东西(还有更深的)仍然被忽略(没有改变)
-
- 编辑
bin/*
到bin/**
-
bin
目录下的所有东西(和更深的)仍然被忽略(没有改变)
-
- 编辑
bin/**
到bin/**/
-
bin/Test.txt
不再被忽略
-
- 编辑
bin/**/
到bin/**/*
-
bin
目录下的所有内容(以及更深)都会被忽略
-
请注意, **
和子目录 ( **/bar
) 结合在一起时 ,必须改变其默认行为,因为git1.8.2的发行说明现在提到:
.gitignore
和.gitattributes
文件中的模式可以具有**/
,作为匹配0或更多级子目录的模式。例如“
foo/**/bar
”与“foo
”本身或“foo
”的子目录中的“foo/**/bar
”相匹配。
要记住的规则(以及哪些帮助理解这些语法背后的意图的差异)是:
如果排除该文件的父目录,则不可能重新包含文件。
通常情况下,如果要从忽略文件夹f的子文件夹中排除文件,您应该:
f/** !f/**/ !f/a/sub/folder/someFile.txt
那是:
- 如果第一个规则是
f/
,那么文件夹f/
将被忽略,下面有关f
规则将无关紧要。 -
f/**
实现与f/
相同,但忽略所有子元素 (文件和子文件夹)。
这使您有机会白名单(从gitignore排除)子文件夹:!f/**/
。 - 由于所有
f
子文件夹都不被忽略,所以可以添加一个规则来排除一个文件(!f/a/sub/folder/someFile.txt
)
bin/*
和bin/
还有另一个区别。
bin/
匹配foo/bin/test.txt
(与预期的一样),但是bin/*
没有,这看起来很奇怪,但是有logging: https : //git-scm.com/docs/gitignore
“Documentation / *。html”与“Documentation / git.html”匹配,但不匹配“Documentation / ppc / ppc.html”或“tools / perf / Documentation / perf.html”。
原因似乎是这些规则:
如果模式以斜线结尾,则为了下面的描述将其删除…
如果模式不包含斜杠/,Git会将其视为shell glob模式,并检查与path名相对于.gitignore文件位置的匹配项。
否则,Git会将该模式视为适合fnmatch(3)与FNM_PATHNAME标志使用的shellshell…
因此,如果模式以斜线结尾,斜杠将被删除,并将其视为一个shell glob模式,在这种情况下bin
匹配foo/bin/test.txt
。 如果以/*
结尾,则斜杠不会被删除,并且会传递给fnmatch,这在子目录中不匹配。
但是,对于foo/bin/
和foo/bin/*
,因为即使从foo/bin/
删除了尾部斜杠,它仍然包含一个斜杠,所以它被视为fnmatch模式,而不是glob。 即它不会匹配bar/foo/bin/test.txt