试图了解`git diff`和`git mv`重命名检测机制

Chr*_*chs 3 git github git-diff git-status git-mv

这是我之前提出的另一个问题的后续措施。

正在编辑之前,最初创建的文件something被重命名为somethingelse可观察到这里

git mv something somethingelse
Run Code Online (Sandbox Code Playgroud)

该文件somethingelse然后得到重命名回something第二VIM编辑之前:

git mv somethingelse something
Run Code Online (Sandbox Code Playgroud)

基本上在代码的以下部分中

git mv something somethingelse
Run Code Online (Sandbox Code Playgroud)

如果在这一点上我添加abc到代码中,我们将最终得到:

First line of code. abc
Run Code Online (Sandbox Code Playgroud)

我认为这是第1行增加了4个字节,而这又将在此结束:

On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   something
        deleted:    somethingelse
Run Code Online (Sandbox Code Playgroud)

然后,如果我们添加换行符并在第三行中键入abc(也应为4个字节,如果有错,请更正我):

First line of code.

abc
Run Code Online (Sandbox Code Playgroud)

突然,Git会检测到重命名(包括编辑):

On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        renamed:    somethingelse -> something
Run Code Online (Sandbox Code Playgroud)

@torek给出的一个很好的答案/评论一定程度上解释了这一点,同时考虑了git diff重命名检测的阈值git status

因为在两种情况下我们都添加了4个字节,所以Git的行为不应该相同,但是以不同的方式还是换行符与此有关?

tor*_*rek 5

据我所知,Git的“相似性指数”计算未从源代码中以diffcore-delta.c开头记录在文件中

为了计算两个文件S(源)和D(目标)的相似性索引,Git:

  • 读取两个文件
  • 计算文件S所有块的哈希表
  • 计算文件D所有块的第二个哈希表

这两个哈希表中的条目只是该哈希值(加上如下所述的块的长度)的实例的出现次数。

文件块的哈希值通过以下方式计算:

  • 从当前文件偏移量开始(最初为零)
  • 读取64个字节或直到'\n'字符为止,以先到者为准
  • 如果文件声称是文本,并且在'\r'之前有'\n',则丢弃'\r'
  • 使用链接文件中显示的算法对所得的最多64个字节的字符串进行哈希处理

现在有两个哈希表小号d,每一个可能的散列ħ 出现Ñ š小号Ñ dd(或者可以是零,虽然代码跳过右在两个零的散列值)。如果D中的出现次数小于或等于S中的出现次数,即n D?n S-然后D “从S中复制” n D次。如果D中出现的次数超过了D中出现的次数小号(包括当在数小号是零),则d具有一个“加载字面” Ñ d - N的š散列块的出现,和d也复制所有Ñ š原始事件为好。

每个散列的块都保留其输入字节数,这些字节数乘以副本数或“块”的添加数即可得出复制或添加的字节数。(删除,其中D缺少S中存在的项目,在这里仅具有间接作用:字节复制和添加计数变小,但是Git本身并不专门对删除进行计数。)

在中计算的这两个值(src_copiedliteral_addeddiffcore_count_changes移交给in中的函数estimate_similaritydiffcore-rename.c。它完全忽略了literal_added计数(此计数用于确定如何构建packfile增量,但不用于重命名评分)。相反,只有src_copied数字很​​重要:

score = (int)(src_copied * MAX_SCORE / max_size);
Run Code Online (Sandbox Code Playgroud)

其中max_size两个输入文件SD中较大的一个的大小(以字节为单位)。

请注意,有一个较早的计算:

max_size = ((src->size > dst->size) ? src->size : dst->size);
base_size = ((src->size < dst->size) ? src->size : dst->size);
delta_size = max_size - base_size;
Run Code Online (Sandbox Code Playgroud)

并且如果两个文件的大小已更改 “太大”:

if (max_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE)
        return 0;
Run Code Online (Sandbox Code Playgroud)

我们甚至从来没有进入过diffcore-delta.c对它们进行哈希处理的代码。这minimum_score-M或的参数--find-renames,转换为小数位数。 MAX_SCORE60000.0(type double),因此minimum_score当您使用默认值时-M50%,默认值是30000(一半为60000)。但是,除了在CR之前进食CR的情况外,此特定的快捷方式不应影响更昂贵的相似度计算的结果。

同样,git status始终使用默认值。没有旋钮可以更改阈值(也没有更改重命名查找队列中允许的文件数量)。如果有代码,请在此处设置rename_scorediff选项的字段。