在Git中重新设置合并树的基

在Git中重新设置合并树的基,git,git-merge,git-rebase,Git,Git Merge,Git Rebase,我有一些类似于以下历史的东西(但更复杂的是几个合并): A和A′是具有不同历史的同一棵树 我希望将所有分支提交重新设置为主分支上的等效提交的基础,从而保留合并(可能是通过手动指定重定基础树上等效提交位置的哈希)。我如何告诉K′它需要从H′和J′合并?还是必须手动重新创建这些合并提交 如果我在B'BL上执行git-rebase-p--,它将无法干净地应用。我可以将H重设为B'和M重设为D',然后自己重新创建mergeK,然后将L重设为K'(对于未显示的其他分支/合并也是如此),但这将是一项相当大的

我有一些类似于以下历史的东西(但更复杂的是几个合并):

A和A′是具有不同历史的同一棵树

我希望将所有分支提交重新设置为主分支上的等效提交的基础,从而保留合并(可能是通过手动指定重定基础树上等效提交位置的哈希)。我如何告诉
K′
它需要从
H′
J′
合并?还是必须手动重新创建这些合并提交

如果我在B'BL上执行git-rebase-p--,它将无法干净地应用。我可以将
H
重设为
B'
M
重设为
D'
,然后自己重新创建merge
K
,然后将
L
重设为
K'
(对于未显示的其他分支/合并也是如此),但这将是一项相当大的工作


我已经看过了,但没有一个是以合并为特色的。

你试过使用交互式重定基址吗?基本上,只要执行
git-rebase-ia
,git就会在一个列表之后启动文本编辑器并提交。然后,您可以移动提交并将提交内容压缩到彼此的心里。

假设这不是一个公共存储库,或者存储库的任何其他用户都可以进行重大重写,实现这一点的最有效方法是使用
git filter branch
。其中一个可能的过滤器是
--parent filter
,它允许您更改特定提交的父级,这有点类似于嫁接或重定树的一部分,但由于您也可以传递
--all
选项,因此您可以在一次调用中实现对多个分支的效果。这也可以通过
--commit过滤器来实现;但这是一个更通用的解决方案,旨在改变个人承诺的其他方面,而不仅仅是父母。您可能还希望使用
--tagname过滤器cat
来移动正在重写的树部分中的任何标记

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

git filter-branch --parent-filter <somescript> --tag-name-filter cat -- --all
git过滤器分支--父过滤器--标记名过滤器cat--all
其中
被正确引用/转义
bash
代码,以将
A
替换为
A'
,用于
B
提交(有关如何向脚本提供信息以及脚本结果的详细信息,请参见
git help filter branch
),或者完成相同操作的实际shell脚本的名称


之后还需要进行一些清理-
过滤器分支
保留原始分支,但使用新名称(
refs/original/…
),以便在出现问题时进行恢复。一旦您确信
过滤器分支
满足了您的要求,并且重新打包了存储库以恢复存储空间,就有大量关于如何删除死分支的信息,因此我不会在这里重复…

您的回购是私有的,还是可以在GitHub上公开访问?如果是公开的,人们可以直接看一看。如果这是私人回购,那么您应该能够通过git filter branch--parent filter实现这一点--all
,其中父过滤器的脚本标识
B
,并声明其新父过滤器应为
A'
,而不是
A
。您可能需要添加一个
--tag name filter cat
,以保留要重写的部件中的任何标记。不过,如果是公开回购,这可能是不可取的。看起来您也可以使用
--commit-filter
,但它更通用一些……我需要在
--all
标志之前加上一个双破折号,因为该标志被发送到一个子命令:
git-filter branch-f--parent-filter'test$git\u commit=HASH_OF_B&&echo“--p HASH_OF_OF a_PRIME”| cat'--all
,但除此之外,它仍然有效。非常感谢。
git filter-branch --parent-filter <somescript> --tag-name-filter cat -- --all