gitignore:忽略文件夹层次结构中除特定文件类型之外的所有文件

28

我想忽略一个文件夹及其子文件夹中的所有文件,但是除了特定类型的文件外(该文件可以在文件夹层次结构的任何位置):

示例:

/Test
/Test/unknown/folder/structure/below

现在我想忽略Test文件夹及其子文件夹中的所有文件,除了一个名为layout.css的特定css文件,例如:

/Test/layout.css
/Test/fileto.ignore
/Test/another/folder/ig.nore
/Test/in/a/unknown/folder/layout.css
/Test/in/a/unknown/folder/ignore.me

.gitignore应该忽略哪些内容

/Test/fileto.ignore
/Test/another/folder/ig.nore
/Test/in/a/unknown/folder/ignore.me

我的 .gitignore 文件不起作用:

Test/
!layout.css

有什么建议吗?


你也尝试过换个顺序吗? - Jan Hudec
@Jan 是的,我做了 - 不幸的是没有成功。 - Jörg
请参见:https://dev59.com/AGMm5IYBdhLWcg3wKsrO#17821597,以获取一个集中的解决方案。 - Ben Martin
3个回答

30

我通过在Test/目录下放置一个名为.gitignore的文件并添加以下内容来使您的示例正常运行。

*
!*/
!.gitignore
!layout.css

1
David,感谢你的回答。由于我有很多这些Test文件夹分散在各处,所以我更喜欢一个“集中”的解决方案,而不是各种.gitignore文件。 - Jörg
@Jörg 很抱歉,我没有找到解决方法。你可能已经尝试过调整我的解决方案并将其用于顶级目录,通过在前两行添加“Test”(并删除第三行)。如果你这样做了,你会发现这并不能解决问题。希望有人能提供一个更完整的解决方案。 - David Alber
是的,我尝试了各种组合和您解决方案的一些变化,但正如您所说,它不起作用。无论如何,感谢您花费时间。 - Jörg

14

这是一个很老的问题,但由于我现在仍在苦恼这个问题,所以我想分享解决问题的实际方法。

事实上,在Git中无法像忽略文件一样提交空目录,但这个规则不适用于.gitignore

来自https://git-scm.com/docs/gitignore

尾随“/*”匹配内部的所有内容。例如,“abc / * ” 匹配相对于.gitignore文件位置的目录“abc”中的所有文件,并具有无限深度。

斜杠后跟两个连续的星号,然后是斜杠,匹配 零个或多个目录。例如,“a / ** / b”匹配“a / b”, “a / x / b”,“a / x / y / b”等。

** 匹配内部的所有内容 - 确实是所有的东西 - 文件和目录。

这让我们又想到了gitignore文档中的另一个点:

可选前缀“!”否定模式;任何匹配的文件 通过先前的模式排除将再次包含。 如果父目录被排除,则不可能重新包含文件。 Git不列出被排除的目录以提高性能 原因,因此包含在其中的文件的任何模式都没有效果, 无论它们在何处定义。对于以文字“!”开头的模式,在第一个反斜杠(“”)前放置反斜杠。

如果模式以斜杠结尾,则为了 下面的描述,但它只会找到与一个匹配项 目录。换句话说,foo /将匹配目录foo和路径 在其下面,但不会匹配常规文件或符号链接 foo(这与Git中pathspec的工作方式一致)。

现在,假设我们有以下目录结构:

/path/to/git/repo
|-- .gitignore
|-- /cache
    |-- somefile
    |-- README    
    |-- /dir
        |-- somefile2
        |-- README

我们希望忽略cache/目录下的所有文件,但是README文件除外。

如果我们像这样指定gitignore:

/cache/**
!README

Git会忽略除了/cache/README之外的所有内容。其他的README不会显示出来,因为它所在的目录/cache/dir已经被排除了,使用了/cache/**,而!README甚至都不适用于它。

为了解决这个问题,我们需要将gitignore指定为以下内容:

# Ignore everything inside cache/ dir
/cache/**
# Except for subdirectories(won't be commited anyway if there is no commited file inside)
!/cache/**/
# And except for README files
!README

3
令人惊讶的是,这是唯一一个真正回答了原问题的答案。 - Larry Kyrala
1
确认这对我有效。拥有!/cache/**/非常重要。(从https://dev59.com/AGMm5IYBdhLWcg3wKsrO#49496926来到这里) - Johnster

12

为了实现你的目标,你需要使用一些负面排除。基本思路是你需要排除任何你想要添加到git仓库中未被忽略的文件的每个父级目录。

所以,如果你想要将 /Test/in/a/unknown/folder/layout.css 添加到你的git仓库中,那么你就需要取消忽略 /Test/、/Test/in/、/Test/in/a/、/Test/in/a/unknown/ 以及 /Test/in/a/unknown/folder/。

然后,当你最终进入含有已忽略和未忽略文件的目录时,你需要按如下方式单独指定每个文件:

# Fille: .gitignore
!Test/
Test/*
!Test/layout.css
Test/fileto.ignore
!Test/another/
Test/another/*
!Test/another/folder/
Test/another/folder/*
!Test/in/
Test/in/*
!Test/in/a/
Test/in/a/*
!Test/in/a/unknown/
Test/in/a/unknown/*
!Test/in/a/unknown/folder/
Test/in/a/unknown/folder/ignore.me
!Test/in/a/unknown/folder/layout.css

所以当你运行 $ git add-all 时,你将看到你期望的结果:

$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

    new file:   .gitignore
    new file:   Test/in/a/unknown/folder/layout.css
    new file:   Test/layout.css

注意:您可以在http://lexsheehan.blogspot.com/2014/05/git-add-update.html找到关于为什么使用git add-all是将文件添加到git存储库的最佳方法的解释。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接