【问题标题】:How do I whitelist a directory in .gitignore and blacklist a file inside it in ~/.gitignore?如何将 .gitignore 中的目录列入白名单并将 ~/.gitignore 中的文件列入黑名单?
【发布时间】:2021-01-27 06:18:33
【问题描述】:

关于这个话题有很多问题,但没有一个涉及~/.gitignore


我有一个奇怪的项目,它有一个顶级项目目录——称之为project/——充满了垃圾,但至少有一个重要的子目录——比如project/feedme/。我想.gitignore project/ 中的所有内容,但不是.gitignore project/feedme/ 及其内容。使用否定模式很容易:

project$ cat .gitignore
/*
!/feedme/

我有一个文件project/feedme/.exrc,我想忽略它。作为vi 用户,我经常使用.exrc 文件进行本地编辑器设置,因此我的~/.gitconfig 中有一个条目(由core.excludesFile Git 设置指定):

project$ cat ~/.gitignore
.exrc

不幸的是git 似乎不想重新认识.exrc

project$ git status -s
?? feedme/
project$ git add feedme/
project$ git status -s
A  feedme/.exrc

为什么 Git 不忽略 project/feedme/.exrc


编辑:根据prosoitos' answer,这部分是错误的。请参阅此问题末尾的我的编辑,因为它尚未得到完全回答。

为什么我认为这应该有效?手册页 gitignore(5) 是这样说的:

gitignore 文件中的每一行都指定一个模式。决定时 是否忽略路径,Git 通常会检查 gitignore 模式 多个来源,具有以下优先顺序,从最高 到最低(在一个优先级内,最后一个匹配模式 决定结果):

  • […]

  • 模式从一个 .gitignore 文件中读取 路径,或在任何父目录中,具有更高级别的模式 文件(直到工作树的顶层)被覆盖 那些在较低级别的文件下到包含
    的目录 文件。 […]

  • […]

  • 从配置变量指定的文件中读取的模式 core.excludesFile

由于来自~/.gitignore 的模式是最后读取的,我原以为.exrc 最终会被忽略而不管本地.gitgnores。

一种可能的解释是(再次来自 gitignore(5) 手册页,强调我的)

这是 如果该文件的父目录无法重新包含该文件 文件被排除

也适用于它的双重形式(不是在手册页中)

这是 如果该文件的父目录不能排除该文件 文件被重新包含

如果是这样的话,我会认为这是一个错误;至少应该在文档中明确说明。


P.S.:我的~/.gitignore在正常情况下工作,所以问题不存在。


编辑

Prosoitos 是对的,全局~/.gitignore 被读取首先,所以project/feedme/ 子目录被重新包含之后 .exrcs 被全局忽略。但是我仍然面临另一个奇怪的问题。

根据我现在对文档的理解,将.exrc 放在~/.gitignore 的最后一行相当于(如果project/.git/info/excludes 为空)将.exrc 放在project/.gitignore 的第一行。但是,如果我这样做,这次project/feedme/.exrc 将被忽略!

project$ cat ~/.gitignore
project$ cat .gitignore
.exrc
/*
!/feedme/
project$ git ls-files --other --ignored --exclude-standard
.gitignore
feedme/.exrc

这里发生了什么?

【问题讨论】:

  • 似乎您已经回答了自己的问题“如果排除了该文件的父目录,则无法重新包含该文件。” .gitignore 的手册页中已经非常清楚地说明了这一点 - 或者您是否正在寻找另一种清晰度?从概念上讲,.exrc 文件听起来不属于该文件夹,或者至少可以为该文件夹的内容构造特定的排除模式。
  • @zrrbite 我正在尝试排除 feedme/.exrc 文件,而不是像上面发生的那样重新包含它。至于本地.exrc 文件,它们指定本地编辑器设置并且很少(阅读:从不)需要提交,这就是我在~/.gitignore 中忽略它们的原因。
  • 啊,是的,抱歉,来晚了!反过来:) 但我认为这同样适用。我现在明白你的意思了,文档中没有明确说明从被忽略的文件夹中重新添加要忽略的内容的“反向”场景。
  • @zrrbite 这里也已经很晚了……当我真的应该处理那个 Git 存储库的内容时,我花了太多时间思考这些极端案例!我同意“反过来”适用,只是它看起来像是我永远不会使用的东西。如果我真的想防止子目录的所有内容被排除在外,我只需在内部添加一个 !** 的另一个 .gitignore

标签: git configuration gitignore home-directory


【解决方案1】:

据我现在了解文档,将.exrc 放在~/.gitignore 的最后一行相当于(如果project/.git/info/excludes 为空)将.exrc 放在project/.gitignore 的第一行。
但是,如果我这样做,这次project/feedme/.exrc 将被忽略!

project$ cat ~/.gitignore
project$ cat .gitignore
.exrc
/*
!/feedme/
project$ git ls-files --other --ignored --exclude-standard
.gitignore
feedme/.exrc

您已将文件夹 /feedme/ 从忽略规则中排除,但未排除其内容。
您需要该文件中的!/feedme/.exrc 才能被忽略。

【讨论】:

    【解决方案2】:

    因为来自 ~/.gitignore 的模式是最后读取的 [...]

    没有。这是你弄错的地方。您引用的 Git 手册部分:

    Git 通常会检查来自多个来源的 gitignore 模式,优先顺序如下,从最高到最低 [...]

    意味着全局 .gitignore 会被本地覆盖,而不是相反。

    因此,您本地的 .gitignore 中的 !/feedme/ 会覆盖您的全局 .exrc 中的 .exrc。因此,feedme/.exrc 未被排除。

    一个简单的解决方案是在本地的.gitignore 文件中添加.exrc,并确保它位于!/feedme/ 行的下方,因为:

    (在一个优先级内,最后匹配的模式决定结果)


    注意:

    诚然,“优先顺序”的表达方式可能会令人困惑。

    在这里,“更高的优先级”意味着它“比”更重要(因此它会覆盖)。

    您似乎从运算符优先级的意义上理解它,其中“更高优先级”意味着“之前执行”,这将导致相反的结果。因此混乱。


    编辑问题后编辑:

    既然你已经对你的情况进行了更正,我认为你是对的。

    我复制了你的情况,然后跑了:

    git check-ignore -v feedme/.exrc
    

    我得到:

    .gitignore:1:.exrc  feedme/.exrc
    

    表明.exrc 的排除没有被!/feedme/ 否定。

    我尝试用谷歌搜索,但也找不到任何文档。

    【讨论】:

    • 你说得对,谢谢。但是,请参阅我编辑的帖子;奇怪的事情还在发生。
    猜你喜欢
    • 2015-03-29
    • 2021-02-21
    • 2011-10-18
    • 1970-01-01
    • 2012-10-06
    • 1970-01-01
    • 2021-12-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多