6

我们有一个主分支,我们在其中合并了大约 10 个功能分支,一次一个。

所以最近的历史是这样的:

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

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

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

我会注意到真实的历史比您在上面的示例中看到的要复杂得多,因此手动重新执行自 feat/7 以来的所有合并不是一个好的选择。

编辑

为了澄清那些投票决定将其作为 dup 关闭的人:这不是关于如何使用 rebase 取出提交的常见问题解答,这当然已被多次回答。这里的问题是关于在不展平合并历史的情况下取出提交。

4

4 回答 4

1

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

唯一的问题是导致删除代码更改的冲突会发生什么......没有真正的知道方法,它可能是罪魁祸首。

于 2012-08-06T10:00:50.127 回答
1

这并不是您想要做的(可以说是“zap”合并提交),但实际上它比说服您的合作者git reset --hard在 a rebaseor之后更容易filter-branch。只需还原合并。

git revert -m 1 <commit_for_feat7>

我不是特别喜欢用还原来污染我的主分支,但它本质上并没有错。如果您暂时不打算打补丁feat7,或者只是希望它的更改集脱离历史,那么这个解决方案比历史修订麻烦得多。

于 2012-08-06T12:28:30.197 回答
1

如果您的历史记录当前看起来像这样并且您没有删除分支但您可以简单地git reset --hard HEAD~4将您的代码重置回您合并到 7 之前的状态,那么您可以简单地git merge将好的代码重新放入。这是我能想到的最简单的方法我的头。

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

EDIT2:如果您在使用此命令之前没有采取适当的预防措施,我不承担任何责任。在阅读手册页之前也不要使用它。

于 2012-08-06T08:48:03.627 回答
0

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

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

如果我没记错的话,另一种选择是git replace(我认为它曾经被称为移植物)。它可以让您将专长/8 处的指针从专长/7“替换”为专长/6。我不完全确定它是如何实现这一点的,但它看起来不是一个真正的替代品,因为 feat/8 仍然有一个指向 feat/7 的指针,因为哈希没有改变,但git replace不知何故添加了一个替代品其中专长/8 指向专长/6 的历史。从手册页

git replace [-f] <object> <replacement>   
git replace -d <object>…  
git replace -l [<pattern>]

在 .git/refs/replace/ 中添加替换引用

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

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

默认情况下,所有 git 命令都将使用替​​换引用,除了那些执行可达性遍历(修剪、包传输和 fsck)的命令。

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

编辑:再三考虑git replace可能是个坏主意,因为从 feat/7 的变化将存在于 feat/8 的合并中。您可能应该只使用第一个选项:从合并的专长 / 6 开始一个新分支并从专长 / 8 开始重新合并

于 2012-08-06T09:36:39.293 回答