在两个分支中移动文件时,Git合并失败

时间:2015-03-11 17:59:00

标签: git

我正在执行git merge,其中许多文件以相同的方式在合并的两个分支中移动。令我惊讶的是,对于大约10个文件,git无法在我合并的分支中找到该文件的版本。

即。文件在/path/file.txt中启动。在分支1文件中修改,然后移动到/path/newpath/file.txt。在分支2中,文件被移动到相同的路径/path/newpath/file.txt。当我合并时,我希望git能够处理这个问题。但是,它将此显示为合并冲突,表示文件已从分支1中删除。我有三个问题:

  1. 为什么git找不到这些文件?天真的我希望git简单地说“在合并分支中获取此文件路径的版本”,但它可能不是这样做的?在我看来,所涉及的文件已经发生了很大变化,这让我怀疑git正在比较文件内容以确定它们是否是合并候选者,正如这个SO问题所示:git merge with renamed files 但是,具有相同路径和名称的文件肯定应被视为合并候选者,即使它们的内容发生了很大变化吗?
  2. 是否有一些配置我可以更改告诉git考虑与合并候选人具有相同名称和路径的文件?我引用的SO问题表明您可以设置文件相似度百分比,但这似乎是实现我想要的一种倾斜方式。
  3. 我可以通过我的git索引的手动或脚本更新来使这个合并工作,告诉git另一个分支中文件的对象哈希。根据另一个SO问题的脚本,它看起来像这样:

    FILE_PATH = “路径/到/ file.txt的”

    git update-index --index-info<< EOI 000000 0000000000000000000000000000000000000000 0 $ FILE_PATH 100644电子邮件向我们提供电子邮件 100644 0ddb2a448cb9cca97834df78ae00e213ecd9dd71 3 $ FILE_PATH EOI

  4. 如果我这样做,我还需要告诉git有关共同的祖先对象吗?即使用第2阶段和第3阶段的记录,还是使用update-index为第1阶段输入一个条目?我感到困惑的原因是因为在这个特定的情况下,共同的祖先将有两个其他版本的路径不同,所以即使我要更新索引以包含它,如何告诉git这是祖先!?如果文件路径不同,那么将第1阶段条目与第2阶段和第3阶段条目联系起来会是什么?

1 个答案:

答案 0 :(得分:1)

索引保存您想要提交的内容,因此索引中的路径应该是合并提交中的任何内容。但是,这里有多条路径,请参阅下面#3的答案。

按顺序回答您的问题:

  1. “当然,具有相同路径和名称的文件应被视为合并候选”:不一定,因为重命名检测。

    Git通过识别合并基础(实际提交,或者在某些极少数情况下使用“递归合并”技巧,通过执行另一次合并进行虚拟提交)开始合并过程,然后区分合并基础 - 整个树 - 针对有问题的两个提交(HEAD,运行git merge时所在的提交/分支,以及MERGE_HEAD,您要求合并的提交)。这会产生两个独立的差异,每个差异都会进行单独的重命名检测。

    在这种特殊情况下,path_a在两个分支中都重命名为path_b,但实际上只检测到一个重命名。 (如果未检测到重命名,则表示存在“创建/创建冲突”,其中git认为path_b是在两个分支中独立创建的。如果两者相同已经检测到重命名,git只会合并“从基础path_apath_bHEAD MERGE_HEAD。所以我们可以得出结论,git只有一半成功了。)

    由于git没有注意到两个差异之一中的path_b实际上是从path_a重命名的,所以它决定在那个差异中你只是删除了path_a并写了一个完全不同的path_b。它无法合并任何更改,因为path_b中的HEADpath_b中的MERGE_HEAD无关。

    您链接的索引更新问题显示了如何告诉git,不,实际上两个path_b 都是相关的,并且合并基础版本只是命名为{{1在这两种情况下。然后最后的“git checkout -m”创建适当的合并版本(可能有合并冲突)。

  2. 目前,path_a选项就是全部。按照您链接的问题中的链接,可以获得该脚本,告诉git“事后事件”,因为它错过了任何重命名。

  3. 这是我需要进行一些实验的地方。索引条目 告诉git共同祖先的SHA-1,它位于“索引槽1”中。在某种意义上,与它一起使用的路径完全无关:要进行合并,git只需要文件内容(对于所有三个版本:base aka stage 1,HEAD aka stage 2,and MERGE_HEAD又名第3阶段。看起来很可能,无论是基于索引格式还是脚本(https://gist.github.com/tvogel/894374),你需要的路径不是原始路径,而是新提交路径 - 但我不知道肯定不知道。