为什么 git 不能合并重命名和修改?

Why git can't merge renames with modifications?

我遇到了无法解释的合并行为。以下脚本初始化存储库并创建一些带有修改和重命名的分支。

$ git init
$ emacs file.txt
$ cat file.txt 
1
2
3
4
$ git add file.txt && git ci -m "initial"
$ git branch A && git branch B && git branch C && git branch D

$ git checkout A
$ emacs file.txt
$ cat file.txt
1
added after 1
2
3
4
$ git add file.txt && git commit -m "edited in A"

$ git checkout B
$ emacs file.txt
$ cat file.txt
1
2
3
added after 3
4
$ git add -u && git commit -m "edited in B"

$ git checkout C
$ git mv file.txt f.txt
$ git commit -m "renamed in C"

$ git checkout D
$ git mv file.txt f.txt
$ git commit -m "renamed in D"
$ emacs f.txt
$ cat f.txt
1
2
3
added after 3
4
$ git add -u && git commit -m "edited in D (after rename)"

有那个:

  1. 如果您尝试 'git checkout B && git merge A' 合并将在没有任何冲突的情况下完成。
  2. 如果您尝试 'git checkout C && git merge A' 合并将在没有任何冲突的情况下完成。
  3. 如果你尝试 'git checkout D && git merge A' 你会得到:

CONFLICT (rename/delete): f.txt deleted in A and renamed in HEAD. Version HEAD of f.txt left in tree.

案例 2 git 检测到分支 C 中的重命名,因此成功合并了分支 A 中的更改。

在案例 3 中,我无法理解为什么 git 即使在成功检测到重命名后也无法合并来自两个分支的更改。

$ git --version
git version 1.9.3 (Apple Git-50)

其实是对的:

If I recall the default is that 80% of the file content matches, but I would never expect this to work reasonably with such tiny files.

我刚刚用一个有 100 行(而不是 4 行)的文件测试了相同的过程,并且 Git 正确识别了所有更改而没有冲突,所以我最终得到了一个文件 f.txt 和两行添加。

原因是 Git 根本不跟踪文件重命名,甚至 更改 。它跟踪内容,git mv 只是 git rmgit add 的组合(尽管是 similar/identical)文件。因此,为了识别文件重命名以用于合并策略或其他视觉辅助(例如 git status 中),它会查看内容的相似性,然后根据两个文件的相似性进行判断。如果它们非常相似,并且在添加另一个文件时删除了一个文件,那么 Git 会将其识别为重命名(复制检测的工作方式相同)。现在,文件的内容越多,Git 就越容易识别相同的内容并因此重命名文件。