编辑:我现在相信我今天早上误读了这个问题,并且您的分支中只有一个修改过的文件,源自单一来源。在这种情况下,下面的描述是准确的,但告诉我们 Git 应该自己找到重命名的文件,只要它足够相似。如果没有,您可以将-X find-renames=<em>number</em> 参数添加并调整为git merge。您可能想先运行一些手动的git diffs,使用--find-renames=<em>number</em>(或更短的拼写,-M<em>number</em>)来找出哪些数字使 Git 将合并基数视为 --ours 更改为重命名。
如果您在自己的分支中有两个 修改过的文件,它们都来自一个单个 源文件,Git 的git merge 将无济于事。您必须自己合并此文件,可能使用git merge-file。有关说明,请参阅下面的最后一节。
git merge 有三个输入
这里的根本问题是 git merge 只查看三个提交。1 我们需要这些提交的名称,而 Git 对这些名称并不一致:有时它们是 --ours 和--theirs 用于两个分支提示提交,有时它们是 local 和 remote。我将使用 L,表示左侧或本地或 --ours,使用 R 表示右侧或远程或 --theirs。第三次提交在某些方面是最重要的,但 Git 会自行找到第三次提交:我们无法控制它选择的 哪个 提交。我们只选择 L 和 R 提交。第三次提交是 合并基础,简而言之,2 这是两个分支第一次重新组合在一起的地方:
o--...--o--o <-- L
/
...--o--*
\
o--o--...--o <-- R
或:
...--o--o--o--*--o <-- L
\ \
o--o--o--o <-- R
在这两个图中,标记为 * 的提交是合并基础。
1为简单起见,我们在这里假设一个正常的合并,两个头,一个合并基础提交。具有两个或多个合并基的交叉合并案例,以及具有两个以上头部的章鱼合并,使这变得复杂很多,但无论如何我们都不关心这种情况。
2这有点太短,但对于大多数情况来说已经足够了。
Git 产生两个差异
现在 Git 已经找到了合并基础——L 提交只是我们当前的分支提示,而 R 提交是您在运行 @987654343 时指定的提交@——并且有它的三个输入,Git 运行 git diff 两次:
git diff --find-renames base L # what we did
git diff --find-renames base R # what they did
第一个git diff 将存储在合并基础提交中的所有文件(请记住,每个提交都是所有文件的快照)与存储在 L 中的所有文件进行比较,以查看 我们更改了--ours。 --find-renames 选项使这个特定的git diff 检查被重命名的文件,但不检查被复制的文件。重命名检测器以默认的“至少 50% 相似”运行(您可以在我的其他一些答案中找到此重命名检测器如何工作的详细描述:diff rename, copy, and break detection 和 similarity index),但您可以使用 @ 调整百分比987654350@.
第二个 git diff 做同样的事情,但他们的 R 提交。
然后,git merge 继续合并两组差异。
如果两个 diff 之一或两者检测到基础中的 index.html 被重命名为 L 和 R之一或两者中的某个其他路径> 提交,Git 将采用其中一个重命名(如果这两个提交都重命名了基本文件,则声明高级重命名/重命名冲突)。不过,同样没有打开副本检测的选项,Git 只会将任何副本视为 L 和 R 之一或两者中的新文件。如果两者都添加,这可能会导致高级别的添加/添加冲突;或者如果它只是在一次提交中添加,Git 假定它应该被添加到新的提交中。
如果没有高级冲突和低级冲突,git merge 通常会立即进行新的提交。您可以使用--no-commit 抑制此操作并对工作树进行额外的工作。 (结果是一些人所说的evil merge。你应该意识到这一点,并且至少以某种方式标记提交,例如,在提交消息中。或者,进行正常合并,然后进行修复提交。没有这个特殊问题的完美答案。)
手动合并
要手动合并复制的文件,请提取合并基础版本(您可以使用 git merge-base 找到合并基础提交哈希 ID)和两个提示版本到三个普通文件中,然后在其上使用 git merge-file。请注意,默认情况下,git merge-file 将其输出写入三个输入之一 - 这可能是您想要的,因为 HEAD 或 --ours 版本已经在您的工作树中,在您使用的名称下, 所以你真正需要做的就是提取基础和--theirs 或 R 版本:
git show base-hash:base-path > newname.base
git show theirs:theirs-path > newname.theirs
git merge-file newname newname.base newname.theirs
然后在完成合并后删除.base 和.theirs 版本。 (与往常一样,检查生成的合并是明智的,因为 Git 只是遵循简单的一次一行的规则来组合差异。)