题 如果我已经开始使用rebase,如何将两个提交合并为一个?


我试图将2个提交合并为1,所以我跟着 从git准备好的“压缩承诺与rebase”

我跑了

git rebase --interactive HEAD~2

在生成的编辑器中,我改变了 pick 至 squash 然后保存退出,但是rebase因错误而失败

没有先前的提交,不能'挤压'

既然我的工作树已达到这种状态,我就无法恢复了。命令 git rebase --interactive HEAD~2 失败了

交互式rebase已经开始

git rebase --continue 失败了

没有先前的提交,不能'挤压'


991
2018-04-01 20:56


起源


我也打了这个。我的错误是因为git rebase -i以git log的相反顺序列出了提交;最新的提交是最底层的! - lmsurprenant
有关: 使用Git将我的最后一次X提交压缩在一起。
还看看: git-scm.com/book/en/Git-Tools-Rewriting-History - nha


答案:


概要

错误消息

没有先前的提交,不能'挤压'

意味着你可能试图“向下挤压”。 Git总是将较新的提交压缩为较旧的提交 或者在交互式rebase待办事项列表中查看的“向上”,即进入前一行的提交。更改你的待办事项列表第一行的命令 squash 将始终产生此错误,因为第一次提交压缩没有任何内容。

修复

首先回到你开始的地方

$ git rebase --abort

说你的历史是

$ git log --pretty=oneline
a931ac7c808e2471b22b5bd20f0cad046b1c5d0d c
b76d157d507e819d7511132bdb5a80dd421d854f b
df239176e1a2ffac927d8b496ea00d5488481db5 a

也就是说,a是第一次提交,然后是b,最后是c。在提交c之后,我们决定将b和c压缩在一起:

(注意:跑步 git log 将其输出传输到寻呼机, less 默认情况下在大多数平台上要退出寻呼机并返回到命令提示符,请按 q 键。)

运行 git rebase --interactive HEAD~2 给你一个编辑

pick b76d157 b
pick a931ac7 c

# Rebase df23917..a931ac7 onto df23917
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

(请注意,此todo列表与输出相比的顺序相反 git log。)

改变b pick 至 squash 会导致你看到的错误,但是如果相反你将c压缩成b(较旧的提交到较旧的或“向上挤压”)通过将todo列表更改为

pick   b76d157 b
squash a931ac7 c

并保存退出您的编辑器,您将获得另一个内容为的编辑器

# This is a combination of 2 commits.
# The first commit's message is:

b

# This is the 2nd commit message:

c

保存并退出时,已编辑文件的内容将成为新组合提交的提交消息:

$ git log --pretty=oneline
18fd73d3ce748f2a58d1b566c03dd9dafe0b6b4f b and c
df239176e1a2ffac927d8b496ea00d5488481db5 a

关于重写历史的注意事项

交互式rebase重写历史记录。尝试推送到包含旧历史记录的遥控器将失败,因为它不是快进的。

如果您重新分支的分支是主题或功能分支 你自己工作的人, 没什么大不了。推送到另一个存储库将需要 --force 选项,或者您可以根据远程存储库的权限首先删除旧分支,然后推送已更新的版本。可能会破坏工作的那些命令的示例超出了本答案的范围。

在您与其他人合作的分支上重写已发布的历史记录 非常 诸如泄露密码或其他敏感细节之类的正当理由迫使您的合作者工作并且是反社会的,并会惹恼其他开发人员。该 “从上游Rebase恢复”部分 git rebase 文件 解释说,更加强调。

重新定位(或任何其他形式的重写)其他人基于其工作的分支是一个坏主意:它下游的任何人都被迫手动修复其历史记录。本节介绍如何从下游的角度进行修复。 然而,真正的解决方法是首先避免重新上游。 ...


1536
2018-04-02 19:04



如果我使用rebase来压缩提交,则会创建一个包含两个更改集的新“组合”提交,但哈希值不同。是git保留的原始提交吗? - fabsenet
@fabsenet是和否。原始提交仍然可以访问,但可能无法再通过任何参考(根据您的历史细节)。最终通过垃圾收集过程清除未引用的提交。 - Greg Bacon
我只是在玩耍......我做到了 git log hashoftheoldcommit 它有效,但我很想看到一个 git log --graph 包含所有这些无法访问的提交 - fabsenet
这个壁球是推送之前组织提交的好工具,但如果我推送一个提交,我不能压缩它? git说:成功重组并更新了独立的HEAD。 - Sérgio
我没有得到第二个实例的编辑器,git bash,似乎被冻结到某个过程中。该怎么办? - sidgupta234


