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

发布于 2024-08-27 14:22:09 字数 603 浏览 6 评论 0原文

我试图将 2 个提交合并为 1 个,所以我遵循 “使用 rebase 压缩提交”来自 git read

git rebase --interactive HEAD~2

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

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

现在我的工作树已达到此状态,我在恢复时遇到了困难。

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

交互式变基已开始

git rebase --continue 失败并显示

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

I am trying to merge 2 commits into 1, so I followed “squashing commits with rebase” from git ready.

I ran

git rebase --interactive HEAD~2

In the resulting editor, I change pick to squash and then save-quit, but the rebase fails with the error

Cannot 'squash' without a previous commit

Now that my work tree has reached this state, I’m having trouble recovering.

The command git rebase --interactive HEAD~2 fails with:

Interactive rebase already started

and git rebase --continue fails with

Cannot 'squash' without a previous commit

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

迷迭香的记忆 2024-09-03 14:22:09

摘要

错误信息

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

意味着您可能试图“向下挤压”。 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 key。)

运行 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 将导致您看到的错误,但如果您将 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 恢复”部分 解释道,并强调了这一点。

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

Summary

The error message

Cannot 'squash' without a previous commit

means you likely attempted to “squash downward.” Git always squashes a newer commit into an older commit or “upward” as viewed on the interactive rebase todo list, that is into a commit on a previous line. Changing the command on your todo list’s very first line to squash will always produce this error as there is nothing for the first commit to squash into.

The Fix

First get back to where you started with

$ git rebase --abort

Say your history is

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

That is, a was the first commit, then b, and finally c. After committing c we decide to squash b and c together:

(Note: Running git log pipes its output into a pager, less by default on most platforms. To quit the pager and return to your command prompt, press the q key.)

Running git rebase --interactive HEAD~2 gives you an editor with

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

(Notice that this todo list is in the reverse order as compared with the output of git log.)

Changing b’s pick to squash will result in the error you saw, but if instead you squash c into b (newer commit into the older or “squashing upward”) by changing the todo list to

pick   b76d157 b
squash a931ac7 c

and save-quitting your editor, you'll get another editor whose contents are

# This is a combination of 2 commits.
# The first commit's message is:

b

# This is the 2nd commit message:

c

When you save and quit, the contents of the edited file become commit message of the new combined commit:

$ git log --pretty=oneline
18fd73d3ce748f2a58d1b566c03dd9dafe0b6b4f b and c
df239176e1a2ffac927d8b496ea00d5488481db5 a

Note About Rewriting History

Interactive rebase rewrites history. Attempting to push to a remote that contains the old history will fail because it is not a fast-forward.

If the branch you rebased is a topic or feature branch in which you are working by yourself, no big deal. Pushing to another repository will require the --force option, or alternatively you may be able, depending on the remote repository’s permissions, to first delete the old branch and then push the rebased version. Examples of those commands that will potentially destroy work is outside the scope of this answer.

Rewriting already-published history on a branch in which you are working with other people without very good reason such as leaking a password or other sensitive details forces work onto your collaborators and is antisocial and will annoy other developers. The “Recovering From an Upstream Rebase” section in the git rebase documentation explains, with added emphasis.

Rebasing (or any other form of rewriting) a branch that others have based work on is a bad idea: anyone downstream of it is forced to manually fix their history. This section explains how to do the fix from the downstream’s point of view. The real fix, however, would be to avoid rebasing the upstream in the first place.

失与倦" 2024-09-03 14:22:09

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

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

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

If there are multiple commits, you can use git rebase -i to squash two commits into one.

If there are only two commits you want to merge, and they are the "most recent two", the following commands can be used to combine the two commits into one:

git reset --soft "HEAD^"
git commit --amend
江挽川 2024-09-03 14:22:09

Rebase:你不需要它:

针对最常见场景的更简单的方法。

在大多数情况下:

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

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

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

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

git commit --amend

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

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

Rebase: You Ain't Gonna Need It:

A simpler way for most frequent scenario.

In most cases:

Actually if all you want is just simply combine several recent commits into one but do not need drop, reword and other rebase work.

you can simply do:

git reset --soft "HEAD~n"
  • Assuming ~n is number of commits to softly un-commit (i.e. ~1, ~2,...)

Then, use following command to modify the commit message.

git commit --amend

which is pretty much the same as a long range of squash and one pick.

And it works for n commits but not just two commits as above answer prompted.

清晨说晚安 2024-09-03 14:22:09

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

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

而不是使用“squash”来做。剩下的瘦身就很容易了。如果你还不知道,请阅读 http://zerodie.github.io /博客/2012/01/19/git-rebase-i/

First you should check how many commits you have:

git log

There are two status:

One is that there are only two commits:

For example:

commit A
commit B

