从历史记录中移除Git合并提交

167

我的Git历史记录如下:

Git history

我想将紫色提交压缩为一个提交。我不想在我的提交日志中再次看到它们。

我尝试过运行git rebase -i 1命令,但是即使1在蓝色分支上(参见图片),我仍然看到紫色分支上的每个提交。

如何完全删除紫色分支(从提交日志中)?


你的代码库是否已经推送到其他人已经拉取过的地方了? - Schleis
两个分支都是纯本地的。 - Benjamin Toueg
今天我学到了一个技巧:使用 git rebase -i <first commit sha> 命令可以消除所有合并提交记录 :) 但这只适用于没有冲突解决的仓库,且仅包含合并提交记录。 - vivekmore
5个回答

151

执行git rebase -i <分支发散之前的SHA>命令,这将使您能够删除合并提交,日志将会是您所需的单行。您还可以删除任何不再需要的提交。如果重置失败,原因可能是您回退的版本不够早。

警告: 执行此操作将重写历史记录。对已经推送到远程仓库的更改执行此操作将导致问题。建议仅对本地提交执行此操作。


7
即使在分支发生分歧之前我选择了一个提交记录,我仍然会看到紫色分支的所有提交记录。-_- - Benjamin Toueg
6
删除提交记录导致合并所做的所有修改都丢失了。但是我进行了软重置,现在获得了与我想要的相似的结果(顺序与最初的预期不符)。 - Benjamin Toueg
3
这个答案缺乏细节,你需要从哪个分支开始重新设置基底(rebase)? 这个答案不够详细,你要从哪个分支开始执行 rebase 操作? - grgry
1
@gregorynich 你只处理了一个分支,它刚刚合并了另一个分支。这导致所有提交都出现在历史记录中,OP的问题没有涉及其他分支。 - Schleis
4
我很确定你不想“删除”提交记录。在变基中,“删除”不是一个选项,但“删除”是一个选项。如果你删除了一个提交记录,你将会丢失它所引入的更改。你想要压缩(commit)这些提交记录。 - thecoshman
显示剩余5条评论

140

从原始状态的 repo 开始

Original repo history

为了删除合并提交且将分支压缩成主干上的单一提交

Squashed commits, no merge commit

使用以下命令(将 5 和 1 替换为相应提交的 SHA):

git checkout 5
git reset --soft 1
git commit --amend -m '1 2 3 4 5'
git rebase HEAD master

保留合并提交,但将分支提交合并为一个:

合并后的提交,保留了合并提交

使用以下命令(将5、1和C替换为相应提交的SHA):

git checkout -b tempbranch 5
git reset --soft 1
git commit --amend -m '1 2 3 4 5'
git checkout C
git merge --no-ff tempbranch
git rebase HEAD master

移除合并提交并用分支中的单个提交替换它

分支已合并到主线,没有合并提交

只需执行以下操作(将5替换为相应提交的SHA):

git rebase 5 master

最后,要完全删除该分支

完全删除的分支

使用此命令(将C和D替换为相应提交的SHA):

git rebase --onto C D~ master

1
git rebase 5 master 的情况下,为什么不是按照 "A B C 1 2 3 4 5 D ..." 的顺序呢? - Roy
3
该命令获取master5不共有的提交,并将它们放在5之上。位于C的提交不是5的祖先,而是第一个移动到5之上的提交。 - Allen Luce
3
如果你想得到类似于"A B C 1 2 3 4 5 D …"的结果,可以执行以下命令:git rebase C 5; git rebase 5 master - Allen Luce
就像这样完全一模一样,甚至往前追溯了上千个提交,都能正常工作! - Michael-O

51

只需删除合并提交

如果你只想要删除一个合并提交(2),使它看起来从未发生过,那么命令如下:

git rebase --onto <第1个提交的 sha> <第2个提交的 sha> <蓝色分支名>

现在紫色分支不会再出现在蓝色分支的提交记录中,你将拥有两个独立的分支。接下来,你可以单独压缩紫色分支,并进行其他任何操作,而合并提交不会再成为干扰。


3
在所有的答案中,我认为这个既是最直接的也是最容易实现的。谢谢。 - Roshambo
这是问题的第一步,我同意这是最容易做到完全符合要求的。第二步将是 git merge --squash <紫色分支名称> - Tony
如果您想保留蓝色分支上的其他合并提交记录(否则rebase默认会将其平铺),请添加--rebase-merges。最佳答案,肯定的。谢谢。 - chris

25

根据您的需求,有两种方法来解决这个问题:

方法1:删除紫色提交,保留历史记录(以防需要回退)

git revert -m 1 <SHA of merge>

-m 1指定要选择哪个父级行

紫色提交将仍然存在于历史记录中,但由于您已经还原,因此您将无法看到这些提交中的代码。


解决方案2:完全删除紫色提交(如果存储库是共享的,则会产生破坏性的更改)

git rebase -i <SHA before branching out>

并删除与紫色提交相应的行。

如果合并后没有进行提交,则此过程将较为简单。额外的提交会增加在撤销/变基时发生冲突的机会。


这听起来不太对。撇开原帖想要在第一次提交中使用紫色提交的意图不谈,如果您还原合并,那么可以将该提交的更改进行反向修补,并将其作为另一个提交添加,从而取消紫色提交。这就像 1-1=0。但是,如果您然后通过变基删除紫色提交,除非您也将其变基删除,否则会留下已还原的补丁。如果您不这样做,就好像将 -1 应用于您的历史记录,而不是 0,因此您将留下不想要的更改。 - user456814
@Cupcake,之前提供了两个不同的答案。我已经修改了答案,使其更加清晰易懂 :P - prem
据我所知,这不是OP所要求的。他想保留更改,但从日志中删除噪音。为此,他需要压缩提交记录,删除将会移除更改。 - thecoshman
真的,看起来原来的问题已经被重新表述了。这个答案不是针对OP的问题的。 - prem

10
为了完全掌控操作并保留您想要保留的合并提交,现代方法是使用:
git rebase -i -r

好知道..但这是我永远不会使用的选项...因为个人偏爱在我的git历史记录中最小化或没有合并提交 :) - vivekmore
我开始做这个,但后来我完全不知道自己在做什么,你能详细解释一下这个答案吗? - acolchagoff
命令的核心仍然是git rebase -i,所以首先确保你对此命令非常熟悉。建议你先选择一个简单的合并提交来尝试一下。阅读待办事项文本文件中的内容,尝试追踪和跟随git将要执行的操作。一旦你有了一个好的想法,你可以开始尝试引入新的提交到合并中,将提交移动到合并之前等等。如果你需要更具体的帮助,请提供更多细节 :) - squall3d

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接