如果有多个提交,您可以使用 git rebase -i 将两个提交压缩成一个。

如果您只想合并两个提交,并且它们是“最近的两个”,则可以使用以下命令将两个提交合并为一个:

git reset --soft "HEAD^"
git commit --amend

336
2017-07-11 05:31



与rebase相比有什么缺点?我发现一个更简单易用。 - Guillaume86
您不能以任意顺序加入 - 仅限 最后两次提交。 - dr0i
@ dr0i您可以根据需要合并任意数量的提交,只要它们是 最后的X提交, 而不是中间的某个地方。赶紧跑 git reset --soft HEAD~10,其中10是您要合并的提交数。 - bfred.it
如果您没有远程原点集,并且只有两个提交,则可以使用此选项。 - atedja
如果您不想计算有多少提交,您也可以重置为特定提交 HEAD通过使用 git reset --soft 47b5c5... 哪里 47b5c5... 是提交的SHA1 ID。 - dguay


首先,您应该检查您拥有的提交数量:

git log

有两种状态:

一个是有 只要 两个提交:

例如:

commit A
commit B

(在这种情况下,您不能使用git rebase)您需要执行以下操作。

$ git reset --soft HEAD^1

$ git commit --amend

另一个是有两个以上的提交;你想合并提交C和D.

例如:

commit A
commit B
commit C
commit D

(在这种情况下,你可以使用git rebase)

git rebase -i B

而不是用“壁球”来做。其余的很容易。如果您还不知道,请阅读 http://zerodie.github.io/blog/2012/01/19/git-rebase-i/ 


51
2018-05-27 19:01



重置--soft和commit --amend是唯一可行的方法,如果你已经有一个正在进行的rebase(并为这个提交选择'edit'而不是'squash')。 +1 - Jacek Lach
合并存储库中的第一个和第二个提交,完全是我的边缘情况:-) - Chris Huang-Leaver
请加上 git push -f origin master 可能是必要的。 - Rishabh Agrahari


Rebase:你不需要它:

对于最常见的场景,更简单的方法。

在多数情况下:

实际上,如果你想要的只是 只需将几个最近的提交合并为一个  但不需要 dropreword 和其他rebase工作。

你可以简单地做:

git reset --soft "HEAD~n"
  • 假设 ~n 是轻微不承诺的提交数量(即 ~1~2,...)

然后,使用以下命令修改提交消息。

git commit --amend

这是一个很长的范围 squash 一个 pick

并且它适用于n次提交但不仅仅是两次提交,如上面的答案提示。


50
2018-04-26 09:15



如果你想要除了压缩提交之外还要进行一些额外的清理,例如在中间删除1个提交或更改一行代码,这是很好的。 - styfle
假设 ~n 是轻微不承诺的提交数量(即 ~1, ~2,...) - Ray
如果我想不合并怎么办? n 最后提交,但是 n 在中间承诺?我可以轻松地做到这一点吗? - chumakoff
然后 git rebase -i 是你需要做的 squash 工作。 @chumakoff - pambda
YanTing_ThePanda, Then git rebase -i is what you need to do squash work,你能举例说明吗? n 在答案中提交中间?感谢您提出问题的最佳答案。 - Саша Черных


假设你在自己的主题分支。如果要将最后两个提交合并为一个并且看起来像英雄,请在最后两次提交之前分支提交。

git checkout -b temp_branch HEAD^2

然后squash在这个新分支中提交另一个分支:

git merge branch_with_two_commits --squash

这将带来变化,但不会提交。所以只需提交它们就可以了。

git commit -m "my message"

现在,您可以将此新主题分支合并回主分支。


26
2017-10-23 23:44



这对我来说实际上是最有用的答案,因为它不需要手动变基,而只是将整个分支的所有提交压缩成一个提交。非常好。 - Robert
谢谢你!这是如何使git做我的图片压缩提交在我脑海里! - Marjan Venema
惊人的答案,比替代品简单得多 - richardstartin
显然,这个答案不适合这种情况 a 和 c 需要合并并保持 b 原样。 - Talha Ashraf
最新版本的git有什么变化吗?当我尝试第一个命令时(git checkout -b combine-last-two-commits "HEAD^2")在git版本2.17中,我收到一个错误: fatal: 'HEAD^2' is not a commit and a branch 'combine-last-two-commits' cannot be created from it - mhucka


你可以取消rebase

