.gitignore排除规则实际上如何工作?


146

我正在尝试解决大型目录结构上的gitignore问题,但是为了简化我的问题,我将其简化为以下内容。

我在全新的git存储库中具有以下两个文件(foo,bar)的目录结构(到目前为止尚未提交):

a/b/c/foo
a/b/c/bar

显然,“ git status -u”显示:

# Untracked files:
...
#       a/b/c/bar
#       a/b/c/foo

我想做的是创建一个.gitignore文件,该文件忽略a / b / c内部的所有内容,但不忽略文件'foo'。

如果我这样创建一个.gitignore:

c/

然后,'git status -u'显示foo和bar被忽略:

# Untracked files:
...
#       .gitignore

这是我所期望的。

现在,如果我为foo添加排除规则,则:

c/
!foo

根据gitignore的联机帮助页,我希望它能起作用。但这不是-它仍然忽略foo:

# Untracked files:
...
#       .gitignore

这也不起作用:

c/
!a/b/c/foo

这也不是:

c/*
!foo

给出:

# Untracked files:
...
#       .gitignore
#       a/b/c/bar
#       a/b/c/foo

在这种情况下,尽管不再忽略foo,也不会忽略bar。

.gitignore中规则的顺序似乎也无关紧要。

这也没有达到我的期望:

a/b/c/
!a/b/c/foo

那个人忽略了foo和bar。

起作用的一种情况是,如果我创建文件a / b / c / .gitignore并放在其中:

*
!foo

但是问题是最终在a / b / c下会有其他子目录,而我不想将每个单独的.gitignore放到每个子目录中-我希望创建“基于项目”的.gitignore这些文件可以位于每个项目的顶部目录中,并涵盖所有“标准”子目录结构。

这似乎也等效:

a/b/c/*
!a/b/c/foo

这可能是我可以实现的与“工作”最接近的事情,但是需要说明完整的相对路径和显式异常,如果我在不同级别具有大量名称为“ foo”的文件,这将是一件痛苦的事情子目录树。

无论如何,要么我不太了解排除规则的工作原理,要么忽略目录(而不是通配符)时它们根本不起作用-规则以/结尾

任何人都可以对此有所了解吗?

有没有办法使gitignore使用明智的东西(如正则表达式)代替这种笨拙的基于shell的语法?

我正在使用Cygwin / bash3上的git-1.6.6.1和Ubuntu / bash3上的git-1.7.1进行观察。



4
优秀的书面问题!您尝试的案例数量确实帮助我了解了类似案例中我做错了什么。谢谢上帝,我已经找了很久了。
亚历克斯G

Answers:


153
/ a / b / c / *
!foo

似乎对我有用(Linux上为git 1.7.0.4)。这*很重要,因为否则您将忽略目录本身(因此git不会进入内部),而不是目录中的文件(这将排除在外)。

认为排除是在说“但不是这个”而不是“但包括这个”-“忽略此目录(/a/b/c/),而不是这个目录(foo)”没有多大意义;“忽略此目录(/a/b/c/*)中的所有文件,但忽略此目录(foo)”。引用手册页:

可选的前缀!否定了模式;先前模式排除的所有匹配文件将再次包含在内。

也就是说,该文件必须已经被排除在外,才能再次包含在内。希望能阐明一点。


是的,您提供的示例对我来说也很好。问题是,如果foo在c中,则/ a / b / *不起作用,这意味着如果我在c下的各个子目录中有多个foo文件(例如d /,e /,f / g / h /,i / j /等),则否定规则'!foo'将不会捕获这些规则。
davidA 2010年

1
@meowsqueak确实不会。如果您忽略/ a / b / *,则没有foo所在的目录!如果您想忽略/ a / b下的整个目录树,但要包括树中任何位置的任何名为“ foo”的文件,则我认为.gitignore模式不可行:\
Chris

实际上,这可能可以解释为什么这对我不起作用-以下规则不起作用:“ / a / b / *”,“!c / foo”。如果可行,则可能没有问题。
davidA 2010年

5
“我认为使用.gitignore模式不可行”-不幸的是,我认为您是对的。
davidA 2010年

@meowsqueak您可能会忽略/a/b/c,然后将钩子写入git add --force任何预先提交的匹配文件或其他内容
Chris 2010年

24

我有类似的情况,我的解决方案是使用:

/a/**/*
!/a/**/foo

如果我**正确阅读的话,这应该适用于任意数量的中间目录。


6

从.gitignore手册页中绝对不清楚。这有效:

*
!/a
!/a/b
!/a/b/c
!/a/b/c/foo

# don't forget this one
!.gitignore

如Chris所述,如果排除了某个目录,它甚至不会打开。因此,如果您希望能够忽略*但可以忽略某些文件,则必须如上所述构建这些文件的路径。对我来说,这很方便,因为我想对库的一个文件进行代码审查,如果以后要对另一个文件进行审查,则只需添加它,其他所有内容都将被忽略。


6

这是另一种选择:

*
!/a*
!/a/*
!/a/*/*
!/a/*/*/*

这将忽略每个文件和目录,但文件/目录中不包含三个级别的文件/目录。


5

更笼统地说,git1.8.2将包含Adam Spiers补丁(也在v4中由某些Stack Overflow问题提示),用于确定哪个规则实际上忽略了您的文件。gitignore

请参阅git1.8.2发行说明和SO问题“ 哪个gitignore规则正在忽略我的文件 ”:
这将是命令git check-ignore


1
感谢您广播此信息。 如果是这种情况,check-ignore还会告诉您哪个规则阻止您的文件被忽略。
亚当·斯皮尔斯

@AdamSpiers听起来很棒。我一定会玩的。
VonC
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.