在《Git原理-探寻日志记录》中我们看到,git是可以判断文件是否被改了个名字:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
git log --name-status
commit dc91f7f38cdb3c8876a7bfd38020e2a64f33015d (HEAD -> master, origin/master)
Author: ticktechman <ticktechman@gmail.com>
Date: 2024-06-12 19:28:09 +0800
delete conn.c
D src/conn.c
commit 0909df98f750118bebab6fb325ede8a836b6b7c1
Author: ticktechman <ticktechman@gmail.com>
Date: 2024-06-12 19:27:38 +0800
rename demo.c to conn.c
R100 src/demo.c src/conn.c
|
git log --name-status
commit dc91f7f38cdb3c8876a7bfd38020e2a64f33015d (HEAD -> master, origin/master)
Author: ticktechman <ticktechman@gmail.com>
Date: 2024-06-12 19:28:09 +0800
delete conn.c
D src/conn.c
commit 0909df98f750118bebab6fb325ede8a836b6b7c1
Author: ticktechman <ticktechman@gmail.com>
Date: 2024-06-12 19:27:38 +0800
rename demo.c to conn.c
R100 src/demo.c src/conn.c
这里最后一行中的R100
表示这是一个rename的改动,100表示100%相同。由此我们有了下面两个疑问:
- Git是如何判断是一个rename的改动的呢?
- 除了100%相同,是否还有90%或者80%相同呢?
判断依据
- 文件内容相同,即:对应的对象ID一样,文件名不同(可能在同一个目录或者不同目录)
- 文件内容不同,但相似度超过50%(默认),且文件名不同
相似度计算
从上面的判断依据中,我们可以看到有一个两个文件相似度的值,这个值是如何来的呢?既然是要判断相似度,那就免不了要读取文件内容,git会将两个文件中的内容分割成64Bytes大小的块,然后分块计算HASH值,HASH值相同则认为文件内容相同,相似度就等于相同部分的大小与文件总大小的比值。计算HASH的时候会忽略换行符和回车符,因为他们对文件相似度没有贡献。公式如下:
1
2
3
4
5
6
|
// diffcore-rename.c
// max_size为需要对比的两个文件大小取最大值
// src_copied就是两个文件相同部分的大小
// score就是计算出来的分值,相似度百分比 = score / MAX_SCORE
#define MAX_SCORE 60000.0
score = (int)(src_copied * MAX_SCORE / max_size);
|
// diffcore-rename.c
// max_size为需要对比的两个文件大小取最大值
// src_copied就是两个文件相同部分的大小
// score就是计算出来的分值,相似度百分比 = score / MAX_SCORE
#define MAX_SCORE 60000.0
score = (int)(src_copied * MAX_SCORE / max_size);
选哪些文件进行对比
- 上一个版本没有,当前版本有
- 上一个版本有,这个版本没有
- 剔除文件内容相同的文件(对象ID一样,文件名不同),因为这些文件可以直接判断为rename,无需计算相似度。