[英]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 B1a
和B0a
中的所有文件。 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.我会尽力解释我认为发生了什么,以及如何避免它。
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
解决了问题。
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 !富 |
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?那么,如何才能忽略子目录中的文件呢?
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.我的问题得到了回答——几乎。
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 .
我还了解到,如果条目以.
. .
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.