git rebase --abort

当你再次运行交互式rebase命令时,'squash; commit必须低于列表中的pick commit


22
2018-04-01 20:59





我经常使用 git reset --mixed 要在多次提交之前恢复基本版本,然后我进行新的提交,这样可以让您的提交最新,确保您的版本在推送到服务器后是HEAD。

commit ac72a4308ba70cc42aace47509a5e
Author: <me@me.com>
Date:   Tue Jun 11 10:23:07 2013 +0500

    Added algorithms for Cosine-similarity

commit 77df2a40e53136c7a2d58fd847372
Author: <me@me.com>
Date:   Tue Jun 11 13:02:14 2013 -0700

    Set stage for similar objects

commit 249cf9392da197573a17c8426c282
Author: Ralph <ralph@me.com>
Date:   Thu Jun 13 16:44:12 2013 -0700

    Fixed a bug in space world automation

如果我想将两个提交合并为一个,首先我使用:

git reset --mixed 249cf9392da197573a17c8426c282

“249cf9392da197573a17c8426c282”是第三个版本,在你合并之前也是你的基础版本,之后,我做了一个新的提交:

git add .
git commit -m 'some commit message'

总而言之,希望是每个人的另一种方式。

仅供参考。来自 git reset --help

 --mixed
     Resets the index but not the working tree (i.e., the changed files are
     preserved but not marked for commit) and reports what has not been
     updated. This is the default action.

13
2017-09-09 02:48



我还没有读过'--mixed'的文档,但我确信其他人都会阅读帖子并想知道同样的事情:使用--mixed有什么好处?可能会改进您的帖子以包含手册页的摘要。 - funroll
@funroll我不知道 - 在我写这个答案之前,根据我自己的经验,非常混淆了 杂 操作将指定我作为参数传递的版本作为存储库HEAD版本,并且在该版本之后没有任何东西可以丢失,因此我们仍然可以处理这些更改。 - VinceStyling


$ git rebase --abort

如果要撤消git rebase,请随时运行此代码

$ git rebase -i HEAD~2

重新申请最后两次提交。上面的命令将打开代码编辑器

  • [ 最新的提交将在底部 ]。改变最后一个 承诺壁球。壁球将与之前的提交融合在一起。
  • 然后按esc键并键入:wq以保存并关闭

之后:wq你将处于活跃的rebase模式

注意:如果没有警告/错误消息,您将获得另一个编辑器,如果有错误或警告其他编辑器将不显示,您可以通过runnning中止 $ git rebase --abort 如果您看到错误或警告,则只需继续运行即可 $ git rebase --continue

您将看到2提交消息。选择一个或编写自己的提交消息,保存并退出[:wq]

笔记2: 如果运行rebase命令,则可能需要强制将更改推送到远程仓库

$ git push -f

$ git push -f origin master


10
2018-02-20 21:49



笔记2: git push -f origin/master 是缺少其他答案。 +1 - Rishabh Agrahari


如果你的主分支 git log 看起来像下面这样:

commit ac72a4308ba70cc42aace47509a5e
Author: <me@me.com>
Date:   Tue Jun 11 10:23:07 2013 +0500

    Added algorithms for Cosine-similarity

commit 77df2a40e53136c7a2d58fd847372
Author: <me@me.com>
Date:   Tue Jun 11 13:02:14 2013 -0700

    Set stage for similar objects

commit 249cf9392da197573a17c8426c282
Author: Ralph <ralph@me.com>
Date:   Thu Jun 13 16:44:12 2013 -0700

    Fixed a bug in space world automation

并且您想要合并前两个提交,只需执行以下简单步骤:

  1. 首先要安全地检查单独分支中的第二个最后提交。您可以将分支命名为任何名称。 git checkout 77df2a40e53136c7a2d58fd847372 -b merged-commits
  2. 现在,只需从最后一次提交中选择您的更改到这个新分支: git cherry-pick -n -x ac72a4308ba70cc42aace47509a5e。 (如果出现任何冲突,解决冲突)
  3. 所以现在,你最后一次提交的更改都在你的第二次提交中。但是你仍然必须提交,所以首先添加你刚刚挑选的更改,然后执行 git commit --amend

而已。如果您愿意,可以在分支“merged-commits”中推送此合并版本。

此外,您现在可以丢弃主分支中的背对背两次提交。只需将您的主分支更新为:

git checkout master
git reset --hard origin/master (CAUTION: This command will remove any local changes to your master branch)
git pull

1
2018-06-16 15:57