撤消尚未推送的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.
我不希望我的分支通过任何数量的提交领先.我该如何回到那一点?
回答
随着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
因为它不会不必要地重置文件:
git reset --merge ORIG_HEAD
git reset --merge ORIG_HEAD
git reset --merge ORIG_HEAD
重置索引并更新工作树中<commit>和HEAD之间不同的文件,但保留索引和工作树之间不同的文件(即哪些文件尚未添加更改).
- 我不认为这会(总是?)工作 - "合并之前的一个"将是从另一个分支合并的最新提交 - 它不会是当前分支上的最新提交.对?(这可能只是'git log`默认选择显示的结果 - 也许有一个不同的输出`git log`或`git reflog`可用于此)
- 我发现有用的是查看"git reflog"并查找我在master中执行的最后一次提交.然后做`git reset --hard <commit_sha>`
- @JohnBachir是对的.在`git log`输出中,您要查看两个父提交.一个是您的分支中的最新提交,一个是您合并到的分支中的最新提交.你想`git reset --hard`到你合并的分支上的父提交.
- @JohnBachir:只要"merge"不是真正的快进,就会产生一个位于日志顶部的新提交,并且这个提交有两个父母(如果你做一个章鱼,则超过2个)合并).如果删除这一个合并提交,那么从合并中进入的所有旧提交也将消失.但是为了安全起见,在重置git后会告诉你新头的位置:"HEAD现在位于88a04de <commit message>".我总是看着它,以确保我最终达到了我预期的目标.我的项目使用标准的分支命名方案来保持令人难忘的状态.
- 我认为这可能取决于你是否压缩合并.
- 您也可以执行`git reset --hard origin/master`而不是指定commit sha.
- 也许这个**警告**应该进入答案本身:[***总是避免重写git历史!***](http://stackoverflow.com/questions/1491001/what-are-the-practical-consequences -of重写-git的历史)
- @MarcinGil ORIG_HEAD至少在2009年存在:)这是5年前.
- `git reset --hard`除了回溯历史之外,还将不可逆转地丢弃任何本地修改.`git reset --keep`重置历史记录,同时保留本地更改(如果有的话)更安全.
- @skypecakes:好吧,我认为如果有人想做“撤消”操作,则有人希望某些更改会被恢复/丢失。无论如何,我对这种情况感到很好奇,如果丢失更改,如何执行重置。仅应删除合并提交本身,仅此而已。
- 这是直接来自 Github 的一个很好的资源:[如何使用 Git 撤消 (几乎) 任何事情](https://github.com/blog/2019-how-to-undo-almost-anything-with-git)
假设您的本地主人不在原点/主人之前,您应该能够做到
git reset --hard origin/master
然后你的本地master
分支应该看起来相同origin/master
.
- @Carter它实际上不是最好的答案.某些提交可能是源/主服务器在合并之前可能位于本地主服务器之前,在这种情况下,这可能无法提供所需的结果
- @ dhruva-sagar是的,但是只要git没有说你落后了,而你没有取,你应该没事.
- 谢谢!如果(并且仅当)您拥有远程存储库,这是完美的.
- 不,这不是这个问题的完美之处,请参阅"假设"条款.MBO的答案实际上涵盖了这种情况,以及合并不是唯一的本地提交的情况.
- 也许这个**警告**应该进入答案本身:[***总是避免重写git历史!***](http://stackoverflow.com/questions/1491001/what-are-the-实事求是的后果-的改写 - git的历史)
见第4章在Git的书,并在原来的职位由Linus Torvalds.
要撤消已推送的合并:
git revert -m 1 commit_hash
如果你再次提交分支,请确保恢复恢复,如Linus所说.
- @perfectionist同意:)希望有一种方法可以将这个答案迁移到另一个问题 - (也许有?)
- 请注意**这确实*不*实际上解决了原始海报的问题**.原来的海报***已经***使用了`git revert -m 1 <commit>`.问题在于,这样做并没有消除他所做的意外合并(并且还没有推动).涉及硬重置的其他答案对于原始海报的问题更好.
- 为了确信此还原已成功,您可以执行 **git diff hash1 hash2** 其中 hash1 是已提交的还原,而 hash2 是您试图返回其状态的旧提交。没有输出==成功!通过多次执行此操作,我能够回滚多个提交,首先是恢复最近的合并并向后工作。**git diff** 向我展示了我最终达到了我想要的状态。
奇怪的是,最简单的命令丢失了.大多数答案都有效,但撤消刚刚进行的合并,这是一种简单而安全的方法:
ref ORIG_HEAD
将指向合并之前的原始提交.
(该--merge
选项与合并无关.它就像git reset --hard ORIG_HEAD
,但更安全,因为它不会触及未提交的更改.)
- 如果你弄脏了你的工作树,那么`git reset --merge ORIG_HEAD`会保留这些变化.
- 这是*唯一*的正确答案(我不是说这是最好的答案——注意区别)。假设,在 master 上,我在 t1、t3 和 t5 处进行了 3 次提交。假设在 branch1 上,我在 t2、t4 和 t6 处做了 3 条评论(假设 t1、t2、t3、t4、t5 和 t6 按时间顺序排列)。任何类似于 `git reset --hard HEAD~5` 的命令只会重置 HEAD(可能会删除 master 和 branch1 中的提交)。只有`--merge` 选项会删除`merge`。
对于较新的Git版本,如果您还没有提交合并并且您有合并冲突,您可以简单地执行:
git merge --abort
git merge --abort
git merge --abort
来自man git merge
:
- 他的合并已提交但未推送(见标题),他已经合并,您的命令仅在他仍在合并中时才起作用
您应该重置为上一次提交.这应该工作:
git reset --hard HEAD^
甚至HEAD^^
还原恢复提交.如果您不确定应该采取多少步骤,则可以随时提供完整的SHA参考.
如果您遇到问题且主分支没有任何本地更改,您可以重置为origin/master
.
- 最好的答案恕我直言,包含OP自己的一个(假设只有一步还原,在Q中似乎就是这种情况),以及randomguy3的快捷方式(当你的主分支没有任何局部变化时有效) ")
- 你是评论者,@ Inger和@Konstantin,为什么?在我的答案创建后你来到这里,它更正确.向上迈出一步通常是错误的,你必须实际计算你需要走多远.Git已经为你设置了'ORIG_HEAD`,为什么不使用它?
最近,我一直在用它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
强迫这个分支在合并之前进行跟踪,并随身携带.
使用现代Git,您可以:
较旧的语法:
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
它在日常工作中更加强大和有用,所以这就是我经常使用的.
好吧,这里给我的其他人的答案很接近,但是没有用.这就是我做的.
这样做......
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
- 或者你可以使用`HEAD ^^^^`
- 甚至可能重置为`origin/master`;)
它可以通过多种方式完成。
1) 中止合并
如果您处于错误合并之间(错误地使用错误的分支完成),并且希望避免合并返回最新的分支,如下所示:
2) 将 HEAD 重置为远程分支
如果您从远程开发分支工作,您可以将 HEAD 重置为远程分支上的最后一次提交,如下所示:
git reset --hard origin/develop
3) 删除当前分支,再从远程仓库checkout
考虑到您正在本地仓库中开发分支,与远程/开发分支同步,您可以执行以下操作:
git checkout master
##to delete one branch, you need to be on another branch, otherwise you will fall with the branch :)
git branch -D develop
git checkout -b develop origin/develop
- Be careful! git merge --abort "can only be run after the merge has resulted in conflicts. git merge --abort will abort the merge process and try to reconstruct the pre-merge state"
您可以git reflog
用来查找之前的结帐.有时这是一个你想要回归的好状态.
具体而言,
$ git reflog
$ git reset --hard HEAD@{0}
如果您正在合并中,可以随时中止合并
git merge --abort
- 谢谢兄弟,我正要做那个可怕的东西正确的答案。幸运的是我向下滚动。我只想删除合并头
如果分支被合并而不被推送,那么下面给出的 git reset 命令将用于撤消合并:
如果你还没提交,你只能使用
$ git checkout -f
它将撤消合并(以及您所做的一切).
得到这个问题也希望恢复匹配原点(即,NO提交原点之前).进一步研究,发现有一个reset
确切的命令:
git reset --hard @{u}
注意:@{u}
是简写origin/master
.(当然,您需要该远程存储库才能实现此功能.)
我能够使用一个不涉及查找提交ID的单个命令来解决此问题.
git reset --hard remotes/origin/HEAD
接受的答案对我没有用,但是这个命令达到了我想要的结果.
只是为了看一个额外的选项,我一直主要关注这里描述的分支模型:http://nvie.com/posts/a-successful-git-branching-model/并且因此一直在合并--no-ff
(否)快进)通常.
我只是读了这个页面,因为我不小心合并了一个测试分支而不是我的发布分支与master进行部署(网站,主是什么是现场).测试分支有两个其他分支合并到它,总共约六个提交.
所以为了恢复整个提交,我只需要一个git reset --hard HEAD^
,它就恢复了整个合并.由于合并没有快速转发,合并是一个块,后退一步是"分支未合并".
您只能使用两个命令来恢复合并或通过特定提交重新启动:
git reset --hard commitHash
(您应该使用要重新启动的提交,例如44a587491e32eafa1638aca7738)git push origin HEAD --force
(将新的本地主分支发送到origin/master)
祝你好运,继续吧!
最简单的答案是odinho给出的 - Velmont
先做 git reset --merge ORIG_HEAD
对于那些希望在推送更改后重置的人,请执行此操作(因为这是任何git重置合并问题的第一篇文章)
git push origin HEAD --force
这将以一种方式重置,以便在拉后不会再次获得合并的更改.
如果您的合并和相应的提交尚未推送,您可以随时切换到另一个分支,删除原始分支并重新创建它.
例如,我意外地将一个开发分支合并到master中,并想要撤消它.使用以下步骤:
git checkout develop
git branch -D master
git branch -t master origin/master
瞧!师父与原点处于同一阶段,你的错误合并状态将被删除.
您必须更改HEAD,当然不是git HEAD。
因此,在回答之前,让我们添加一些背景知识,解释一下这是什么HEAD
。
First of all what is HEAD?
HEAD
只是对当前分支上当前提交(最新)的引用。在任何给定时间
只能有一个HEAD
。(不包括git worktree
)
的内容HEAD
存储在内部.git/HEAD
,它包含当前提交的40个字节的SHA-1。
detached HEAD
如果您不在最新的提交上,这意味着它HEAD
指向历史上的先前提交detached HEAD
。
在命令行上,它看起来像这样-SHA-1而不是分支名称,因为HEAD
并不指向当前分支的尖端
有关如何从分离的HEAD中恢复的几种选择:
git checkout
git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back
git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back
</cod
# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>
# create a new branch forked to the given commit
git checkout -b <branch name>
# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>
# create a new branch forked to the given commit
git checkout -b <branch name>
e>
这将签出指向所需提交的新分支。
该命令将签出给定的提交。
此时,您可以创建一个分支并从此开始工作。
git reflog
您也可以随时使用reflog
。
git reflog
将显示任何更新的更改,HEAD
并签出所需的reflog条目,将HEAD
后退设置为此提交。
每次修改HEAD时,都会在 reflog
git reflog
git checkout HEAD@{...}
这将使您回到所需的提交
git reset --hard <commit_id>
将“ HEAD”“移动”回所需的提交。
- 注意:(从Git 2.7开始),
您也可以使用git rebase --no-autostash
。
git revert <sha-1>
“撤消”给定的提交或提交范围。
reset命令将“撤消”在给定提交中所做的任何更改。
带有撤消补丁的新提交将被提交,而原始提交也将保留在历史记录中。
该模式说明了哪个命令可以执行什么操作。
如您所见,reset && checkout
修改HEAD
。
- This is treasure
如果您需要命令行解决方案,我建议您只使用 MBO 的答案。
如果您是新手,您可能会喜欢图形方法:
- 开始
gitk
(从命令行,或在文件浏览器中右键单击(如果有) - 您可以轻松地在那里发现合并提交 - 顶部的第一个节点有两个父节点
- 按照链接到第一个/左父级(合并前当前分支上的那个,对我来说通常是红色的)
- 在选定的提交上,右键单击“将分支重置到此处”,在那里选择硬重置
策略:从一切都很好的地方创建一个新分支。
理由:恢复合并很困难。解决方案太多,取决于许多因素,例如您是否已提交或推送合并,或者自合并后是否有新提交。此外,您仍然需要对 git 有相对深入的了解,才能根据您的情况调整这些解决方案。如果你盲目地遵循一些指令,你最终可能会得到一个“空合并”,什么都不会合并,进一步的合并尝试会让 Git 告诉你“已经是最新的”。
解决方案:
假设您想合并dev
到feature-1
.
-
git log --oneline feature-1 a1b2c3d4 Merge branch 'dev' into 'feature-1' <-- the merge you want to undo e5f6g7h8 Fix NPE in the Zero Point Module <-- the one before the merge, you probably want this one
-
git checkout e5f6g7h8
-
git checkout -b feature-1
现在您可以重新开始合并:
- 合并:
git merge dev
- 修复您的合并冲突。
- 犯罪:
git commit
- 当您对结果满意时,删除旧分支:
git branch --delete feature-1