为什么 'git status' 忽略了 .gitattributes 的 clean 过滤器?

13
我有一个.gitattributes 清洁过滤器,可以在提交之前从文件中删除所有注释。
$ cat .git/config
[filter "cleancomments"]
    clean = "grep -v '^#'"

$ cat .gitattributes
*   filter=cleancomments

我有一个名为“test”的文件,其内容如下(已提交到代码库):

This is a file with random content

现在我对“test”进行了修改并添加了注释:
This is a file with random content
# and some comments
# like this

git status现在告诉我:

modified:   test

但是git diff为空(这是应该的)。

对我来说不是很清楚为什么git status不使用过滤器来决定文件是否被修改,但我想这就是它的实现方式。

真正让我感到神秘的是以下内容:

如果我这样做:

git add test

突然间,文件“test”不再被标记为已修改,并且它也不出现在git索引中。这是为什么?

你为什么想要从文件中删除所有注释呢?只是好奇,显然你有你的原因,但实际上很少有情况需要这样做。 - Sietse van der Molen
1
这只是我真正所做的事情的一个非常简化的例子 :-) 我已经测试过我的示例,并且它按照描述的方式工作。真实场景涉及从.po文件中删除注释,因为它们几乎从来没有用处,总是可以自动重新生成,并且在多个开发人员编辑同一文件时会引起许多冲突。 - Omar Kohl
1个回答

8

git add 命令将文件加入索引,1但需要先运行必要的过滤器。

索引包含文件在磁盘上的名称和“真实名称”(其Git哈希作为“blob”),以及目录中的stat值和一对Git哈希值(原始和已过滤),以及其他所需的一些信息。一旦添加完成,git status 通过索引数据可以判断该文件现在在索引中“最新”,并且索引本身是最新的,因为Blob的哈希值与HEAD提交的哈希值相匹配。

如果继续修改文件,则某些关键的stat数据会更改,导致Git认为索引已过期,此时git status 将认为需要再次使用 git add 命令。2

这里的一般思路似乎是,git status 不会写任何东西(甚至不是索引)。如果git update-index --refresh 可以更新工作目录/清理条目配对,那就太好了,但似乎不行。


1 更准确地说,git add 计算哈希值,并在仅当对象不存在时将对象添加到存储库中。哈希值现在已知,可以根据需要存储在索引中。哈希值在过滤和哈希之后才能确定,即git status 不知道哈希值。

2 如果使用类似 --assume-unchanged 和/或 core.ignorestat 的选项,则会出现更多细微差别。


1
有没有办法让 'git status' 花更多的时间并考虑过滤/清理?或者有没有其他方法可以避免文件被标记为 'modified' 而不必 'git add' 它? - Omar Kohl
似乎不是这样。但是,git add -u . 将添加所有需要清除“修改”状态的内容(如果它们“真正改变”,当然也会将它们添加)。顺便说一句,我测试了一下,只修改日期并不会导致它再次出现,即我错了,不能简单地使用 touch test,所以现在我对 git status 检查的 stat 信息更加不确定了。(我之前曾经简要浏览过代码,我知道它大量使用 lstat()...) - torek

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