我有类似于以下历史记录(但更复杂的有几个合并):
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′
(等等其他分支/合并未显示)但这将是一项相当有意义的工作。
答案 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之后的提交中启动文本编辑器。然后,您可以移动提交并将提交相互压缩到您心中的内容。