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

时间:2010-04-01 20:56:54

标签: git git-merge

我正在尝试将2个提交合并为1,因此我遵循了“squashing commits with rebase” from git ready

我跑了

git rebase --interactive HEAD~2

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

  

如果没有先前的提交,则无法“压缩”

现在我的工作树已达到这种状态,我无法恢复。命令git rebase --interactive HEAD~2失败并带有

  

交互式rebase已经开始

git rebase --continue失败

  

如果没有先前的提交,则无法“压缩”

13 个答案:

答案 0 :(得分:1650)

摘要

错误消息

  

如果没有先前的提交,则无法“压缩”

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

修复

首先回到你开始的地方

$ git rebase --abort

说出你的历史

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

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

(注意:在大多数平台上,默认情况下,运行git log将其输出通过管道传输到寻呼机less。要退出寻呼机并返回到命令提示符,请按{{1} }键。)

运行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. # 的输出相比,此待办事项列表的顺序相反。)

将b的git log更改为pick会导致您看到的错误,但是如果您改变todo列表,则将c压缩为b(较旧的提交到较旧的或“向上挤压”)

squash

并保存退出编辑器,你将得到另一个内容为

的编辑器
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

关于重写历史的注意事项

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

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

在您与其他人合作的分支机构上重写已发布的历史记录,而无需非常充分的理由,例如泄露密码或其他敏感信息,这会影响您的协作者,并且是反社会的,并且会烦恼其他开发者。 “Recovering From an Upstream Rebase” section in the git rebase documentation解释了这一点,并加以强调。

  

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

答案 1 :(得分:374)

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

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

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

答案 2 :(得分:82)

Rebase:你不需要它:

最常见情况的简单方法。

在大多数情况下:

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

你可以这样做:

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

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

git commit --amend

与远距离squashpick几乎相同。

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

答案 3 :(得分:52)

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

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/

答案 4 :(得分:28)

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

git checkout -b temp_branch HEAD^2

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

git merge branch_with_two_commits --squash

这将引入更改但不提交它们。所以只需提交它们就可以了。

git commit -m "my message"

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

答案 5 :(得分:22)

你可以用

取消rebase
git rebase --abort

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

答案 6 :(得分:16)

我经常使用 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.

答案 7 :(得分:11)

$ 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

答案 8 :(得分:2)

由于我使用git cherry-pick几乎所有东西,对我来说,即使在这里这样做也很自然。

鉴于我已经签出了branchX,并且在其顶端有两个提交,其中我想创建一个提交组合其内容,我这样做:

git checkout HEAD^ // Checkout the privious commit
git cherry-pick --no-commit branchX // Cherry pick the content of the second commit
git commit --amend // Create a new commit with their combined content

如果我想更新branchX(我认为这是此方法的缺点)我还必须:

git checkout branchX
git reset --hard <the_new_commit>

答案 9 :(得分:1)

如果您的主分支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
  4. 就是这样。如果您愿意,可以在分支“merged-commits”中推送此合并版本。

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

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

答案 10 :(得分:1)

如果您想要结合两个最近提交并只使用旧提交的消息,则可以使用expect自动执行该过程。

我假设:

  • 您正在使用vi作为编辑
  • 您的提交是一行

我使用git version 2.14.3 (Apple Git-98)进行了测试。

#!/usr/bin/env expect
spawn git rebase -i HEAD~2

# down, delete word, insert 's' (for squash), Escape, save and quit
send "jdwis \033:wq\r"

expect "# This is a"

# down 4, delete 3 lines, save and quit
send "4j3d\r:wq\r"

interact

答案 11 :(得分:0)

让我建议您采用一种更简单的方法,

您可以执行以下操作,而不是深入研究GIT的深入概念并烦扰编辑人员的螃蟹;

让我们假设您从master创建了一个名为bug1的分支。对bug1做出了2次提交。您仅修改了2个文件。

将这两个文件复制到文本编辑器中。结帐大师。粘贴文件。提交。

就这么简单。

答案 12 :(得分:0)

在完成所有操作后添加到@greg 的答案中,即压缩提交,如果您执行 git push(原始提交将保留在分支中),而如果您执行 git push -f origin,则提交将被删除。 例如-如果你执行 git push 你将提交 B 和提交 C 合并,你将有提交 B、提交 C 和提交 BC,但是如果你执行 git push -f origin 你将只有提交 BC

相关问题