ChatGPT解决这个技术问题 Extra ChatGPT

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

我正在尝试解决大型目录结构上的 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 并观察它。

写得很好的问题!您尝试的案例数量确实帮助我理解了我在类似案例中做错了什么。谢天谢地,今天找了好久。

C
Chris
/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' 不会捕捉到这些。
@meowsqueak 确实不会。如果您忽略 /a/b/* 则没有 foo 所在的目录!如果您试图忽略 /a/b 下的整个目录树,但包含任何名为“foo”的文件,该文件可以位于树中的任何位置,我认为 .gitignore 模式不可行:\
实际上,这可以解释为什么这对我不起作用 - 以下规则不起作用:“/a/b/*”、“!c/foo”。如果这有效,则可能没有问题。
“我认为 .gitignore 模式不可行” - 不幸的是,我认为你是对的。
@meowsqueak 你可能会忽略 /a/b/c 然后写一个钩子到 git add --force 任何匹配的文件预提交或其他东西
R
Rafał Rawicki

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

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

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


P
Peter Petrik

这是另一种选择:

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

这将忽略每个文件和目录,除了文件/目录在 a.


佚名

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

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

# don't forget this one
!.gitignore

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


C
Community

在更一般的说明中,git1.8.2 将包含来自 Adam Spierspatch(也称为 in its v4prompted by some Stack Overflow question),用于确定哪个 gitignore 规则实际上忽略了您的文件。

请参阅 git1.8.2 release notes 和 SO 问题“which gitignore rule is ignoring my file”:
将是命令 git check-ignore


感谢您传播此信息。如果是这种情况,check-ignore 还会告诉您哪个规则防止您的文件被忽略。
@AdamSpiers 听起来很棒。我一定会玩它的。