2014-02-19 45 views
3

我有一个类似于下面的历史记录(但更复杂的几个合并):衍合合并树的Git

 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′MD′,然后重新创建合并K我自己,然后将L重新分配到K′(对于其他分支/合并等未显示),但这将是一个公平的工作。

我看过severalotherquestions但他们都没有合并。

+0

您的回购是私密的,还是可以在GitHub上公开访问?如果它是公开的,人们可以直接看一看。 – 2014-02-19 19:50:37

+0

如果这是一个私人回购,那么你应该可以用'git filter-branch --parent-filter ... --all'来完成这个工作,其中父过滤器的脚本标识为'B'并且声明它是新的父母应该是'A''而不是'A'。您可能会想要添加一个'--tag-name-filter cat'来保留您正在重写的部分中的任何标签。但如果是公共回购,这可能是不明智的。看起来你也可以使用'--commit-filter',但它更通用... – twalberg

回答

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'更换AB提交(细节上的信息究竟是如何提供给脚本以及脚本的结果应该在git help filter-branch中找到),或者实现相同脚本的实际shell脚本的名称。

之后还有一些清理工作要做 - filter-branch将您的原有分支留在原地,但使用新名称(refs/original/...),因此如果某些东西看起来不正确,您可以恢复。当你满意filter-branch做了你想要的并且重新打包你的存储库以恢复存储空间时,如何清除死分支有很多信息,所以我不会在这里复制它...

+0

因为该标志被发送到子命令,所以我在'--all'标志前需要一个双破折号:'git filter- branch -f --parent-filter'test $ GIT_COMMIT = HASH_OF_B && echo“-p HASH_OF_A_PRIME”||猫' - - 都',但否则它的工作。谢谢。 –

+0

啊,是的,忘了那部分 - 为后代编辑它.... – twalberg

1

您是否尝试过使用交互式重新绑定?基本上,做git rebase -i A,git会在列出A后提交你的文本编辑器。然后,您可以将提交和压缩转移到对方的内容中。