题 撤消尚未推送的Git合并


在我的主分支中,我做了一个 git merge some-other-branch 本地,但从未将更改推送到原始主人。我不是故意合并,所以我想撤消它。做的时候 git status 合并后,我收到了这条消息:

# On branch master
# Your branch is ahead of 'origin/master' by 4 commits.

基于一些 我发现的说明,我试过跑步

git revert HEAD -m 1

但现在我收到了这条消息 git status

# On branch master
# Your branch is ahead of 'origin/master' by 5 commits.

我不希望我的分支机构通过任意数量的提交领先。我该如何回到这一点?


3088
2018-03-05 19:24


起源


如果您需要保留历史记录,换句话说,任何人都曾从您那里撤下或者您已将其推到某处使用Yuri Ushakov的解决方案,请在下面回答! - Sedrik
请取消选择当前获胜的答案,虽然仍在收集投票,​​但不安全(正如许多人指出的那样)。对我而言,“MBO”看起来最好,尽管它的分数较少。 - inger
如果你需要 保存历史, 使用 尤里下面的解决方案! (只需添加@Sedrik评论的链接) - cregox
有关: 恢复到之前的Git提交。
这是Github的一个很好的资源: 如何用Git撤消(几乎)任何东西 - jasonleonhard


答案:


git reflog 在合并之前检查哪个提交是一个(git reflog将是比git log更好的选项)。然后你可以使用以下方法重置它

git reset --hard commit_sha

还有另一种方式

git reset --hard HEAD~1

会让你回来1提交。

请注意,任何已修改和未提交/未缓存的文件都将重置为未修改状态。保持他们要么隐藏变化或看到 --merge 选项如下。


正如@Velmont在他的回答中所建议的那样,在这个直接案例中使用:

git reset --hard ORIG_HEAD

可能会产生更好的结果,因为它应该保留您的更改。 ORIG_HEAD 将在合并发生之前直接指向提交,因此您不必自己寻找它。


进一步的提示是使用 --merge 切换而不是 --hard 因为它不会不必要地重置文件:

- 合并

重置索引并更新工作树中<commit>和HEAD之间不同的文件,但保留索引和工作树之间不同的文件(即具有尚未添加的更改)。


3380
2018-03-05 19:34



我认为这不会(总是?)工作 - “合并之前的一个”将是从另一个分支合并的最新提交 - 它不会是当前分支上的最新提交。对? (这可能只是结果 git log 选择默认显示 - 也许有不同的输出 git log 要么 git reflog 可以用于此) - John Bachir
我认为这可能取决于你是否压缩合并。 - Marcin Gil
@JohnBachir是对的。在里面 git log 输出,你想看看两个父提交。一个是您的分支中的最新提交,一个是您合并到的分支中的最新提交。你想要 git reset --hard 到您合并到的分支上的父提交。 - Justin
@JohnBachir:只要“merge”不是真正的快进,就会产生一个位于日志顶部的新提交,并且这个提交有两个父级(如果你做一个章鱼,则超过2个)合并)。如果删除这个合并提交,那么从合并中提取的所有旧提交也将消失。但是为了安全起见,在重置git后会告诉你新头的位置:“HEAD现在位于88a04de <commit message>”。我总是这样看,以确保我最终达到了我预期的目标。我的项目使用标准的分支命名方案来保持令人难忘的状态。 - Mark E. Haase
我发现有用的是查看“git reflog”并查找我在master中执行的最后一次提交。然后做 git reset --hard <commit_sha> - Max Williams


假设您的本地主人不在原点/主人之前,您应该能够做到

git reset --hard origin/master

那你当地的 master 分支应该看起来相同 origin/master


1290
2018-03-17 18:06



