【问题标题】:Git failing to ignore files in subdirectoryGit无法忽略子目录中的文件
【发布时间】:2022-10-03 10:11:30
【问题描述】:

我的 .gitignore 文件似乎没有忽略我想要的所有文件。

==================上下文==================

在我的 git repo 中,我有几个子目录,类似于这个简化的示例:

git base folder
    > .gitignore
    > Folder A
    > Folder B
        > Subfolder B0
            >SubSubfolder B0a
                > Files
        > Subfolder B1
            > SubSubfolder B1a
                > Files
            > File B1b.ft0
            > File B1c.ft0
            > File B1d.ft1
            > File B1e.ft2
            > Etc

我想忽略子文件夹B1 中的所有文件除了(比如说)文件B1b.ft0 和文件B1e.ft2。我还想忽略子子文件夹B1aB0a 中的所有文件。 在我的 .gitignore 文件(只有一个)中,我有以下几行:

#Ignore:
B1/**
B1a/
B0a/

#Include
!B1/B1b.ft0
!B1/B1e.ft2

然而,全部包含子文件夹B1 中的文件。子子文件夹B1a 中的文件忽略,但是子子文件夹 B0a 中的文件是不是.

============== 尝试的解决方案 ==============

我决定首先解决子文件夹B1 中未忽略文件的问题:
我在.gitignore 文件中尝试了B1/,但这忽略了那里的所有文件,包括我想要保留的文件。

我还尝试了B1/*B1/*.*,但它们都无法忽略文件​​夹B1 中的其他文件。

然后我尝试手动列出我想忽略/保留在此文件夹中的所有文件。这行得通,但是有很多文件,它们可能会改变。我不想使用这个选项。

==================方法==================

在测试每个选项是否有效时,我使用了git check-ignore -v <filename>git status --ignore。我还使用git rm --cached -r . 后跟git add -A 来清除被忽略文件的存储库。 (子问题:我需要提交.gitignore 才能生效吗?)

==================总结==================

我对此越来越感到困惑和烦恼,有人可以帮助我吗? (我是否只需要在整个地方应用大量的 *\'s 就可以自动开始工作,as in this question?)

还请解释为什么以及如何,您的解决方案有效,而我的解决方案却没有(如果您知道的话)。

  • 您要忽略的文件已被跟踪?那么.gitignore 对他们没有影响。此外,无需编写规则来跟踪您要跟踪的目录中的 2 个文件几乎忽视。只需忽略目录,然后git add -f 要跟踪的文件,不管规则是否忽略它们。
  • 不......无需提交.gitignore即可生效。它的效果是立竿见影的,无论它是否被跟踪/未跟踪/等等。

标签: windows git


【解决方案1】:

经过大量的测试,reading documentation(相当不错),并询问了其他人,我终于找到了解决方案。 (是的,它确实涉及在各处喷洒大量*)。我会尽力解释我认为发生了什么,以及如何避免它。


简短的回答:

Git 没有忽略子文件夹 B1 中的文件,因为它希望 B1 位于根目录中。将 .gitignore 条目更改为 **/B1/**!**/B1/B1b.ft0!**/B1/B1e.ft2 解决了这个问题。

长(呃)答案:

理解这个问题的关键是理解 .gitignore 语法的一些奇怪之处。幸运的是,没有太多要学习的东西,即使其中一些令人沮丧地晦涩难懂——例如,您可能知道 gitignore 文件是向下读取的,这会导致这种行为:

foo is not ignored foo is ignored completely
 foo 
!foo
 !foo 
foo

我的问题与 .gitignore 语法中另一个神秘的微妙之处有关:它如何解析文件路径。 gitignore 目录分隔符是/,但是根据它在一行中的位置,或者有多少,它的行为方式完全不同:

对于只有一个 / 的条目:

