是否有可能在不丢失合并信息的情况下重写分支的历史记录?

时间:2012-08-06 08:33:08

标签: git

我们有一个主分支,我们已经合并了10个功能分支,一次一个。

所以最近的历史看起来像这样:

merged feat/10 (HEAD of master)
merged feat/9
merged feat/8
merged feat/7
merged feat/6
merged feat/5
...

现在我们发现feat/7很糟糕,我们想把它从主人那里拿走。恢复合并提交是不够的,因为我们根本不希望破坏的提交存在于我们的历史记录中。我们无法真正使用交互式rebase,因为这会使历史变得平坦,使其看起来好像完全在一个分支上完成,并且我们希望保留所有良好合并历史记录。

有没有办法从分支机构的历史记录中删除特定的合并提交?

我会注意到真实的历史要比你在上面的例子中看到的要复杂得多,所以手动重做所有的合并,因为feat / 7不是一个好的选择。

修改

为了澄清那些投票将其作为一个副本关闭的人:这不是关于如何使用rebase进行提交的常见问题解答,当然这已被多次回答。这里的问题是关于提交而不展平合并历史记录。

4 个答案:

答案 0 :(得分:1)

如果你的历史记录目前看起来那样并且你没有删除分支,那么你可以简单地git reset --hard HEAD~4这将在7合并之前将代码重置回状态然后你只需git merge好的分支回来。这是我能想到的最简单的方式。

编辑: 您可以在rebase上使用-p开关来保留合并,但将此开关与-i一起使用可能会产生结果。检查man git-rebase页面并查看BUGS部分以查看当前的错误。

EDIT2:如果在使用此命令之前未采取适当的预防措施,我不承担任何责任。在阅读联机帮助页之前不要使用它。

答案 1 :(得分:1)

您可以使用git filter-branch --parent-filter重写feat/8提交,以便其父级指向feat/6提交。保留所有其他提交的父级(9-10),这应该保留历史中的合并提交。

唯一的问题是导致删除代码的冲突会发生什么变化......没有真正的知道方式,而且可能是罪魁祸首。

答案 2 :(得分:1)

这不是你想要做的事情(可以说是“删除”合并提交),但实际上比在git reset --hard之后让你的协作者说服rebase更容易或filter-branch。只需还原合并。

git revert -m 1 <commit_for_feat7>

我并不特别喜欢使用恢复来污染我的主分支,但它没有任何内在错误。如果你不打算暂时修补feat7,或者只是想让它的变更集超出历史,那么这个解决方案比历史修订要少得多。

答案 3 :(得分:0)

你不能只是从git中删除东西,因为当前的哈希值取决于整个历史记录。

一个选项是创建一个从feat / 6开始的新分支,然后从feat / 8开始合并,以便分支头可以指向不同的哈希,而不需要更改feat / 7。

另一种选择,如果我没记错的话,是git replace(我认为以前称之为移植物)。它可以让你将feat / 8处的指针从feat / 7“替换”为feat / 6。我不完全确定它是如何实现这一点的,但看起来它不是真正的替代品,因为feat / 8仍然有一个指向某个地方的壮举/ 7,因为哈希不会改变,但是{{1}以某种方式添加一个备用历史记录,其中feat / 8指向feat / 6。 来自man page

git replace
  

在.git / refs / replace /

中添加替换引用      

替换引用的名称是对象的SHA1   更换。替换引用的内容是SHA1的SHA1   替换对象。

     

除非给出-f,否则替换引用必须不存在   .git / refs / replace / directory。

     

所有git命令都默认使用替换引用   除了那些进行可达性遍历(修剪,包转移和   fsck的)。

     

可以禁用任何替换引用的使用   在git之后使用--no-replace-objects选项命令。

编辑:第二个想法git replace [-f] <object> <replacement> git replace -d <object>… git replace -l [<pattern>] 可能是一个坏主意,因为在feat / 8的合并中将存在来自feat / 7的更改。你可能应该选择第一个选项:从合并的专长/ 6开始一个新的分支,然后从专长/ 8开始重新开始