我试图合并2个提交为1,所以我遵循“压缩提交与rebase”从git就绪。

我跑

git rebase --interactive HEAD~2

在结果编辑器中,我将pick更改为squash,然后save-quit,但由于出现错误,重基操作失败

没有之前的提交就不能“squash”

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

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

交互式改基已经开始

git rebase -continue失败

没有之前的提交就不能“squash”


当前回答

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

我认为:

您使用vi作为编辑器 每次提交只有一行

我用git版本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

其他回答

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

假设我签出了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>

总结

错误消息

没有之前的提交就不能“squash”

意味着你可能试图“向下挤压”。Git总是将一个新的提交压缩到一个旧的提交中,或者在交互的rebase todo列表中看到的“向上”,即压缩到前一行的提交中。将待办事项列表的第一行命令更改为“压缩”总是会产生这个错误,因为没有任何东西可以让第一个提交进行压缩。

修复

先回到你开始的地方

$ git rebase --abort

说你的历史

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

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

(注意:运行git日志将其输出输送到分页器,在大多数平台上默认情况较少。要退出寻呼机并返回命令提示符,请按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的选择更改为squash将导致您看到的错误,但如果相反,通过将todo列表更改为将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

关于重写历史的说明

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

如果你重基的分支是你自己工作的主题或特性分支,没有什么大不了的。推送到另一个存储库将需要——force选项,或者根据远程存储库的权限,您可以先删除旧的分支,然后再推送重新构建的版本。那些可能破坏工作的命令的示例超出了这个回答的范围。

在你和其他人一起工作的分支上重写已经发布的历史,而没有很好的理由,比如泄露密码或其他敏感细节,会迫使你的合作者承担工作,这是反社会的,会惹恼其他开发人员。git Rebase文档中的“从上游Rebase中恢复”部分解释了这一点,并增加了重点。

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

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

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/

你可以用

git rebase --abort

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

我经常使用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重置——帮助:

 --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.