1275

我正在尝试将 2 个提交合并为 1 个,因此我遵循了 git ready 中的“使用 rebase 压缩提交”

我跑了

git rebase --interactive HEAD~2

在生成的编辑器中,我更改picksquash然后保存退出,但变基失败并出现错误

没有先前的提交就不能“挤压”

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

该命令git rebase --interactive HEAD~2失败并显示:

交互式变基已经开始

git rebase --continue失败了

没有先前的提交就不能“挤压”

4

14 回答 14

1872

概括

错误信息

没有先前的提交就不能“挤压”

意味着您可能试图“向下挤压”。Git 总是将较新的提交压缩为较旧的提交或“向上”,如交互式变基待办事项列表中所见,即前一行的提交。将待办事项列表第一行上的命令更改为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.
#

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

将 b 更改picksquash将导致您看到的错误,但如果您通过将待办事项列表更改为

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

关于重写历史的注意事项

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

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

在没有很好的理由(例如泄露密码或其他敏感细节)的情况下,在与其他人合作的分支上重写已经发布的历史记录会迫使您的合作者工作,并且是反社会的,并且会惹恼其他开发人员。文档中的“从上游 Rebase 恢复”部分进行了git rebase解释,并特别强调了这一点。

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

于 2010-04-02T19:04:45.223 回答
468

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

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

git reset --soft "HEAD^"
git commit --amend
于 2014-07-11T05:31:04.467 回答
160

变基:你不需要它:

最常见情况的更简单方法。

大多数情况下:

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

你可以简单地做:

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

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

git commit --amend

squash这与一个长范围的和一个几乎相同pick

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

于 2017-04-26T09:15:19.547 回答
59

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

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/

于 2014-05-27T19:01:46.700 回答
43

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

git checkout -b temp_branch HEAD~2

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

git merge branch_with_two_commits --squash

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

git commit -m "my message"

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

于 2013-10-23T23:44:46.783 回答
25

你可以取消rebase

git rebase --abort

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

于 2010-04-01T20:59:48.203 回答
19

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

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

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.
于 2013-09-09T02:48:53.283 回答
18

$ git rebase --abort

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

$ git rebase -i HEAD~2

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

  • [最新的提交将在底部]。将最后一次提交更改为 squash(s)。由于 squash 将与先前的提交融合。
  • 然后按 esc 键并输入 :wq 保存并关闭

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

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

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

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

$ git push -f

$ git push -f origin master

于 2017-02-20T21:49:38.510 回答
4

因为我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>
于 2015-11-26T10:52:43.060 回答
4

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

  • git rebase origin/develop -i
  • 然后,您只需在要压缩的提交前写一个“s”,然后将它们汇总到主提交中

处于 git rebase-interactive 模式(vim)时的专业提示:

  1. 导航到您要修改的提交行
  2. (ESC) ciw- (更改内部单词)将更改光标下的整个单词。
  3. 输入你想做什么,例如s挤压
  4. (ESC)wq写得很清楚,大功告成。

在此处输入图像描述

然后git push -f

于 2021-10-13T13:16:05.867 回答
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.

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

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

git checkout master
git reset --hard origin/master (CAUTION: This command will remove any local changes to your master branch)
git pull
于 2013-06-16T15:57:34.210 回答
1

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

于 2021-05-07T07:50:52.497 回答
0

如果您想合并两个最近的提交并只使用旧提交的消息,您可以使用expect.

我假设:

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

我用git version 2.14.3 (Apple Git-98).


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

# change the second "pick" to "squash"
# down, delete word, insert 's' (for squash), Escape, save and quit
send "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 quit
send "4jdG\r:wq\r"

interact
于 2018-02-06T04:45:06.287 回答
0

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

您可以执行以下操作,而不是深入了解 GIT 的深层概念并为编辑的螃蟹而烦恼;

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

将这两个文件复制到文本编辑器中。收银员。粘贴文件。犯罪。

就这么简单。

于 2020-09-27T16:01:54.277 回答