git clean过滤器在git diff结果中显示差异。

3

我设置了一个干净的筛选器以应用uncrustify自动格式化。相应的smudge筛选器什么也不做,只是调用cat

[filter "autoformat"]
        clean = uncrustify -c ~/tmp/autoformat/uncrustify.cfg --replace
        smudge = cat

我的问题是,当我检出例如master时,git说我的工作树与提交不同,显示的差异是干净过滤器的作用。
似乎清洁过滤器是在diff之前应用的。这是正确的吗?是否可以禁用它?这是一个好主意吗?
我想要的解决方案是将自动格式化应用于暂存区域,即仅对已暂存的块进行操作。清洁过滤器不是一个合适的解决方案吗?
使用未遵循我的uncrustify配置的代码规范的主提交,checkout -f HEAD^后跟checkout master -f会显示差异。这既令人困惑又繁琐(git拒绝检出其他内容,以防止丢失更改)。
1个回答

7
似乎在diff之前应用了clean filter。这是正确的吗?
是的。在某些情况下,它必须是这样的。例如,考虑如果smudge filter由“双倍每个字符”组成,而clean filter由“删除双倍”组成——或者如果smudge filter由“翻译为一些替代字符集”,而clean filter将其翻译回来。
用于比较工作树与实际提交的git diff必须在提交内容上运行smudge过滤器或在工作树内容上运行clean过滤器。或者它甚至可以同时运行两个过滤器,并将输出写入临时文件。(我很确定我曾经测试过这个,很久以前,发现Git使用的方法是运行clean filter,而不是smudge filter。但是请参见Cyker's comment,该评论建议运行两个过滤器,然后对smudged结果进行差异比较。)

这个能否禁用?这是一个好主意吗?

请参见上文,最多你可能有一个“仅运行污点过滤器”的选项(但实际上没有)。

请注意,按照定义,索引中的内容已经是干净的。清理发生在从工作树到索引的转换时;污点发生在从索引到工作树的转换时。

现有提交是严格只读的,从提交中提取到索引不会进行任何更改。因此,虽然索引内容按定义是干净的,但如果干净过滤器本身发生了变化,则它们可能与通过重新运行过滤器获得的内容不匹配。

我想要的解决方案是将自动格式应用于暂存区,即仅对已暂存的块进行操作。清理过滤器是否是适当的解决方案?

这并不像你想象的那样起作用。

运行 git add 不会将差异块应用于索引副本:运行 git add 将整个工作树文件复制到索引中。整个文件都会被清理。

运行git add -p并不会实际将差异块应用于索引副本,因为它根本无法这样做。相反,git add -p将索引副本提取到临时文件中,将差异块应用于临时文件,然后将整个带有应用程序块的临时文件复制到索引中,并通过清理过滤器运行该文件。再次进行整个清理 - 只是“整个清理”是通过修补弄脏的索引副本构建的临时文件。

换句话说,每个文件的索引副本都是一个独立的实体,与HEAD提交副本和工作树副本无关。git checkout时,Git仅通过直接将文件的提交副本复制到索引中(无更改,无过滤器)来开始,然后将文件的索引副本复制到工作树中(弄脏过滤器)。在git add时间,Git在工作树文件上运行清理过滤器(或修补结果),并将其塞入索引。1


1从技术上讲,索引并不持有文件本身,而是它们的内容哈希值。添加文件的过程包括将文件写入存储库!生成的blob对象的哈希ID放入索引中。如果索引是唯一使用该blob的地方(如果该blob与某个已提交的blob匹配,则安全免受Grim Collector的影响),则索引条目会阻止该blob被垃圾回收。


你确定 git diff 运行的是 clean 而不是 smudge 过滤器吗?看起来两个过滤器都在运行,但是差异结果是使用 smudge 过滤器生成的。Git 版本为 2.24.1(最新版)。 - Cyker
@Cyker:我完全不确定。我曾经花了一些时间阅读源代码,它非常复杂,并且似乎在多年的时间里经历了许多修订。我想我曾经在Git 1.9或2.2左右的时候测试过它。所以它可能已经改变了(并且可能会再次改变:文档并没有真正承诺这一点)。我怀疑Git-LFS可能已经推动了“使用污点过滤器”的方向。 - torek

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