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

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

我跑了

git rebase --interactive HEAD~2

在结果编辑器中,我将pick改为squash ,然后保存退出,但是 rebase 失败并显示以下错误

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

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

交互式基础已经开始

git rebase --continue失败

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

答案

摘要

错误讯息

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

意味着您可能试图 “向下压缩。Git 总是将新提交压缩为较旧的提交或 “向上” 压缩,如在交互式 rebase 待办事项列表中所看到的那样,即转换为上一行的提交。将待办事项列表第一行上的命令更改为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 的pick更改为squash将导致您看到的错误,但是如果相反,您可以通过将 todo 列表更改为 b 将 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文档中“从上游基础恢复中” 部分进行了说明,并重点强调。

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

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

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

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

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

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

绝大多数情况下:

实际上,如果您只需要将几个最近的提交合并为一个即可,而无需dropreword和其他reword工作。

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

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

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

git commit --amend

这与squash和一picksquash几乎是一样的。

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

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

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/

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

git checkout -b temp_branch HEAD^2

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

git merge branch_with_two_commits --squash

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

git commit -m "my message"

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

您可以使用取消取消基准

git rebase --abort

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

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

$ 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

因为我几乎所有东西都使用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 (我想这是该方法的branchX ),我还必须:

git checkout branchX
git reset --hard <the_new_commit>

如果您的主分支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更改樱桃选择到该新分支中,即可: 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