简体   繁体   English

Git 无法忽略子目录中的文件

[英]Git failing to ignore files in subdirectory

My.gitignore file does not seem to be ignoring all the files I want it to. My.gitignore 文件似乎并没有忽略我想要的所有文件。

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

In my git repo, I have several subdirectories, similar to this reduced example:在我的 git 存储库中,我有几个子目录,类似于这个简化的示例:

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

I want to ignore all files in Subfolder B1 except (say) file B1b.ft0 and file B1e.ft2 .我想忽略子文件夹B1中的所有文件,除了(比如说)文件B1b.ft0和文件B1e.ft2 I also want to ignore all files in SubSubfolder B1a and B0a .我还想忽略 SubSubfolder B1aB0a中的所有文件。 In my .gitignore file (there is only one), I have these lines:在我的.gitignore文件(只有一个)中,我有以下几行:

#Ignore:
B1/**
B1a/
B0a/

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

However, all of the files in Subfolder B1 are included.但是,子文件夹B1中的所有文件都包括在内。 Files in SubSubfolder B1a are ignored, however files in SubSubfolder B0a are not . SubSubfolder B1a中的文件忽略,但是 SubSubfolder B0a中的文件不是

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

I decided to start by solving the problem of unignored files in Subfolder B1 first:我决定首先解决子文件夹B1中未忽略文件的问题:
I tried B1/ in the .gitignore file, but this ignored all the files there, including the ones I want to keep.我在.gitignore文件中尝试了B1/ ,但这忽略了那里的所有文件,包括我想要保留的文件。

I also tried B1/* and B1/*.* , but these both fail to ignore the other files in folder B1 .我也尝试过B1/*B1/*.* ,但它们都无法忽略文件夹B1中的其他文件。

Then I tried manually listing all the files I want to ignore/keep in this folder.然后我尝试手动列出我想忽略/保留在此文件夹中的所有文件。 This worked, but there are a lot of files and they might change.这行得通,但是有很多文件,它们可能会改变。 I don't want to have to use this option.我不想使用这个选项。

================== Methods ================== ==================方法==================

When testing if each option works, I used git check-ignore -v <filename> and git status --ignore .在测试每个选项是否有效时,我使用git check-ignore -v <filename>git status --ignore I also used git rm --cached -r.我还使用git rm --cached -r. followed by git add -A to clear the repo of ignored files.然后是git add -A以清除忽略文件的存储库。 (Subquestion: do I need to commit the .gitignore before it will take effect?) (子问题:我需要提交.gitignore才能生效吗?)

================== Summary ================== ==================总结==================

I'm getting more and more confused and annoyed by this, can anyone help me?我越来越对此感到困惑和烦恼,有人可以帮助我吗? (Do I just need to apply a generous quantity of *'s all over the place for it to automagically start working, as in this question ?) (我是否只需要在整个地方应用大量的 * 就可以自动开始工作, 就像在这个问题中一样?)

Please also explain why, and how, your solution works while my ones don't (if you know).还请解释为什么以及如何,您的解决方案有效,而我的解决方案无效(如果您知道的话)。

After a significant amount of testing, reading documentation (quite good), and asking other people, I finally found a solution.经过大量测试、阅读文档(非常好)并询问其他人,我终于找到了解决方案。 (And yes it does involve sprinkling a generous quantity of *'s everywhere). (是的,它确实涉及在各处喷洒大量*)。 I'll do my best to explain what I think was going on, and how it can be avoided.我会尽力解释我认为发生了什么,以及如何避免它。


Short answer:简短的回答:

Git was not ignoring the files in Subfolder B1 because it expected B1 to be in the root directory. Git 没有忽略子文件夹B1中的文件,因为它希望B1位于根目录中。 Changing the.gitignore entries to **/B1/** , .**/B1/B1b.ft0 , and .**/B1/B1e.ft2 fixed the problem.将 .gitignore 条目更改为**/B1/**.**/B1/B1b.ft0.**/B1/B1e.ft2解决了问题。