(In this case, you can't use git rebase to do) you need to do following.

$ git reset --soft HEAD^1

$ git commit --amend

Another is that there are more than two commits; you want to merge commit C and D.

For example:

commit A
commit B
commit C
commit D

(under this condition, you can use git rebase)

git rebase -i B

And than use "squash" to do. The rest thins is very easy. If you still don't know, please read http://zerodie.github.io/blog/2012/01/19/git-rebase-i/

放血 2024-09-03 14:22:09

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

git checkout -b temp_branch HEAD~2

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

git merge branch_with_two_commits --squash

这将引入更改但不提交它们。因此,只需提交它们即可。

git commit -m "my message"

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

Assuming you were in your own topic branch. If you want to merge the last 2 commits into one and look like a hero, branch off the commit just before you made the last two commits (specified with the relative commit name HEAD~2).

git checkout -b temp_branch HEAD~2

Then squash commit the other branch in this new branch:

git merge branch_with_two_commits --squash

That will bring in the changes but not commit them. So just commit them and you're done.

git commit -m "my message"

Now you can merge this new topic branch back into your main branch.

狂之美人 2024-09-03 14:22:09

取消变基

git rebase --abort

您可以使用'squash; ,并且当您再次运行交互式变基命令时提交必须位于列表中选择提交的下方

you can cancel the rebase with

git rebase --abort

and when you run the interactive rebase command again the 'squash; commit must be below the pick commit in the list

冷了相思 2024-09-03 14:22:09

$ 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 rebase --abort

Run this code at any time if you want to undo the git rebase

$ git rebase -i HEAD~2

To reapply last two commits. The above command will open a code editor

  • [ The latest commit will be at the bottom ]. Change the last
    commit to squash(s). Since squash will meld with previous commit.
  • Then press esc key and type :wq to save and close

After :wq you will be in active rebase mode

Note: You'll get another editor if no warning/error messages, If there is an error or warning another editor will not show, you may abort by runnning
$ git rebase --abort if you see an error or warning else just continue by running $ git rebase --continue

You will see your 2 commit message. Choose one or write your own commit message, save and quit [:wq]

Note 2: You may need to force push your changes to the remote repo if you run rebase command

$ git push -f

$ git push -f origin master

坚持沉默 2024-09-03 14:22:09

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

commit ac72a4308ba70cc42aace47509a5e
Author: <[email protected]>
Date:   Tue Jun 11 10:23:07 2013 +0500

    Added algorithms for Cosine-similarity

commit 77df2a40e53136c7a2d58fd847372
Author: <[email protected]>
Date:   Tue Jun 11 13:02:14 2013 -0700

    Set stage for similar objects

commit 249cf9392da197573a17c8426c282
Author: Ralph <[email protected]>
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.

I often use git reset --mixed to revert a base version before multiple commits which you want to merge, then I make a new commit, that way could let your commit newest, assure your version is HEAD after you push to server.

commit ac72a4308ba70cc42aace47509a5e
Author: <[email protected]>
Date:   Tue Jun 11 10:23:07 2013 +0500

    Added algorithms for Cosine-similarity

commit 77df2a40e53136c7a2d58fd847372
Author: <[email protected]>
Date:   Tue Jun 11 13:02:14 2013 -0700

    Set stage for similar objects

commit 249cf9392da197573a17c8426c282
Author: Ralph <[email protected]>
Date:   Thu Jun 13 16:44:12 2013 -0700

    Fixed a bug in space world automation

If I want to merge head two commits into one, first I use :

git reset --mixed 249cf9392da197573a17c8426c282

"249cf9392da197573a17c8426c282" was third version, also is your base version before you merge, after that, I make a new commit :

git add .
git commit -m 'some commit message'

It's all, hope is another way for everybody.

FYI, from 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.
这个俗人 2024-09-03 14:22:09

如果您想将多个提交压缩在一起,则可以使用交互式变基方法来实现。 (感谢 Mads 教我这一点!)

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

在 git rebase-interactive 模式 (vim) 下的专业提示:

  1. 导航到您想要修改的提交行
  2. (ESC) ciw - (更改内部单词)将更改光标下的整个单词。
  3. 输入您想要执行的操作,例如 s 表示挤压
  4. (ESC) wq 写得很安静,您就完成了。

输入图像描述这里

然后git push -f

If you have several commits you'd like to squash together, you can do so using the interactive rebase method. (Thanks Mads for teaching me about this!)

  • git rebase origin/develop -i
  • Then you simply write an 's' in front of the commits you would like to squash and have them roll up into the main commit

Pro-tip when in git rebase-interactive mode (vim):

  1. Navigate to commit line you would like to amend
  2. (ESC) ciw - (change inner word) will change the whole word under the cursor.
  3. Type what you wanna do, e.g. s for squashing
  4. (ESC) wq write quite, you are done.

enter image description here

then git push -f

诠释孤独 2024-09-03 14:22:09

由于我几乎所有事情都使用 gitcherry-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>

Since I use git cherry-pick for just about everything, to me it comes natural to do so even here.

Given that I have branchX checked out and there are two commits at the tip of it, of which I want to create one commit combining their content, I do this:

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

If i want to update branchX as well (and I suppose this is the down side of this method) I also have to:

git checkout branchX
git reset --hard <the_new_commit>
红玫瑰 2024-09-03 14:22:09

如果您的主分支 git log 看起来如下所示:

commit ac72a4308ba70cc42aace47509a5e
Author: <[email protected]>
Date:   Tue Jun 11 10:23:07 2013 +0500

    Added algorithms for Cosine-similarity

commit 77df2a40e53136c7a2d58fd847372
Author: <[email protected]>
Date:   Tue Jun 11 13:02:14 2013 -0700

    Set stage for similar objects

commit 249cf9392da197573a17c8426c282
Author: Ralph <[email protected]>
Date:   Thu Jun 13 16:44:12 2013 -0700

    Fixed a bug in space world automation

并且您想要合并前两个提交,只需执行以下简单步骤:

  1. 首先为了安全起见,在单独的分支中签出倒数第二个提交。您可以为分支命名任何名称。 git checkout 77df2a40e53136c7a2d58fd847372 -b merged-commits
  2. 现在,只需将上次提交中的更改挑选到这个新分支中,如下所示:gitcherry-pick -n -x ac72a4308ba70cc42aace47509a5e。 (如果出现任何冲突,请解决)
  3. 所以现在,您上次提交中的更改将出现在倒数第二次提交中。但您仍然必须提交,因此首先添加您刚刚挑选的更改,然后执行 git commit --amend 。

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

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

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

If your master branch git log looks something like following:

commit ac72a4308ba70cc42aace47509a5e
Author: <[email protected]>
Date:   Tue Jun 11 10:23:07 2013 +0500

    Added algorithms for Cosine-similarity

commit 77df2a40e53136c7a2d58fd847372
Author: <[email protected]>
Date:   Tue Jun 11 13:02:14 2013 -0700

    Set stage for similar objects

commit 249cf9392da197573a17c8426c282
Author: Ralph <[email protected]>
Date:   Thu Jun 13 16:44:12 2013 -0700

    Fixed a bug in space world automation

and you want to merge the top two commits just do following easy steps:

  1. First to be on safe side checkout the second last commit in a separate branch. You can name the branch anything. git checkout 77df2a40e53136c7a2d58fd847372 -b merged-commits
  2. Now, just cherry-pick your changes from the last commit into this new branch as: git cherry-pick -n -x ac72a4308ba70cc42aace47509a5e. (Resolve conflicts if arise any)
  3. So now, your changes in last commit are there in your second last commit. But you still have to commit, so first add the changes you just cherry-picked and then execute git commit --amend.

That's it. You may push this merged version in branch "merged-commits" if you like.

Also, you can discard the back-to-back two commits in your master branch now. Just update your master branch as:

git checkout master
git reset --hard origin/master (CAUTION: This command will remove any local changes to your master branch)
git pull
半窗疏影 2024-09-03 14:22:09

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

To add to @greg's answer after you are done with everything i.e. squashing the commits, if you do git push (the original commits will remain in the branch) whereas if you do git push -f origin the commits will be deleted.
Eg- you combined commit B and commit C if you do git push you will have commit B, commit C and commit BC, but if you do git push -f origin you will only have commit BC

智商已欠费 2024-09-03 14:22:09

好的,

  1. 首先,git rebase -i HEAD~2
  2. 现在选择旧提交并压缩最新提交。保存并关闭窗口。
  3. 然后会出现一个新的提交消息窗口,从那里删除所有内容,只添加您想要的提交消息。保存并关闭窗口。
  4. 现在要推送 git push origin -f YOUR-BRANCH-NAME-WHERE-YOU-WANT-TO-PUSH
  5. 现在再次检查,您现在应该有单个提交。

Okay, So

  1. firstly, git rebase -i HEAD~2.
  2. now pick the old commit and squash the latest commit. Save and close the window.
  3. then a new window for commit message will appear remove everything from there and only add the commit message you want. Save and close the window.
  4. now to push do git push origin -f YOUR-BRANCH-NAME-WHERE-YOU-WANT-TO-PUSH
  5. Now check again, you should now have single commit.
无人接听 2024-09-03 14:22:09

如果您想合并两个最近的提交并仅使用较旧的提交消息,您可以使用 < 自动化该过程代码>期望

我假设:

  • 您使用 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

If you want to combine the two most recent commits and just use the older commit's message, you can automate the process using expect.

I assume:

  • You're using vi as your editor
  • Your commits are one-line each

I tested with 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
淡淡離愁欲言轉身 2024-09-03 14:22:09

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

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

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

将这两个文件复制到文本编辑器中。结账师傅。粘贴文件。犯罪。

就这么简单。

Let me suggest you an easier approach,

Instead of divind into GIT's deep consepts and bothering with the editor's crab, you could do the following;

Lets suppose you created a branch named bug1 from master. Made 2 commits to bug1. You only modified 2 files with these changes.

Copy these two files into a text editor. Checkout master. Paste the files. Commit.

That simple.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文