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

我试图将2个提交合并为1,所以我遵循了“用rebase压扁提交”从git就绪

我跑

git rebase --interactive HEAD~2

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

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

现在我的工作树已经达到这种状态,我很难恢复。

命令git rebase --interactive HEAD~2失败:

交互式rebase已经开始

git rebase --continue失败

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

1005846 次浏览

您可以通过以下方式取消重新定位

git rebase --abort

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

总结

错误信息

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

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

The Fix

先回到你开始的地方

$ git rebase --abort

说你的历史是

$ git log --pretty=onelinea931ac7c808e2471b22b5bd20f0cad046b1c5d0d cb76d157d507e819d7511132bdb5a80dd421d854f bdf239176e1a2ffac927d8b496ea00d5488481db5 a

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

(注意:在大多数平台上,默认情况下,运行git log将其输出通过管道传输到分页器,less。要退出分页器并返回您的命令提示符,请按q键。)

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

pick b76d157 bpick 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.#

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

将b的pick更改为squash将导致您看到的错误,但如果您通过将待办事项列表更改为将c压缩到b(较新的提交到较旧的或“向上挤压”)

pick   b76d157 bsquash 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=oneline18fd73d3ce748f2a58d1b566c03dd9dafe0b6b4f b and cdf239176e1a2ffac927d8b496ea00d5488481db5 a

关于重写历史的说明

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

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

重写分支上已经发布的历史记录,如果你在没有非常充分理由的情况下与其他人一起工作,比如泄露密码或其他敏感细节,会迫使你的合作者工作,并且是反社会的,会惹恼其他开发人员。#0留档中的“从上游重定位恢复”部分解释了,并增加了强调。

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

如果您的主分支git log看起来像以下内容:

commit ac72a4308ba70cc42aace47509a5eAuthor: <me@me.com>Date:   Tue Jun 11 10:23:07 2013 +0500
Added algorithms for Cosine-similarity
commit 77df2a40e53136c7a2d58fd847372Author: <me@me.com>Date:   Tue Jun 11 13:02:14 2013 -0700
Set stage for similar objects
commit 249cf9392da197573a17c8426c282Author: 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

就是这样。如果你愿意,你可以在分支“合并提交”中推送这个合并版本。

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

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

我经常使用git重置-混合在你要合并的多个提交之前恢复一个基本版本,然后我做一个新的提交,这样可以让你的提交最新,确保你的版本在你推送到服务器后是HEAD。

commit ac72a4308ba70cc42aace47509a5eAuthor: <me@me.com>Date:   Tue Jun 11 10:23:07 2013 +0500
Added algorithms for Cosine-similarity
commit 77df2a40e53136c7a2d58fd847372Author: <me@me.com>Date:   Tue Jun 11 13:02:14 2013 -0700
Set stage for similar objects
commit 249cf9392da197573a17c8426c282Author: 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

 --mixedResets the index but not the working tree (i.e., the changed files arepreserved but not marked for commit) and reports what has not beenupdated. This is the default action.

假设您在自己的主题分支中。如果您想将最后2次提交合并为一次并看起来像英雄,请在进行最后两次提交之前分支提交(使用相对提交名称HEAD~2指定)。

git checkout -b temp_branch HEAD~2

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

git merge branch_with_two_commits --squash

这会带来变化,但不会提交它们。所以只要提交它们,你就完成了。

git commit -m "my message"

现在您可以将这个新的主题分支合并回您的主分支。

首先,您应该检查您有多少提交:

git log

有两种状态:

一个是有只有两个提交:

例如:

commit Acommit B

(在这种情况下,你不能使用git rebase来做)你需要做以下事情。

$ git reset --soft HEAD^1
$ git commit --amend

另一个原因是有两个以上的提交;您想合并提交C和D。

例如:

commit Acommit Bcommit Ccommit D

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

git rebase -i B

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

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

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

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

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

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

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

如果我也想更新branchX(我想这是这个方法的缺点),我还必须:

git checkout branchXgit reset --hard <the_new_commit>

$ git rebase --abort

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

$ git rebase -i HEAD~2

重新应用最后两次提交。上面的命令将打开一个代码编辑器

  • [最新的提交将在底部]。更改最后一个提交到squash(s)。因为squash会与之前的提交融合。
  • 然后按esc键并键入:wq保存并关闭

在:wq之后,您将处于活动rebase模式

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

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

注2:如果您运行rebase命令,您可能需要强制将更改推送到远程存储库

$ git push -f

$ git push -f origin master

Rebase:你不需要它:

对于最常见的场景,这是一种更简单的方法。

在大多数情况下:

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

你可以简单地做:

git reset --soft "HEAD~n"
  • 假设~n是软取消提交的提交数(即~1~2、…)

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

git commit --amend

这与squash和1pick的长范围几乎相同。

它适用于n次提交,而不仅仅是上面提示的两次提交。

如果您想合并两个最近的提交并仅使用旧提交的消息,您可以使用#0自动化该过程。

我假设:

  • 你正在使用vi作为你的编辑器
  • 你们的提交都是单行的

我测试了git version 2.14.3 (Apple Git-98)


#!/usr/bin/env expectspawn git rebase -i HEAD~2
# change the second "pick" to "squash"# down, delete word, insert 's' (for squash), Escape, save and quitsend "jdwis \033:wq\r"
expect "# This is a"
# skip past first commit message (assumed to be one line), delete rest of file# down 4, delete remaining lines, save and quitsend "4jdG\r:wq\r"
interact

让我建议你一个更简单的方法,

你可以做以下事情,而不是陷入GIT的深层推理和困扰编辑的螃蟹;

假设您从master创建了一个名为bug1的分支。对bug1进行了2次提交。您只修改了2个文件进行了这些更改。

将这两个文件复制到文本编辑器中。签出主机。粘贴文件。提交。

就这么简单。

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

如果你有几个提交想要压缩在一起,你可以使用交互式rebase方法来完成。(感谢Mads教我这方面的知识!)

  • git rebase origin/develop -i
  • 然后你只需写一个's'在前面的提交你想压扁并有他们卷到主提交

在git rebase交互模式(vim)下的专业提示:

  1. 导航到您要修改的提交行
  2. (ESC)ciw-(更改内部单词)将更改光标下的整个单词。
  3. 键入你想做的事情,例如s用于压扁
  4. (ESC)wq写得相当,你就完成了。

输入图片描述

然后git push -f