Long(er) answer:长(呃)答案:

The key to understanding this problem is to understand some oddities of the.gitignore syntax.理解这个问题的关键是理解 .gitignore 语法的一些奇怪之处。 Fortunately, there is not much of it to learn, even though some of it is frustratingly arcane - for instance, you may know that gitignore files are read downwards, leading to this behaviour:幸运的是,没有太多要学习的东西,即使其中一些令人沮丧地晦涩难懂——例如,您可能知道 gitignore 文件是向下读取的,这会导致这种行为:

foo is not ignored foo没有被忽略 foo is ignored completely foo被完全忽略
foo
!foo !富
!foo !富
foo

My issue was related to another arcane subtlety in the.gitignore syntax: how it parses filepaths.我的问题与 .gitignore 语法中另一个神秘的微妙之处有关:它如何解析文件路径。 The gitignore directory separator is / , but depending on its location in a line, or how many of them there are, it behaves in quite different ways: gitignore 目录分隔符是/ ,但是根据它在一行中的位置,或者有多少,它的行为方式完全不同:

For entries with only one / :对于只有一个/的条目:

/ at end of line, as in foo/ /在行尾,如foo/ / in middle of line, as in foo/bar /在行的中间,如foo/bar / at start of line, as in /foo /在行首,如/foo
Git ignores every directory named foo , no matter how many subdirectories deep it is. Git 忽略每个名为foo的目录,无论它有多深的子目录。 Git ignores any folders and files named bar in the filepath <.gitignore_directory>/foo/ . Git 忽略文件路径<.gitignore_directory>/foo/中名为bar的任何文件夹和文件 Folders (or files) named foo/bar will only be ignored if they have that specific filepath, ie, the path starts in the same directory as the.gitignore file.名为foo/bar的文件夹(或文件)只有在具有特定文件路径的情况下才会被忽略,即该路径从与 .gitignore 文件相同的目录开始。 Git ignores any files and folders named foo , but only if they are in the same directory as the.gitignore file. Git 忽略任何名为foo的文件和文件夹,前提是它们与 .gitignore 文件位于同一目录中。

For entries with multiple / s, the rules are a combination of the above rules.对于有多个/的条目,规则是上述规则的组合。 A few examples demonstrate:几个例子说明:

/foo/ foo/bar/ /foo/bar
This pattern matches only one item: a subfolder in the same folder as the.gitignore, named foo .此模式仅匹配一项:与 .gitignore 位于同一文件夹中的子文件夹,名为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.此模式只匹配一个项目,即在文件夹foo中找到的名为bar的子子文件夹,它本身必须是也包含 .gitignore 文件的文件夹的子文件夹。 This pattern is identical to one in the middle example, except it can also ignore a file named bar , not just a directory.此模式与中间示例中的模式相同,除了它还可以忽略名为bar的文件,而不仅仅是目录。

In all the above cases, files and subdirectories within any ignored directory foo can not be unignored by eg !foo/bar .在上述所有情况下,任何被忽略的目录foo中的文件和子目录都不能被例如!foo/bar忽略。

The devious subtlety is that a / at the end of a line like foo/ will cause any directory named foo to be ignored, no matter of its depth, but putting any character (including wildcards!) after that / , or putting any other / in the same line will mean it matches only relative to the path where the.gitignore is found.狡猾的微妙之处在于,像foo/ /的行末尾的 / 将导致任何名为foo的目录被忽略,无论其深度如何,但在/之后放置任何字符(包括通配符!),放置任何其他/在同一行中将意味着它仅与找到 .gitignore 的路径相关。 So then, how can files inside a subdirectory be unignored?那么,如何才能忽略子目录中的文件呢?

Wildcards通配符

