基于指定的一对提交作为公共基础,合并Git分支。

4
可以基于特定的一对提交作为共同基础在Git中合并分支吗?
情境:
有两个独立的Git仓库,一个叫“ours”,一个叫“theirs”。
“theirs”是在已知时间点使用“ours”的工作副本(仅限文件)创建的。 “theirs”的初始提交是将“our”文件的快照添加到其中。
现在我们想要将“theirs”合并到“ours”中:
git remote add theirs <their repository path>
git pull theirs <their branch> --allow-unrelated-histories

git merge将寻找一个共同的祖先来作为合并的基础。然而,在'ours'和'theirs'之间没有共同的提交记录。

既然我们可以在'ours'中找到与'theirs'中初始提交匹配的工作副本的提交记录,我认为Git应该能够明智地开始合并,但是我们需要指示Git将这两个特定的提交记录视为共同的基础。


1
git merge 命令也有 --allow-unrelated-histories 选项。 - Qeek
max630的回答 - 本质上,创建一个父扭曲来掩盖提交历史(这是可以的,因为这个谎言是真的!)- 这是实现此目的的方法。 - torek
2个回答

2
“theirs”是在已知时间点上,使用“ours”的工作副本(仅文件)创建的。在“theirs”的初始提交中,添加了“our”文件的快照。
可能,在您的情况下,最好的选择是对应的“ours”提交添加替换为伪父提交:
git replace --edit <THEIRS_INIT>

在头部添加 "parent <OURS_COMMIT>" 行,保存

合并完成后,您可以删除替换。


这是我没有考虑过的replace用法。个人而言,我不喜欢它留下的历史记录,但这是另一个相当简单的选项。 - Mark Adelsberger
1
如果您要在提交上使用replace,我建议使用--graft语法。 - LightBender

0

所以让我们先将所有的对象放在一个仓库中,然后再考虑合并。

git fetch theirs

现在你已经有了

A -- B -- C -- D -- E -- F -- G <--(master)

d -- H -- I -- J <--(theirs/master)

d处的内容(TREE)与D处的内容相同。

现在,您想将HJ合并到master中,并将D视为合并基础。您可能可以想出一些组合的命令来完成这个任务。但我不会这样做。

相反,我会考虑如何最好地合并历史记录。最简单的方法是将HJ变基到D上。类似的,但处理更少/发生奇怪事情的机会更小,是将H重新父节点化而不是变基。(因为dD具有相同的内容,所以无论使用哪种操作,结果应该是相同的。)

要更改 H 的父节点,您需要使用带有 --parent-filter 选项的 git filter-branch 命令。您需要查找 dD 的提交 ID(SHA)值,然后可能使用一个 sed 脚本,将 d ID 替换为 D ID。有关详细信息,请参见 filter-branch 文档;我很确定有一个恰好符合这种情况的例子。
如果您不想处理这个问题,就像我说的,在这种情况下重新基础操作应该是等效的。您仍然需要一个表达式来解析到 D,比如在示例中的 master~3,或者提交 ID 也可以。还需要一个解析到 d 的表达式,例如在示例中用到的 theirs/master~3
git checkout theirs/master
git checkout -b temp
git rebase --onto master~3 theirs/master~3

这会给你

A -- B -- C -- D -- E -- F -- G <--(master)
                \
                 H' -- I' -- J' <--(temp)

d -- H -- I -- J <--(theirs/master)

现在你可能只想将temp合并到master并且丢弃theirs/master;但是潜在的风险是H'I'J'是新的提交(具有新的ID值等),因此如果您要继续维护theirs存储库并希望迁移更改,这种方法会在下一次迁移时留下相同的问题。

因此,如果您要保留theirs,可以进行以下调整:

在这种情况下,理想情况下,您希望使用theirs的原始提交,但这并不是非常容易做到的。相反,您可以在将temp合并到master之前,对theirs/master进行一种“虚假合并”。

git checkout temp
git merge -s ours theirs/master

现在你有了

A -- B -- C -- D -- E -- F -- G <--(master)
                \
                 H' -- I' -- J' -- JJ <--(temp)
                                  /
                  d -- H -- I -- J <--(theirs/master)

JJ 可能看起来像是一个“邪恶的合并” - 它的内容不是将 J'J 合并的自然/默认结果。但是,考虑到这些历史记录,这样的合并应该会产生冲突 - 也就是说,对于这样的合并,不应该存在“自然/默认结果”。因此,这并不令人困扰。

这意味着 JJ'JJ 都具有相同的内容,将 temp 合并到 master 应该仍然可以得到正确的结果。

A -- B -- C -- D --- E --- F --- G --- M <--(master)
                \                     /
                 H' -- I' -- J' -- JJ <--(temp)
                                  /
                  d -- H -- I -- J <--(theirs/master)

此时您可以删除temp

保留dHIJJJ的目的,正如我所说,是为了方便以后从theirs进行更新。在未来的获取中,您可能会得到:

A -- B -- C -- D --- E --- F --- G --- M -- N -- O -- P <--(master)
                \                     /
                 H' -- I' -- J' -- JJ 
                                  /
                  d -- H -- I -- J -- K -- L <--(theirs/master)

从这个状态开始,你可以简单地将theirs/master合并到master中,因为Git会计算出J是合并基础。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接