@Carter它实际上不是最好的答案。某些提交可能是源/主服务器在合并之前可能位于本地主服务器之前,在这种情况下,这可能无法提供所需的结果 - Dhruva Sagar
@ dhruva-sagar是的,但是只要git没有说你落后了,而你没有取,你应该没事。 - Kelvin
谢谢!如果(并且仅当)您拥有远程存储库,这是完美的。 - tomc
不,这不是这个问题的完美问题,请参阅“假设”条款。 MBO的答案实际上涵盖了这种情况,以及合并不是唯一的本地提交的情况。 - inger
再一次,也许这个 警告 应该进入答案: 始终避免重写git历史记录! - cregox


看到 Git书中的第4章 和 Linus Torvalds的原帖

撤消合并 那已经被推了

git revert -m 1 commit_hash

如果你再次提交分支,请确保恢复恢复,如Linus所说。


1085
2018-06-02 16:31



^ - 这里唯一正确的答案如何在不破坏历史的情况下还原合并。如果您使用共享仓库,这一点很重要。 - Ruslan Kabalin
由于改变从未被推动过,因此没有被更多的投票,因此没有理由将意外合并添加到历史记录中。在本地擦除它并继续前进。 - Justin
恢复未被推送的提交在历史中看起来很丑陋并且使其更加混乱。如果你尚未推动它,那么将你的HEAD向后移动一些提交更有意义,那么推动。 - Mark E. Haase
“这还没有得到更多的支持,因为......” - 然而,对于像我这样的人来说这个问题,因为我们/已经/推动了额外的提交,这是非常宝贵的。 - perfectionist
@perfectionist同意:)有点希望有一种方法可以将这个答案迁移到另一个问题 - (也许有?) - mikermcneil


奇怪的是,最简单的命令丢失了。大多数答案都有效,但撤消了刚才的合并, 这是简单而安全的方式

git reset --merge ORIG_HEAD

裁判 ORIG_HEAD 将指向合并之前的原始提交。

(该 --merge 选项与合并无关。就像 git reset --hard ORIG_HEAD,但更安全,因为它不会触及未提交的更改。)


833
2018-01-29 15:46



是的,这是迄今为止最简单的方法。我想知道为什么与其他答案相比,它的票数如此之少。 - Pablo Olmos de Aguilera C.
如果你弄脏了你的工作树,那么, git reset --merge ORIG_HEAD 保留这些变化。 - yingted
这是我的答案。没必要 git reflog 或其他任何东西。谢谢。 - crmpicco
是的,最好的答案。这是stackoverflow投票系统如何基本上只奖励早期发布的答案的一个例子。 - samthebest
那么,这个答案是在被接受之后近三年来的;但我同意,这很有效! - Mike Branski


对于较新的Git版本,如果您还没有提交合并 你有一个合并冲突,你可以简单地做:

git merge --abort

man git merge

[此]只能在合并导致冲突后运行。 git merge --abort 将中止合并过程并尝试重建合并前状态。


307
2018-02-12 02:13





您应该重置为上一次提交。这应该工作:

git reset --hard HEAD^

甚至 HEAD^^ 还原该还原提交。如果您不确定应该采取多少步骤,则始终可以提供完整的SHA参考。

如果您遇到问题且主分支没有任何本地更改,您可以重置为 origin/master


104
2018-03-05 19:31



最好的答案恕我直言,包含OP自己的一个(假设只有一步还原,在Q中似乎就是这种情况),以及randomguy3的快捷方式(当你的主分支没有任何局部变化时有效) “) - inger
我完全同意这是最好的答案!!! - Konstantin
你是评论者,@ Inger和@Konstantin,为什么?在我的答案创建后你来到这里,它更正确。向上迈出一步通常是错误的,你必须实际计算你需要走多远。 Git已经确定了 ORIG_HEAD 为你,为什么不使用它? - odinho - Velmont
它会重置本地更改吗? #请更新。 - CoDe
这对我来说非常有效,重置头像这样比一半的答案更有意义。 - Varda Elentári


最近,我一直在使用 git reflog 帮助解决这个问题。这大部分仅在合并刚刚发生时才有效,并且它在你的机器上。

git reflog 可能会返回如下内容:

fbb0c0f HEAD@{0}: commit (merge): Merge branch 'master' into my-branch
43b6032 HEAD@{1}: checkout: moving from master to my-branch
e3753a7 HEAD@{2}: rebase finished: returning to refs/heads/master
e3753a7 HEAD@{3}: pull --rebase: checkout e3753a71d92b032034dcb299d2df2edc09b5830e
b41ea52 HEAD@{4}: reset: moving to HEAD^
8400a0f HEAD@{5}: rebase: aborting

第一行表示发生了合并。第二行是我合并之前的时间。我只是 git reset --hard 43b6032 强制此分支在合并之前进行跟踪,并随身携带。


78
2017-12-19 17:51



Omigosh生命保护:) - M.G.Palmer
天啊。非常感谢。 - Ross Henderson
为什么这不是我不知道的最佳答案。这非常有效。 - Matt
谢谢你,太棒了! - zooblin


使用现代Git,您可以:

git merge --abort

较旧的语法:

git reset --merge

老套:

git reset --hard

但实际上,值得注意的是 git merge --abort 只相当于 git reset --merge 鉴于 MERGE_HEAD 存在。这可以在Git help for merge命令中读取。

git merge --abort is equivalent to git reset --merge when MERGE_HEAD is present.

合并失败后,什么时候没有 MERGE_HEAD,失败的合并可以撤消 git reset --merge,但不一定是 git merge --abort所以他们不仅是同一件事的新旧语法

我个人觉得 git reset --merge 在日常工作中更加强大和有用,所以这是我一直使用的。


42
2018-05-08 19:13



对我来说很棒。其他所有帖子都说这太复杂了,但这完全符合预期。我认为这只会有效,因为存在冲突,这些冲突并不能完全回答原始问题。 - Jeremy
这个答案并没有关注OP的情况,而是留下了重要的背景。 - Ben Wheeler


好吧,这里给我的其他人的答案很接近,但是没有用。这就是我做的。

这样做......

git reset --hard HEAD^
git status

......给了我以下状态。

# On branch master
# Your branch and 'origin/master' have diverged,
# and have 3 and 3 different commit(s) each, respectively.

然后我不得不输入相同的内容 git reset 多次命令。每次我这样做,消息都会被改变,如下所示。

> git reset --hard HEAD^
HEAD is now at [...truncated...]
> git status
# On branch master
# Your branch and 'origin/master' have diverged,
# and have 3 and 3 different commit(s) each, respectively.
> git reset --hard HEAD^
HEAD is now at [...truncated...]
> git status
# On branch master
# Your branch and 'origin/master' have diverged,
# and have 2 and 3 different commit(s) each, respectively.
> git reset --hard HEAD^
HEAD is now at [...truncated...]
> git status
# On branch master
# Your branch and 'origin/master' have diverged,
# and have 1 and 3 different commit(s) each, respectively.
> git reset --hard HEAD^
HEAD is now at [...truncated...]
> git status
# On branch master
# Your branch is behind 'origin/master' by 3 commits, and can be fast-forwarded.

此时,我看到状态消息已更改,所以我尝试了一个 git pull,这似乎工作:

> git pull
Updating 2df6af4..12bbd2f
Fast forward
 app/views/truncated |    9 ++++++---
 app/views/truncated |   13 +++++++++++++
 app/views/truncated |    2 +-
 3 files changed, 20 insertions(+), 4 deletions(-)
> git status
# On branch master

长话短说,我的命令归结为:

git reset --hard HEAD^
git reset --hard HEAD^
git reset --hard HEAD^
git reset --hard HEAD^
git pull

32
2018-03-05 19:54



或者你可以使用 HEAD^^^^ - hasen
甚至可能重置为 origin/master ;) - hasen
哇!这工作了! - Yiğit Güler


你可以用 git reflog 找到以前的结帐。有时这是一个你想要回归的好状态。

具体而言,

$ git reflog
$ git reset --hard HEAD@{0}

21
2018-01-17 22:36



谢谢!你节省了半天的工作。但是我无法使用任何命令退出reflog模式。 - Katarzyna
@Katarzyna使用“q”键退出reflog - Amjed Baig