The fix is to make better use of the wildcards.解决方法是更好地使用通配符。 There are three wildcards in.gitignore syntax: .gitignore 语法中有三个通配符:

  • ? - matches 1 or more characters, except / . - 匹配 1 个或多个字符,除了/ Almost only used for filename matching.几乎只用于文件名匹配。
  • * - matches 0 or more characters, except / * - 匹配 0 个或多个字符,除了/
  • ** - matches 0 or more characters, including / . ** - 匹配 0 个或多个字符,包括/

? or * can be used to ignore all files in a directory, but not subfolders.*可用于忽略目录中的所有文件,但不能忽略子文件夹。 The following examples will both ignore all files in the subdirectory foo , if foo resides in the same directory as.gitignore.如果foo与 .gitignore 位于同一目录中,则以下示例都将忽略子目录foo中的所有文件。

  • foo/*
  • foo/? This one will not ignore files with 0-character names.这不会忽略名称为 0 字符的文件。

However, note that these will not ignore files in eg <.gitignore_directory>/filepath/foo .但是,请注意,这些不会忽略例如<.gitignore_directory>/filepath/foo中的文件。

Since ** matches directories, it can solve the above problem like so: **/foo/ .由于**匹配目录,它可以像这样解决上述问题: **/foo/ Even though there is a non-whitespace character after the / , this will ignore all directories and subdirectories named foo , because **/ matches all filepaths.即使/之后有一个非空白字符,这也会忽略所有名为foo的目录和子目录,因为**/匹配所有文件路径。

  • **/foo/? Ignores all named files inside any directory foo .忽略任何目录foo中的所有命名文件。
  • foo/**/bar.txt Ignores every file named bar.txt at any depth inside a folder called foo , where foo is in the <.gitignore_directory> . foo/**/bar.txt忽略名为foo的文件夹中任意深度的每个名为bar.txt的文件,其中foo位于<.gitignore_directory>中。
  • **/foo/** Ignores everything inside every directory foo , but does not ignore the directory itself , and therefore I can unignore a select few files inside it! **/foo/**忽略每个目录foo的所有内容,但不忽略目录本身,因此我可以取消忽略其中的 select 几个文件!

Yay.耶。 My question is answered - almost.我的问题得到了回答——几乎。

Regarding SubSubfolder B0a:关于子子文件夹 B0a:

For the entry in my.gitignore to ignore SubSubfolder B0a , I actually had something slightly different from what I asked.对于 my.gitignore 中的条目忽略 SubSubfolder B0a ,我实际上有一些与我所要求的略有不同的东西。 In my actual project, B0a is called .generated_files .在我的实际项目中, B0a被称为.generated_files I was not entirely sure what git would think of a.gitignore entry starting with a dot, so I had prefixed it with a slash, like so: /.generated_files/ .我不完全确定 git 会如何看待以点开头的 .gitignore 条目,所以我在它前面加上了一个斜杠,如下所示: /.generated_files/ (I forgot about this when I wrote the question.) As I have now learnt, this caused git to expect it only in the root directory, and therefore miss it. (我在写问题时忘记了这一点。)正如我现在所知,这导致 git 只期望它在根目录中,因此错过了它。 I also learnt that git does not care in the slightest if an entry begins with a .我还了解到,如果条目以. . .


Final notes最后的笔记

Although It was not causing a problem in my case, I also discovered that an entry in a.gitignore file will match both files and folders.尽管在我的情况下它没有引起问题,但我还发现 .gitignore 文件中的条目将同时匹配文件和文件夹。 So if you had a file named foo and a folder named foo, putting foo in the.gitignore would cause them both to be ignored.因此,如果您有一个名为 foo 的文件一个名为 foo 的文件夹,将foo放入 .gitignore 会导致它们都被忽略。

Hopefully this answer was helpful, I'm afraid it is so long that reading the official documentation might actually be easier to understand.希望这个答案对您有所帮助,恐怕阅读官方文档可能会更容易理解。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM