试图理解'git diff'和'git mv'重命名检测机制

试图理解'git diff'和'git mv'重命名检测机制,git,github,git-diff,git-status,git-mv,Git,Github,Git Diff,Git Status,Git Mv,这是一个后续行动 在编辑之前,最初创建的文件something将重命名为somethingelse,可以看到: 文件somethingelse然后在第二次vim编辑之前进入something: git mv somethingelse something 基本上如下: #如果在第一行添加了内容,Git将无法检测到重命名 #但是,如果您改为创建2个换行符并用新代码填充第3行, #无论出于何种原因,都会检测到重命名 printf“\n命令:vim某物\n\n” 维姆什么的 如果此时我在代码中添加

这是一个后续行动

在编辑之前,最初创建的文件
something
将重命名为
somethingelse
,可以看到:

文件
somethingelse
然后在第二次vim编辑之前进入
something

git mv somethingelse something
基本上如下:

#如果在第一行添加了内容,Git将无法检测到重命名
#但是,如果您改为创建2个换行符并用新代码填充第3行,
#无论出于何种原因,都会检测到重命名
printf“\n命令:vim某物\n\n”
维姆什么的
如果此时我在代码中添加
abc
,我们将得到:

First line of code. abc
我认为第1行增加了4个字节,结果是:

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

        new file:   something
        deleted:    somethingelse
Git会突然检测到重命名(包括编辑):

分支主机上的

要提交的更改:
(使用“git重置磁头…”取消分级)
重命名:somethingelse->something
@torek给出的一个很好的回答/评论在一定程度上解释了这一点,并考虑了
git-diff
rename-detection-treshold的
git-status

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

据我所知,Git的“相似性指数”计算并没有记录在中以外的任何地方

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

  • 读取两个文件
  • 计算所有文件块的哈希表
  • 计算文件D的所有块的第二个哈希表
这两个哈希表中的条目只是该哈希值实例的出现次数(加上块的长度,如下所述)

文件块的哈希值由以下公式计算:

  • 从当前文件偏移量开始(最初为零)
  • 读取64字节或直到
    '\n'
    字符,以先到者为准
  • 如果文件声明为文本,并且在
    '\n'
    之前有一个
    '\r'
    ,则丢弃
    '\r'
  • 使用链接文件中显示的算法对结果字符串(最多64个字节)进行散列
现在S和D都有了哈希表,每个可能的哈希hi在S中出现nS次,在D中出现nD次(两者都可以是零,尽管代码跳过了两个零哈希值)。如果D中的出现次数小于或等于S-i中的出现次数,即nD≤ nS然后D“从S”复制第n次。如果D中的出现次数超过S中的出现次数(包括S中的出现次数为零时),则D具有散列块的nD-nS出现次数的“文字相加”,并且D还复制所有nS原始出现次数

每个散列块保留其输入字节数,这些字节数乘以“块”的副本数或添加数,得到复制或添加的字节数。(删除,其中D缺少S中存在的项,在这里只有间接影响:字节复制和添加计数变小,但Git并不专门计算删除本身。)

diffcore\u count\u changes
中计算的这两个值(
src\u copied
literal\u added
)将移交给。它完全忽略添加的
literal_
计数(此计数用于决定如何构建packfile delta,但不用于重命名评分)。相反,只有复制的
src\u
编号才重要:

score = (int)(src_copied * MAX_SCORE / max_size);
其中
max_size
是两个输入文件S和D中较大者的大小(以字节为单位)

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

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;
max_size=((src->size>dst->size)?src->size:dst->size);
基本尺寸=((src->sizesize)?src->size:dst->size);
增量大小=最大大小-基本大小;
如果两个文件的大小变化“太大”:

if(最大尺寸*(最大尺寸分数-最小尺寸分数)
我们甚至从来没有进入
diffcore delta.c
代码来散列它们。
最低评分
这里是
-M
-find-renames
的参数,转换为缩放数字<代码>最大得分
60000.0
(键入
双精度
),因此当您使用默认的
-M50%
时,默认的
最小得分
为30000(60000的一半)。但是,除了LF进食前的CR情况外,这种特殊的快捷方式不应影响更昂贵的相似性计算的结果


同样,
git status
始终使用默认值。没有旋钮来更改阈值(也没有重命名查找队列中允许的文件数)。如果存在代码,则设置差异选项的
rename\u score
字段。

为什么修改文件以添加
abc
最终会报告为新文件和使用其他名称删除的文件?您是否也重命名了该文件?您不断地说和提到“重命名”,但您的问题实际上并不表明您正在重命名文件。请明确说明你在做什么。文件在编辑之前会被重命名,这是在第一次发生,但问题中没有提到。如果有先前的信息(即使这是在你发布后续信息的问题中),你需要在这里发布。堆栈溢出不是一个线程化的讨论板,每个问题都需要独立解决。对于小文件,重命名检测总是很脆弱的。
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        renamed:    somethingelse -> something
score = (int)(src_copied * MAX_SCORE / max_size);
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;
if (max_size * (MAX_SCORE-minimum_score) < delta_size * MAX_SCORE)
        return 0;