git相似度指数如何计算?

时间:2018-07-05 07:27:41

标签: git

我是git的新手,有些东西我不清楚。 git内部如何知道文件是新文件还是修改后的文件?
由于git不跟踪文件,而是跟踪blob。这与相似性指标有关吗?

我也遇到了问题,当移动文件并对其进行修改时,有时git会将其识别为重命名的文件,有时则将其识别为新文件。
如果文件较小,它将识别为新文件并删除。

我该如何“欺骗” git,以将这种情况标记为已移动文件,而不是新的和已删除的文件(不进行两次不同的提交-一个用于移动,另一个用于更改)?

1 个答案:

答案 0 :(得分:3)

有关相似性指数计算的详细讨论,请参见Trying to understand `git diff` and `git mv` rename detection mechanism。不过,在执行此操作之前,请注意以下几点:

  • 每个提交都是完整的独立快照。快照是包含更多文件和/或更多目录的命名文件和命名目录(或文件夹)的树。 1 给定提交和完整路径名path/to/file.ext,Git可以提取快照。适当的 blob内容(如Git所称),它们将命名文件保存在该提交中,而无需查看任何其他提交。

  • 每当您向Git询问快照以进行比较时,都必须给Git两次提交 次提交的哈希ID,或名称或其他可解析为哈希ID的字符串,即两个快照。实际上,Git一次提取一个快照,然后比较生成的文件树。 (某些命令,例如git showgit log -p,通过查看子提交来找出父哈希,然后按该顺序比较父子。)

因此,Git始终在查看一棵树木:左侧(a/)的树可能包含README.txt,而右侧({{ 1}})还包含b/,而左侧包含README.txt,右侧没有具有doc.txt。左侧的提交没有具有doc.txt,右侧的 具有documentation.rst

Git此时要做的是匹配文件。路径名完全相同的两个文件(例如此处的两个documentation.rst文件)必须是“相同”文件,因此Git会查看左侧README.txt的内容和右侧的内容侧README.txt产生两者的差异。匹配此类事物的技术术语是确定文件的 identity 。 (这在哲学上是一项壮举。有关讨论,请参见The Ship of Thesus。与哲学论点不同,在计算中,我们得到了明确而具体的答案。好吧,直到我们介绍类似Git的README.txt或至少-B中的 break 值!)

在没有可匹配名称的地方,例如git diffdoc.txt,Git会在每个这样的文件对之间计算相似性索引,比较左边-side的文件(此时,到达右侧时似乎已被删除)到右侧的文件(现在看来是新文件)。好吧,就是说,如果您已打开重命名检测,则Git会计算该索引 。在Git 2.9之前的版本中,重命名检测默认情况下处于关闭状态,而在后续版本中,默认情况下处于启用状态。 Git在这里进行最佳匹配,然后将文件配对:如果documentation.rstdoc.txt足够相似,那么为什么这些文件也必须是“相同”文件,即使它们具有不同的名称。 / p>

在Git甚至为这种相似性的索引技巧而烦恼之前,它会先通过查找100%相同的文件。由于Git存储内容的方式,这比计算相似性索引要容易得多。任何此类完全匹配都会被配对,并从可能配对的文件列表中删除,仅在Git内部称为重命名队列的上保留完全匹配的文件。因此,仅对名称在重命名队列中的文件执行相似性索引计算。这种计算比较昂贵(文件数为O(n 2 )),因此对于快速documentation.rstgit show,提交是个好主意先重命名,然后再更改内容。


1 这是内部的表示形式,从外部看,您甚至不知道也不关心Git将每个目录存储为树条目。特别是,Git喜欢声称它仅存储文件(不存储目录),并且Git使其难以存储空目录。为此,Git必须具有一个empty tree-它确实是 ,但是如果您尝试使用它,则会得到怪异的效果。