如果我已经开始重新设置基准,如何将两个提交合并为一个?


1157

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

我跑了

git rebase --interactive HEAD~2

在生成的编辑器中,我更改picksquash然后保存退出,但是重新设置失败并显示以下错误

没有先前的提交就无法“压扁”

现在我的工作树已达到此状态,我无法恢复。

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

交互式基础已经开始

git rebase --continue失败了

没有先前的提交就无法“压扁”


22
我也打了 我的错误是由于git rebase -i以与git log相反的顺序列出了提交而引起的;最新的提交在底部!
lmsurprenant 2014年


Answers:


1732

摘要

错误讯息

没有先前的提交就无法“压扁”

表示您可能试图“向下挤压”。在交互式rebase待办事项列表中,Git总是将较新的提交压缩为较旧的提交或“向上” 提交,即将其压缩为上一行的提交。将您的待办事项列表第一行上的命令更改为squash总是会产生此错误,因为第一次提交没有任何内容。

修复

首先回到开始的地方

$ git rebase --abort

说你的历史是

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

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

(注意:在大多数平台上git logless默认情况下,运行将其输出通过管道传递到寻呼机中。要退出该寻呼机并返回到命令提示符,请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将导致您看到的错误,但是如果改为将c压缩为b(较新的内容提交到较旧的或“向上挤压”),则将待办事项列表更改为

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选项,或者替代地,您可以根据远程存储库的权限,先删除旧分支,然后再推送重新建立基础的版本。这些可能破坏工作的命令示例不在此答案的范围内。

在一个分支中,你与其他人一起工作而无需重写已经发布的历史非常充分的理由,如泄露密码或其他敏感信息的力量工作到你的合作者,是反社会的,并会惹恼其他开发商。文档中“从上游基础恢复中”部分进行了git rebase说明,并重点强调。

对其他人基于其工作的分支重新建立基础(或进行任何其他形式的重写)是一个坏主意:该分支下游的任何人都必须手动修复其历史记录。本节从下游的角度说明如何进行修复。但是,真正的解决方法是首先避免对上游进行重新调整。


如果我使用rebase压缩提交,则会创建一个包含两个变更集的新“组合”提交,但哈希值却有所不同。git也保留了原始提交吗?
fabsenet 2013年

@fabsenet是和否。原始提交仍可访问,但可能无法从任何引用中获取(取决于您历史记录的详细信息)。未引用的提交最终会通过垃圾回收过程删除。
格雷格·培根

我只是在玩耍……我确实做到了git log hashoftheoldcommit,而且奏效了,但我很好奇看到其中git log --graph包含所有这些无法到达的提交
fabsenet 2013年

这个压榨是在推送之前组织提交的好工具,但是如果我推送一个提交,我不能压榨吗?git说:成功地重新建立了基础并更新了分离的HEAD。
塞焦,2015年

没有在第二个实例git bash上获得编辑器,似乎冻结到了某个进程中。该怎么办?

411

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

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

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

6
与调整基准相比有什么缺点?我发现使用起来简单得多。
Guillaume86

17
您不能以任意的顺序加入-只有最后两次提交
dr0i 2014年

50
@ dr0i您可以合并任意数量的提交,只要它们是最后的X个提交即可,而不是在中间。只需运行git reset --soft HEAD~10,其中10是要合并的提交数。
fregante

2
如果您没有远程源集,并且只有两个提交,则可以使用此方法。
edja

8
您也可以重置为特定承诺,如果你不想指望有多少来自HEAD使用git reset --soft 47b5c5...其中47b5c5...是提交的SHA1 ID。
dguay

112

重新设置:您将不需要它:

最常见情况的一种简单方法。

在多数情况下:

其实,如果你想要的是只是简单地结合近年来多次提交到一个 更不需要dropreword等底垫的工作。

您可以简单地执行以下操作:

git reset --soft "HEAD~n"
  • 假设~n是提交到数轻声未提交(即~1~2...)

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

git commit --amend

与远距离squash和一个几乎相同pick

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


3
如果您只想压缩提交内容(例如在中间删除1个提交内容或更改代码行),那么还可以进行其他一些清理工作,那就很好了。
styfle

1
假设~n是提交的轻声未提交(即数~1~2...)

1
如果我不希望合并n最后提交但要合并n在中间的怎么办?我可以轻松做到这一点吗?
chumakoff

1
然后git rebase -i就是您需要做的squash工作。@chumakoff
pambda

3
所以,加入n最近提交到一个,第一次使用git reset --soft @~m,在那里m = n - 1
卢卡斯Rajchel

55

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

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/


如果您已经在进行重新基准化(并且为此提交选择了“ edit”而不是“ squash”),则reset --soft和commit --amend是唯一可行的方法。+1
Jacek Lach

1
合并存储库中的第一个和唯一两个提交,正是我的特例:-)
Chris Huang-Leaver

1
请补充,这git push -f origin master可能是必要的。
Rishabh Agrahari'3

33

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

git checkout -b temp_branch HEAD^2

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

git merge branch_with_two_commits --squash

这将带来更改,但不会提交更改。因此,只需提交它们,您就完成了。

git commit -m "my message"

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


5
对于我来说,这实际上是最有用的答案,因为它不需要手动重新设置基准,而只是将整个分支的所有提交压缩为一个提交。非常好。
罗伯特

谢谢你!这就是让git做我如何想象挤在脑海里的提交的方法!
Marjan Venema'8

了不起的答案,比其他选择要简单得多

显然,这个答案是不适合的情况下a,并c需要将合并在一起,并保持b原样。
塔拉·阿什拉夫

2
最近版本的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

23

您可以使用取消取消基准

git rebase --abort

当您再次运行交互式rebase命令时,'squash; 提交必须在列表中的选择提交之下


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.

我还没有阅读'--mixed'的文档,但是我确定其他人也阅读了这篇文章,并想知道同一件事:使用--mixed有什么好处?可能会改善您的帖子,使其包含手册页的摘要。
funroll

@funroll我不知道-在我写这个答案之前,混合非常多,根据我自己的经验,混合操作将把我作为参数传递的指定版本作为存储库HEAD版本,在该版本之后不会丢失任何内容,因此我们仍然可以处理这些更改。
VinceStyling 2014年

14

$ git rebase --abort

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

$ git rebase -i HEAD~2

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

  • [ 最近的提交将在底部 ]。将最后一次提交更改为南瓜。由于壁球将与先前的提交融合。
  • 然后按Esc键并键入:wq以保存并关闭

:wq之后,您将进入活动的变基模式

注意:如果没有警告/错误消息,您将得到另一个编辑器;如果出现错误或警告其他编辑器将不会显示,$ git rebase --abort则如果您看到错误或警告,则可能会由于运行而中止, 否则请继续运行$ git rebase --continue

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

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

$ git push -f

$ git push -f origin master


1
注2:git push -f origin/master其他答案是否缺失。+1
Rishabh Agrahari

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>

1

如果您的master分支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分支中丢弃背对背的两次提交。只需将您的master分支更新为:

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

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

目前还不清楚脚本的作用。
布兹

@buhtz我添加了更多评论。让我知道您是否仍然感到困惑,如果是,那是哪一部分。
erwaman

现在还不清楚你的sc夫是做什么的。也expect未描述。
布兹

@buhtz哪一部分不清楚?我提供了指向页面的链接,其中包含有关的更多文档expect
erwaman

缺少脚本的一般说明。目前尚不清楚它的作用。没有一部分是不清楚的。脚本本身的意图尚不清楚。
buhtz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.