/ at end of line, as in foo/ / in middle of line, as in foo/bar / at start of line, as in /foo
Git ignores every directory named foo, no matter how many subdirectories deep it is. Git ignores any folders and files named bar in the filepath <.gitignore_directory>/foo/. Folders (or files) named foo/bar will only be ignored if they have that specific filepath, i.e, the path starts in the same directory as the .gitignore file. Git ignores any files and folders named foo, but only if they are in the same directory as the .gitignore file.

对于具有多个/s 的条目,规则是上述规则的组合。几个例子说明:

/foo/ foo/bar/ /foo/bar
This pattern matches only one item: a subfolder in the same folder as the .gitignore, named foo. (Of course, everything inside it is ignored too.) This pattern also only matches one item, a subsubfolder named bar found inside the folder foo, which itself must be a subfolder of the folder that also contains the .gitignore file. This pattern is identical to one in the middle example, except it can also ignore a file named bar, not just a directory.

在上述所有情况下,任何被忽略目录中的文件和子目录foo不能被例如忽略!foo/bar

狡猾的微妙之处在于/ 在像foo/ 这样的行的末尾会导致任何名为foo 的目录将被忽略,无论其深度如何,但在/ 之后放置任何字符(包括通配符!),或者将任何其他 / 放在同一行中将意味着它仅与找到 .gitignore 的路径匹配。那么,如何才能忽略子目录中的文件呢?

通配符

解决方法是更好地使用通配符。 .gitignore 语法中有三个通配符:

  • ? - 匹配 1而且只有 1字符,/ 除外。几乎只用于文件名匹配。
  • * - 匹配 0 个或多个字符,/ 除外
  • ** - 匹配 0 个或多个字符,包括 /

* 可用于忽略目录中的所有文件,但不能忽略子文件夹。如果foo 与.gitignore 位于同一目录中,则以下示例都将忽略子目录foo 中的所有文件。

  • foo/*
  • foo/? 这个只会忽略名称只有 1 个字符且没有扩展名的文件。

但是,请注意,这些将不是忽略文件,例如<.gitignore_directory>/filepath/foo

由于** 匹配目录,它可以像这样解决上述问题:**/foo/。即使/ 后面有一个非空白字符,这也会忽略全部名为foo 的目录和子目录,因为**/ 匹配全部文件路径。

  • **/foo/? 忽略任何目录 foo 中的所有 1 字符命名文件。
  • foo/**/bar.txt 忽略名为foo 的文件夹内任意深度的每个名为bar.txt 的文件,其中foo<.gitignore_directory> 中。
  • **/foo/** 忽略每个目录 foo 中的所有内容,但是不忽略目录本身,因此我可以忽略其中的几个文件!

耶!我的问题得到了回答——几乎。

关于子子文件夹 B0a:

对于我的 .gitignore 中忽略 SubSubfolder B0a 的条目,我实际上与我的要求略有不同。在我的实际项目中,B0a 被称为.generated_files。我不完全确定 git 会如何看待以点开头的 .gitignore 条目,所以我在它前面加上了一个斜杠,如下所示:/.generated_files/。 (当我写这个问题时我忘记了这一点。)正如我现在所了解到的,这导致 git 只期望它在根目录中,因此错过了它。 我还了解到,如果条目以. 开头,git 一点也不关心。


最后的笔记

尽管在我的情况下它没有引起问题,但我还发现 .gitignore 文件中的条目将匹配文件和文件夹。所以如果你有一个名为 foo 的文件一个名为 foo 的文件夹,将 foo 放在 .gitignore 中会导致它们都被忽略。

希望这个答案对您有所帮助,恐怕阅读official documentation 可能会更容易理解。

【讨论】:

    猜你喜欢
    • 2011-02-02
    • 1970-01-01
    • 2021-12-20
    • 2012-01-21
    • 1970-01-01
    • 1970-01-01
    • 2012-11-15
    • 2011-08-12
    • 1970-01-01
    相关资源
    最近更新 更多