gitignore排除规则如何实际运作?

dav*_*idA 142 git gitignore

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

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

a/b/c/foo
a/b/c/bar
Run Code Online (Sandbox Code Playgroud)

显然,'git status -u'显示:

# Untracked files:
...
#       a/b/c/bar
#       a/b/c/foo
Run Code Online (Sandbox Code Playgroud)

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

如果我创建一个.gitignore:

c/
Run Code Online (Sandbox Code Playgroud)

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

# Untracked files:
...
#       .gitignore
Run Code Online (Sandbox Code Playgroud)

这是我所期待的.

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

c/
!foo
Run Code Online (Sandbox Code Playgroud)

根据gitignore手册页,我希望这可行.但它没有 - 它仍然忽略了foo:

# Untracked files:
...
#       .gitignore
Run Code Online (Sandbox Code Playgroud)

这也不起作用:

c/
!a/b/c/foo
Run Code Online (Sandbox Code Playgroud)

这也不是:

c/*
!foo
Run Code Online (Sandbox Code Playgroud)

得到:

# Untracked files:
...
#       .gitignore
#       a/b/c/bar
#       a/b/c/foo
Run Code Online (Sandbox Code Playgroud)

在这种情况下,虽然不再忽略foo,但也不会忽略bar.

.gitignore中规则的顺序似乎也不重要.

这也不符合我的期望:

a/b/c/
!a/b/c/foo
Run Code Online (Sandbox Code Playgroud)

那个人忽略了foo和bar.

一种有效的方法是,如果我创建文件a/b/c/.gitignore并放入其中:

*
!foo
Run Code Online (Sandbox Code Playgroud)

但问题是最终在/ b/c下会有其他子目录,我不想在每一个中都放一个单独的.gitignore - 我希望创建'基于项目'.gitignore可以位于每个项目的顶级目录中的文件,并覆盖所有"标准"子目录结构.

这似乎也是等价的:

a/b/c/*
!a/b/c/foo
Run Code Online (Sandbox Code Playgroud)

这可能是我可以实现的最接近"工作"的东西,但需要说明完整的相对路径和明确的异常,如果我在不同级别有很多名为'foo'的文件,那将会很痛苦子目录树的.

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

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

有没有办法让gitignore使用像正则表达式那样合理的东西而不是这种笨拙的基于shell的语法?

我在Cygwin/bash3上使用git-1.6.6.1并在Ubuntu/bash3上使用git-1.7.1进行观察.

Chr*_*ris 144

/a/b/c/*
!foo

似乎适合我(Linux上的git 1.7.0.4).这*很重要,否则你忽略了目录本身(因此git不会查看内部)而不是目录中的文件(允许排除).

把排除想象成"但不是这个"而不是"但包括这个" - "忽略这个目录(/a/b/c/)但不是这个(foo)"没有多大意义; "忽略这个目录中的所有文件(/a/b/c/*)但不是这一个(foo)".引用手册页:

一个可选的前缀!否定了这种模式; 之前模式排除的任何匹配文件将再次包含在内.

即,必须已经排除该文件以便再次包括在内.希望能有所启发.

  • "我不认为这对.gitignore模式是可行的" - 不幸的是,我认为你是对的. (5认同)

小智 24

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

/a/**/*
!/a/**/foo
Run Code Online (Sandbox Code Playgroud)

如果我**正确读取,那应该适用于任意数量的中间目录.


小智 6

这是另一种选择:

*
!/a*
!/a/*
!/a/*/*
!/a/*/*/*
Run Code Online (Sandbox Code Playgroud)

这会忽略每个文件和目录,除了文件/目录中的三个级别.


小智 5

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

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

# don't forget this one
!.gitignore
Run Code Online (Sandbox Code Playgroud)

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


Von*_*onC 5

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

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

  • 感谢您传播此信息。如果是这种情况,“check-ignore”还会告诉您哪个规则“防止”您的文件被忽略。 (2认同)