如何将两个提交合并为一个提交?

155

我有一个名为“firstproject”的分支,里面包含2个提交。我想要消除这些提交并将它们显示为单个提交。

命令git merge --squash听起来很有希望,但当我运行git merge --squash时,终端只会弹出该命令的选项。正确的命令是什么?

Commit 1:
Added 'homepage.html'
Added 'contacts.html'

Commit 2:
Added 'homepage.php'
Added 'homepage.php'
Deleted 'homepage.html'
Deleted 'contacts.html'

我认为那不是正确的命令。而且,我怀疑你是否能够像那样更改提交记录。 - BSull
1
你可以将多个提交合并为一个提交:http://git-scm.com/book/zh/v2/Git-工具-重写历史记录 我的问题只是关于具体的命令。 - Don P
@BSull你完全可以随意修改提交记录,它们在任何时间都是可编辑的。如果你正在与他人共享代码,这样做将重写你的历史记录,实际上你将与其他人使用不同的分支进行工作。 - user229044
这个问题本不应该被复制。事实上,那个问题应该被关闭,因为它太宽泛了。这个标记为重复的问题过于复杂,因为它涉及放弃先前的变基。 - Evan Carroll
5个回答

222

您想要执行一个交互式变基interactive rebase,需要使用git rebase -i命令。

如果您当前位于"commit 1",并且您想要合并的提交是"commit 2",则可以运行git rebase -i HEAD~2命令,它将打开一个编辑器,列出所有将被遍历的提交。您应该会看到两行以"pick"开头。要进行压缩,请将第二行的第一个单词从"pick"更改为"squash"。然后保存文件并退出。Git将把您的第一个提交压缩成倒数第二个提交。

请注意,此过程会重写分支的历史记录。如果您正在将代码推送到其他地方,则必须使用git push -f命令,共享您代码的任何人都必须通过一些步骤来拉取您的更改。

请注意,如果涉及的两个提交不是分支上的最后两个提交,则该过程将略有不同。


3
如何执行“Then write your file, and quit”操作?我使用Android Studio终端、git控制台或者甚至通过SourceTree软件打开git控制台。但是如何保存并退出? - Dr.jacky
3
如何合并分支上不是最后两个提交的两个提交? - Weishi Z
1
@meagar 我认为这是有道理的...如果你检查一下这个问题(一个重复的问题),压缩“方向”会产生很大的差异,并且是整个问题的根源(请参见第一个评论,约200个赞关于“错误压缩”的问题)- https://dev59.com/5HE85IYBdhLWcg3w43sW#2568581 - PandaWood
1
@PandaWood 你误读了答案。第一种方式是简单的错误,而不是不同的。你只能向后压缩,将旧的提交压缩到较新的提交中毫无意义,但如果你可以这样做,那么它将是相同的操作。 - user229044
1
我理解到了“更改第二行的第一个单词”-指的是哪一行的第二行? - Andrew Torr
显示剩余3条评论

110

懒人版,适合像我这样健忘的人:

git rebase -i HEAD~3(或者替换3为需要的提交次数)。

将此转换为:

pick YourCommitMessageWhatever
pick YouGetThePoint
pick IdkManItsACommitMessage

变成这样

pick YourCommitMessageWhatever
s YouGetThePoint
s IdkManItsACommitMessage

当下一个屏幕出现时,删除那些垃圾行(garbage # lines) [2] 并创建一个新的提交信息或类似的东西,并执行相同的 escape enter 操作以保存更改。[1]

哇哦,你的提交次数变少了。或者你把一切都搞砸了。


[1] - 或者根据您的git配置使用其他方法。 这只是在我的设置中有效的序列。

[2] - 你会看到一些像# this is your n'th commit这样的东西,几次之后会有你原始的提交信息。你想删除这些行,并创建一个提交信息来反映你合并成一个的 n 个提交的意图。


5
非常简明的解决方案-谢谢。可能需要概述这里使用的s代表压缩。要使用提交,但融合到之前的提交中。 - UrbanConor
2
如果您只有2个提交并想要合并相同的2个提交,则需要运行git reset --soft HEAD~git commit --amend - scrutari
@Stachu 当我执行 push 命令后,它会要求进行 pull 和 merge。有什么办法可以避免这种情况发生? - Abhay Koradiya
为什么你不想要拉取和合并呢? - Stachu
如果您想保留 pick YourCommitMessageWhatever 的提交信息,并将其他提交合并到其中,可以使用 f(fixup)替换 s。不要忘记确保您的提交顺序正确,以避免出现意外结果!(之后使用 git log -p 查看带有更改的日志) - Eduardo06sp

31
  1. 检出你的分支并计算所有提交的数量。
  2. 打开Git bash,并输入:git rebase -i HEAD~<你的提交数量>(比如git rebase -i HEAD~5
  3. 在打开的txt文件中,将除了最顶部的第一个提交之外的所有提交的关键字pick改为squash。对于顶部的第一个提交,将其更改为reword(这意味着你将在下一步提供一个新的注释),然后点击保存!如果在vim中,请按esc键,然后输入wq!保存并按回车。
  4. 提供注释。
  5. 打开Git并进行“全部获取”以查看新的更改。

完成


18

这就是我的做法。对我来说比进行交互式变基更容易:

git reset HEAD~2.  // go back 2 commits.
git commit -am “My squashed single commit”
git push --force 

3
这应该是被接受的答案!! 或者至少得到更多的投票! 所有其他解决方案都太复杂了,需要大量的打字狂潮,而使用GUI软件(如sourcetree或tortoise)会更好,只需几个鼠标点击即可获得相同的结果。然而,您的解决方案是最干净、最快速的,非常适合个人项目或团队项目,在这些项目中,您处于自己的分支上。 - Tal Kohavy
2
git reset HEAD~2. 不是一个有效的命令。 - tala9999
@tala9999 你是什么意思?我刚刚成功地使用了它。 - cassepipe
你需要的是 git reset --soft。使用这个解决方案,你需要在提交之前重新添加更改到暂存区。请参考:https://dev59.com/Vm435IYBdhLWcg3w1juV#61171280 - cassepipe

1
前面提到了交互式变基和重置合并。 另一种方法对我来说更安全,因为它不使用之前的所有东西(交互式和重置),也不会干扰现有数据。它使用git merge --squash,就像主题发起者建议的那样。它创建一个新分支,并将其与压缩合并:
git branch <result_branch_name> <point from where you want to merge commits>
git checkout <result_branch_name>
git merge --squash <branch_with_all_your_commits>

作为结果,您将收到从创建结果分支的点到最终提交之间的所有提交的分阶段更改。提交消息将包含所有压缩提交的消息。然后只需输入git commit,修改提交消息,您将获得唯一的提交,其中包含所有必要的更改。当您准备好告别时,可以使用git branch -D <branch_name>删除原始分支。=)

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