63

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

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

时间/*
公共/文件/**/*

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

4

6 回答 6

63

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

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

**匹配任何文件夹字符串:

/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
于 2009-03-25T12:10:59.103 回答
19

更新(2016 年 3 月 8 日)

今天,我找不到一台**不能按要求工作的机器。这包括 OSX-10.11.3 (El Capitan) 和 Ubuntu-14.04.1 (Trusty)。可能是 git-ignore 已更新,或者可能是人们期望的最近的fnmatch句柄。**因此,现在接受的答案在实践中似乎是正确的。


原帖

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

shopt -s globstar

但是git不使用bash。要查看gitgit add -nv实际执行的操作,您可以在多个级别的子目录中尝试和文件。

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

public/documents/

以下内容并不像每个人都认为的那样:

public/documents/**/*.obj

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

于 2010-12-31T02:22:00.730 回答
17

如果您使用的是 Bash 4 等 shell,那么 ** 本质上是 * 的递归版本,它将匹配任意数量的子目录。

如果您为示例添加文件扩展名,这将更有意义。要在 tmp 中立即匹配日志文件,您可以键入:

/tmp/*.log

要匹配 tmp 的任何子目录中任何位置的日志文件,您可以键入:

/tmp/**/*.log

但是使用 git 版本 1.6.0.4 和 bash 版本 3.2.17(1)-release 进行测试,似乎 git 根本不支持 ** glob。gitignore的最新手册页也没有提到 **,因此这要么是 (1) 非常新,(2) 不受支持,要么 (3) 在某种程度上取决于您的系统对 globbing 的实现。

此外,您的示例中还有一些微妙的地方。这个表达式:

tmp/*

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

/tmp

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

于 2009-03-25T12:07:45.710 回答
17

请注意,当与子目录( ) 结合使用时,' **'必须已从其默认行为更改,因为git1.8.2 的发行说明现在提到:**/bar

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

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


请参阅提交 4c251e5cb5c245ee3bb98c7cedbe944df93e45f4

foo/**/bar”匹配“ foo/x/bar”、“ foo/x/y/bar”……但不匹配“ foo/bar”。
我们做一个特殊情况,当foo/**/检测到(并且“ foo/”部分已经匹配)时,尝试将“ bar”与字符串的其余部分匹配。

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

这也使得“**/foo匹配”foo除了“ x/foo”,“ x/y/foo”..

签字人:Nguyễn Thái Ngọc Duy<pclouds@gmail.com>


Simon Buchan评论说

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

.gitignore手册页确实提到:

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

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

于 2013-02-18T07:33:41.417 回答
5

当不支持**时,“/”本质上是通配符的终止字符,所以当你有类似的东西时:

public/documents/**/*

它本质上是在斜线之间寻找两个通配符项目,而不是自己拿起斜线。因此,这将与以下内容相同:

public/documents/*/*
于 2011-06-02T18:42:35.210 回答
2

它对我不起作用,但您可以.gitignore在该子目录中创建一个新的:

tmp/**/*.log

可以替换为.gitignorein tmp

*.log
于 2009-05-27T14:00:10.263 回答