ChatGPT解决这个技术问题 Extra ChatGPT

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

我正在尝试将 2 个提交合并为 1 个,所以我遵循了 “squashing commits with rebase” from git ready

我跑了

git rebase --interactive HEAD~2

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

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

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

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

交互式变基已经开始

git rebase --continue 失败

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

我也打这个。我的错误是由于 git rebase -i 以 git log 的相反顺序列出提交;最新的提交在底部!
在尝试疯狂的东西之前,我总是做一个备份分支。只希望它在生活中以这种方式工作;)

G
Greg Bacon

概括

错误信息

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

意味着您可能试图“向下挤压”。 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 的 pick 更改为 squash 将导致您看到的错误,但如果您通过将待办事项列表更改为

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

在没有非常充分理由(例如泄露密码或其他敏感细节)的情况下,在您与其他人合作的分支上重写已发布的历史记录会迫使您的合作者工作,并且是反社会的,并且会惹恼其他开发人员。 “Recovering From an Upstream Rebase” section in the git rebase documentation 进行了解释,并强调了这一点。

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


如果我使用 rebase 压缩提交,则会创建一个新的“组合”提交,其中包含两个变更集,但哈希值不同。 git也保留了原始提交吗?
@fabsenet 是的,也不是。原始提交仍然可以访问,但可能不再可以从任何 ref 访问(取决于您的历史细节)。未引用的提交最终会通过垃圾收集过程清除。
我只是在玩……我做了 git log hashoftheoldcommit 并且它起作用了,但我很想看到一个包含所有这些无法访问的提交的 git log --graph
这个壁球是在推送之前组织提交的好工具,但是如果我推送一个提交,我不能压缩它吗? git 说:成功地重新定位和更新了分离的 HEAD。
@Mithril git rebase --interactive HEAD~3,然后将 c 行移到 a 行下方。将 c 行的 pick 更改为 s,然后退出编辑器。
r
rogerdpack

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

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

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

与rebase相比有什么缺点?我发现使用起来要简单得多。
您不能以任意顺序加入 - 只有最后两次提交。
@dr0i 您可以合并任意数量的提交,只要它们是 最后 X 次提交, 而不是中间的某个地方。只需运行 git reset --soft HEAD~10,其中 10 是您要合并的提交数。
如果您没有设置远程源,并且您只有两次提交,则可以使用此方法。
如果您不想计算来自 HEAD 的数量,也可以使用 git reset --soft 47b5c5... 重置为特定的提交,其中 47b5c5... 是提交的 SHA1 ID。
A
Andrew Spencer

变基:你不需要它:

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

在大多数情况下:

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

你可以简单地做:

git reset --soft "HEAD~n"

假设 ~n 是软取消提交的提交数(即 ~1、~2、...)

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

git commit --amend

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

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


如果您除了压缩提交之外还想进行一些额外的清理,例如删除中间的 1 个提交或更改一行代码,这很好。
假设 ~n 是软取消提交的提交数(即 ~1~2、...)
如果我想合并的不是 n 个最后的提交,而是中间的 n 个提交,该怎么办?我可以轻松做到这一点吗?
那么 git rebase -i 就是您需要做的 squash 工作。 @chumakoff
因此,要将 n 个最近的提交合并为一个,首先使用 git reset --soft @~m,其中 m = n - 1
H
Haimei

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

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/


如果您已经有一个正在进行的变基(并且为此提交选择了“编辑”而不是“壁球”),则 reset --soft 和 commit --amend 是唯一有效的方法。 +1
合并存储库中的第一个也是唯一两个提交,这正是我的边缘情况:-)
请添加 git push -f origin master 可能是必要的。
s
smizzlov

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

git checkout -b temp_branch HEAD~2

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

git merge branch_with_two_commits --squash

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

git commit -m "my message"

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


这实际上对我来说是最有帮助的答案,因为它不需要手动变基,而只是将整个分支的所有提交压缩到一个提交中。非常好。
谢谢你!这就是如何让 git 像我想象的那样在我的脑海中压缩提交!
惊人的答案,比替代方案简单得多
显然,此答案不适用于 ac 需要合并在一起并保持 b 不变的情况。
最近版本的 git 有什么变化吗?当我在 git 版本 2.17 中尝试第一个命令 (git checkout -b combine-last-two-commits "HEAD^2") 时,出现错误:fatal: 'HEAD^2' is not a commit and a branch 'combine-last-two-commits' cannot be created from it
L
Leom Burke

你可以取消rebase

git rebase --abort

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


G
Gnanasekar S

$ 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


注意 2:git push -f origin/master 是缺少其他答案的内容。 +1
C
Christopher Bottoms

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

我还没有阅读“--mixed”的文档,但我相信其他人阅读了这篇文章并想知道同样的事情:使用--mixed 有什么好处?可能会改进您的帖子以包含手册页的片段。
@funroll在我写这个答案之前我不太了解--mixed,根据我自己的经验,混合操作会将我作为参数传递的指定版本作为存储库HEAD版本,并且在该版本之后不会丢失任何东西,所以我们仍然可以处理这些变化。
M
Martin G

由于我几乎将 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>

A
Alireza Rahmani khalili

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

git rebase 起源/开发 -i

然后,您只需在要压缩的提交前写一个“s”,然后将它们汇总到主提交中

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

导航到您要修改的提交行 (ESC) ciw -(更改内部单词)将更改光标下的整个单词。输入你想做的事情,例如 s 用于挤压 (ESC) wq 写得很清楚,你就完成了。

https://i.stack.imgur.com/xbFAM.gif

然后git push -f


U
Usman

如果您的主分支 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

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

首先要安全地检查单独分支中的倒数第二个提交。您可以将分支命名为任何名称。 git checkout 77df2a40e53136c7a2d58fd847372 -b merge-commits 现在,只需将上次提交中的更改挑选到这个新分支中:git cherry-pick -n -x ac72a4308ba70cc42aace47509a5e。 (如果出现任何冲突,请解决冲突)所以现在,您在最后一次提交中的更改存在于您的第二次最后提交中。但是你仍然必须提交,所以首先添加你刚刚挑选的更改,然后执行 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

P
Pavan kumar D

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


e
erwaman

如果您想合并两个最近的提交并仅使用旧提交的消息,您可以使用 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 我添加了更多评论。如果您仍然觉得它令人困惑,请告诉我,如果是,那是哪一部分。
目前还不清楚你的脚本做了什么。 expect 也未描述。
@buhtz 哪一部分不清楚?我提供了一个指向包含更多 expect 文档的页面的链接。
缺少脚本的一般描述。目前还不清楚它的作用。没有一个部分是不清楚的。剧本本身的意图尚不清楚。
y
yılmaz

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

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

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

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

就这么简单。