git diff -M 如何工作?

How does git diff -M work?

我目前正在尝试了解 git diff -M<limit> 的工作原理。

我发现,git diff 通过计算相似度分数来检查两个文件(例如修订版 1 中的 fileA,修订版 2 中的 fileC)的相似程度。如果相似度得分 >= limitfileA 已重命名为 fileC,这可能已被修改(如果得分 < 100%)。

然后我问自己,如果目录中有更多具有相同 sha1-hash 的文件怎么办? git 如何知道哪个是重命名(和更改)的版本?

为了找出答案,我尝试了以下方法:

首先,我创建了两个包含 7 行的文件 ("a"、"b"、"c"、"d"、"e"、"f" , "g")

vi fileA
vi fileB

然后我将它们添加到存储库并提交:

git add fileA fileB
git commit -m "Added fileA and fileB"

    [master ffc8964] Added fileA and fileB
     2 files changed, 6 insertions(+)
     create mode 100644 tests/fileA
     create mode 100644 tests/fileB

接下来,我使用 git mvfileA 重命名为 fileC,并删除了 fileBfileC 中的第一行。之后我提交了更改

git mv fileA fileC
vi fileB
vi fileC
git commit -a -m "Renamed and changed files"

    [master 57ff82a] Renamed and changed filed
     2 files changed, 2 deletions(-)
     rename tests/{fileA => fileC} (85%)

fileBfileC 现在看起来像这样:

b
c
d
e
f
g

我现在期望的是 fileBfileC 的校验和相等:

git hash-object fileB fileC
    9fbb6235d2d7eb798268d4537acebea297321241
    9fbb6235d2d7eb798268d4537acebea297321241

确实是:-)

那么 git diff 现在应该如何知道重命名的文件是什么?由于 fileC 已更改,commit 生成了一个新的 blob,并且 fileCfileA 的校验和也不同(很明显)。

我试过了:

git diff -M80% HEAD master~1

然而,输出让我感到困惑:-(

diff --git a/tests/fileC b/tests/fileA
similarity index 85%
rename from tests/fileC
rename to tests/fileA
index 9fbb623..f9d9a01 100644
--- a/tests/fileC
+++ b/tests/fileA
@@ -1,3 +1,4 @@
+a
 b
 c
 d
diff --git a/tests/fileB b/tests/fileB
index 9fbb623..f9d9a01 100644
--- a/tests/fileB
+++ b/tests/fileB
@@ -1,3 +1,4 @@
+a
 b
 c
 d

显然 git diff 发现 fileA 已重命名为 fileC

但是怎么办? git 是否保存了 fileAfileC 之间的某种联系?

没有保存这样的连接。当删除一个文件并添加另一个文件时,可以检测到重命名。 Git 看到 fileC 是新添加的,并检查了所有已删除的文件,看是否可能是重命名。在这里,唯一删除的文件是 fileA,因此检查速度相当快。

注意:它只需要遍历已删除的文件,否则你不会重命名,你会得到一个副本。副本也可以被检测到,其工作方式大致相同,但它们由单独的选项 (-C) 涵盖。