在Git中重新合并树

时间:2014-02-19 19:38:04

标签: git git-merge git-rebase

我有类似于以下历史记录(但更复杂的有几个合并):

        F - G - H - K - L - …
       /           /
      /       I - J - M - …
     /       /
A - B - C - D - E - …

A′- B′- C′- D′- E′

A和A'是具有不同历史的相同树木。

我想将所有分支提交重新绑定到主分支上的等效提交,保留合并(可能是通过手动指定等效提交在重新生成的树上的哈希值)。如何告诉K′它需要从H′J′合并?或者我是否必须手动重新创建这些合并提交?

如果我git rebase -p --onto B′ B L,则无法干净地应用。我可以将H重新定位到B′,将M重新定位到D′,然后自己重​​新创建合并K,然后将L重新定位到K′ (等等其他分支/合并未显示)但这将是一项相当有意义的工作。

我查看了several other questions,但没有一个是合并。

2 个答案:

答案 0 :(得分:3)

假设这不是公共存储库,或者存储库的任何其他用户都可以进行重要的重写,最有效的方法是使用git filter-branch。其中一个可能的过滤器是--parent-filter,它允许您更改特定提交的父项,有点类似于移植或重新定位树的一部分,但由于您也可以传递--all选项,可以在一次调用中完成对多个分支的影响。这也可以用--commit-filter完成;但这是一个更通用的解决方案,旨在改变个人提交的其他方面 - 而不仅仅是父母。您可能还想使用--tag-name-filter cat移动正在重写的树部分中的任何标记。

所以最后的命令看起来像是:

git filter-branch --parent-filter <somescript> --tag-name-filter cat -- --all

其中<somescript>正确引用/转义bash代码,以A替换A' B提交(具体信息如何提供给脚本以及脚本的结果应该在git help filter-branch)中找到,或者是实现相同内容的实际shell脚本的名称。

之后还要进行一些清理 - filter-branch将原始分支留在原位,但使用新名称(refs/original/...),这样如果看起来不正确,您就可以恢复。一旦你对filter-branch做了你想做的事情感到满意,并且重新打包你的存储库以恢复存储空间,那里有很多关于如何删除死枝的信息,所以我不会在这里复制它。

答案 1 :(得分:1)

您是否尝试过使用互动式变基?基本上,git rebase -i A和git会在列出A之后的提交中启动文本编辑器。然后,您可以移动提交并将提交相互压缩到您心中的内容。