[英]How to revert a merge commit that's already pushed to remote branch?
git revert <commit_hash>
alone won't work. git revert <commit_hash>
单独不起作用。 -m
must be specified, and I'm pretty confused about it. -m
必须指定,我对此感到很困惑。
Anyone experienced this before?以前有人经历过吗?
The -m
option specifies the parent number . -m
选项指定父编号。 This is because a merge commit has more than one parent, and Git does not know automatically which parent was the mainline, and which parent was the branch you want to un-merge.这是因为合并提交有多个父级,并且 Git 不会自动知道哪个父级是主线,哪个父级是您要取消合并的分支。
When you view a merge commit in the output of git log
, you will see its parents listed on the line that begins with Merge
:当您在git log
的 output 中查看合并提交时,您将看到其父项列在以Merge
开头的行上:
commit 8f937c683929b08379097828c8a04350b9b8e183
Merge: 8989ee0 7c6b236
Author: Ben James <ben@example.com>
Date: Wed Aug 17 22:49:41 2011 +0100
Merge branch 'gh-pages'
Conflicts:
README
In this situation, git revert 8f937c6 -m 1
will get you the tree as it was in 8989ee0
, and git revert -m 2
will reinstate the tree as it was in 7c6b236
.在这种情况下, git revert 8f937c6 -m 1
将为您提供 8989ee0 中的树,而8989ee0
git revert -m 2
将恢复7c6b236
中的树。
To better understand the parent IDs, you can run:为了更好地理解父 ID,您可以运行:
git log 8989ee0
and和
git log 7c6b236
Here's a complete example in the hope that it helps someone:这是一个完整的示例,希望对某人有所帮助:
git revert -m 1 <commit-hash>
git push -u origin master
Where <commit-hash>
is the commit hash of the merge that you would like to revert, and as stated in the explanation of this answer , -m 1
indicates that you'd like to revert to the tree of the first parent prior to the merge.其中<commit-hash>
是您想要恢复的合并的提交 hash ,如本答案的解释中所述, -m 1
表示您希望恢复到之前的第一个父级的树合并。
The git revert...
line essentially commits your changes while the second line makes your changes public by pushing them to the remote branch. git revert...
行本质上是提交您的更改,而第二行通过将更改推送到远程分支来公开您的更改。
Ben has told you how to revert a merge commit, but it's very important you realize that in doing so Ben 已经告诉过您如何恢复合并提交,但您意识到这样做非常重要
"... declares that you will never want the tree changes brought in by the merge. As a result, later merges will only bring in tree changes introduced by commits that are not ancestors of the previously reverted merge. This may or may not be what you want. "(git-merge man page) . “...声明您永远不会想要合并带来的树更改。因此,以后的合并只会带来不是先前还原合并的祖先的提交引入的树更改。这可能是也可能不是你想要什么。 ”(git-merge 手册页) 。
An article/mailing list message linked from the man page details the mechanisms and considerations that are involved.从手册页链接的文章/邮件列表消息详细说明了所涉及的机制和注意事项。 Just make sure you understand that if you revert the merge commit, you can't just merge the branch again later and expect the same changes to come back.只要确保您了解,如果您恢复合并提交,您就不能稍后再次合并分支并期望相同的更改回来。
You could follow these steps to revert the incorrect commit(s) or to reset your remote branch back to correct HEAD/state.您可以按照这些步骤恢复不正确的提交或将远程分支重置为正确的 HEAD/状态。
git checkout your_branch_name
git log -n5
从 git 日志git log -n5
复制提交 hash(即在错误提交之前的提交的 ID)should show something like this:应该显示如下内容:
commit 7cd42475d6f95f5896b6f02e902efab0b70e8038 "Merge branch 'wrong-commit' into 'your_branch_name'"提交 7cd42475d6f95f5896b6f02e902efab0b70e8038 “将分支 '错误提交' 合并到 'your_branch_name'”
commit f9a734f8f44b0b37ccea769b9a2fd774c0f0c012 "this is a wrong commit" commit 3779ab50e72908da92d2cfcd72256d7a09f446ba "this is the correct commit"提交 f9a734f8f44b0b37ccea769b9a2fd774c0f0c012 “这是一个错误的提交” 提交 3779ab50e72908da92d2cfcd72256d7a09f446ba “这是正确的提交”
git reset <commit-hash> (ie 3779ab50e72908da92d2cfcd72256d7a09f446ba)
git status
to show all the changes that were part of the wrong commit.运行git status
以显示属于错误提交的所有更改。git reset --hard
to revert all those changes.只需运行git reset --hard
即可恢复所有这些更改。git push -f origin your_branch_name
Note: Apply this solution only for your own branch not for a shared branch.注意:此解决方案仅适用于您自己的分支,而不适用于共享分支。
git revert -m 1 <merge-commit>
To keep the log clean as nothing happened (with some downsides with this approach (due to push -f)):为了保持日志干净,因为没有发生任何事情(这种方法有一些缺点(由于 push -f)):
git checkout <branch>
git reset --hard <commit-hash-before-merge>
git push -f origin HEAD:<remote-branch>
'commit-hash-before-merge' comes from the log (git log) after merge. 'commit-hash-before-merge' 来自合并后的日志(git log)。
Sometimes the most effective way to rollback is to step back and replace.有时最有效的回滚方法是退后一步并替换。
git log
Use the 2nd commit hash (full hash, the one you want to revert back to, before the mistake listed) and then rebranch from there.使用第二次提交 hash(完整的 hash,在列出的错误之前要恢复到的那个),然后从那里重新分支。
git checkout -b newbranch <HASH>
Then delete the old branch, copy the newbranch over in its place and restart from there.然后删除旧分支,将新分支复制到它的位置并从那里重新启动。
git branch -D oldbranch
git checkout -b oldbranch newbranch
If its been broadcast, then delete the old branch from all repositories, push the redone branch to the most central, and pull it back down to all.如果已广播,则从所有存储库中删除旧分支,将重做的分支推送到最中心,然后将其拉回全部。
All the answers already covered most of the things but I will add my 5 cents.所有答案已经涵盖了大部分内容,但我会加上我的 5 美分。 In short reverting a merge commit is quite simple:简而言之,恢复合并提交非常简单:
git revert -m 1 <commit-hash>
If you have permission you can push it directly to the "master" branch otherwise simply push it to your "revert" branch and create pull request.如果您有权限,您可以将其直接推送到“master”分支,否则只需将其推送到您的“revert”分支并创建拉取请求。
You might find more useful info on this subject here: https://itcodehub.blogspot.com/2019/06/how-to-revert-merge-in-git.html您可能会在此处找到有关此主题的更多有用信息: https://itcodehub.blogspot.com/2019/06/how-to-revert-merge-in-git.html
If you want to revert a merge
commit, here is what you have to do.如果您想恢复merge
提交,您必须执行以下操作。
git log
to find your merge commit's id.首先,检查git log
以找到您的合并提交的 id。 You'll also find multiple parent ids associated with the merge (see image below).您还会发现与合并关联的多个父 ID(见下图)。 Note down the merge commit id shown in yellow.记下黄色显示的合并提交 ID。 The parent IDs are the ones written in the next line as Merge: parent1 parent2
.父 ID 是在下一行写为Merge: parent1 parent2
的那些。 Now...现在...
Short Story:短篇故事:
git revert <merge commit id> -m 1
which will open a vi
console for entering commit message.然后只需执行git revert <merge commit id> -m 1
这将打开一个vi
控制台以输入提交消息。 Write, save, exit, done!写入,保存,退出,完成!Long story:很长的故事:
Switch to branch on which the merge was made.切换到进行合并的分支。 In my case, it is the test
branch and I'm trying to remove the feature/analytics-v3
branch from it.就我而言,它是test
分支,我正在尝试从中删除feature/analytics-v3
分支。
git revert
is the command which reverts any commit. git revert
是恢复任何提交的命令。 But there is a nasty trick when reverting a merge
commit.但是在恢复merge
提交时有一个讨厌的技巧。 You need to enter the -m
flag otherwise it will fail.您需要输入-m
标志,否则它将失败。 From here on, you need to decide whether you want to revert your branch and make it look like exactly it was on parent1
or parent2
via:从这里开始,您需要通过以下方式决定是否要恢复分支并使其看起来与parent1
或parent2
上的完全相同:
git revert <merge commit id> -m 1
(reverts to parent2
) git revert <merge commit id> -m 1
(恢复为parent2
)
git revert <merge commit id> -m 2
(reverts to parent1
) git revert <merge commit id> -m 2
(恢复为parent1
)
You can git log these parents to figure out which way you want to go and that's the root of all the confusion.您可以 git 记录这些父母以找出您想要 go 的方式,这就是所有混乱的根源。
I found good explanation for How To Revert The Merge from this link and I copy pasted the explanation below and it would be helpful just in case if below link doesn't work.我从这个链接中找到了关于如何恢复合并的很好的解释,我复制粘贴了下面的解释,如果下面的链接不起作用,它会很有帮助。
How to revert a faulty merge Alan(alan@clueserver.org) said:如何恢复错误的合并Alan(alan@clueserver.org) 说:
I have a master branch.我有一个主分支。 We have a branch off of that that some developers are doing work on.我们有一个分支,一些开发人员正在研究它。 They claim it is ready.他们声称它已经准备好了。 We merge it into the master branch.我们将它合并到主分支中。 It breaks something so we revert the merge.它破坏了一些东西,所以我们恢复合并。 They make changes to the code.他们对代码进行更改。 they get it to a point where they say it is ok and we merge again.他们达到了他们说没问题的地步,然后我们再次合并。 When examined, we find that code changes made before the revert are not in the master branch, but code changes after are in the master branch.经过检查,我们发现在还原之前所做的代码更改不在 master 分支中,但之后的代码更改在 master 分支中。 and asked for help recovering from this situation.并寻求帮助从这种情况中恢复过来。
The history immediately after the "revert of the merge" would look like this: “恢复合并”之后的历史记录如下所示:
---o---o---o---M---x---x---W
/
---A---B
where A and B are on the side development that was not so good, M is the merge that brings these premature changes into the mainline, x are changes unrelated to what the side branch did and already made on the mainline, and W is the "revert of the merge M" (doesn't W look M upside down?).其中 A 和 B 处于不太好的侧开发,M 是将这些过早的更改带入主线的合并,x 是与侧分支所做的和已经在主线上所做的无关的更改,W 是“合并 M" 的还原(W 看起来不是 M 倒置吗?)。 IOW, "diff W^..W" is similar to "diff -RM^..M". IOW,“diff W^..W”类似于“diff -RM^..M”。
Such a "revert" of a merge can be made with:这种合并的“恢复”可以通过以下方式进行:
$ git revert -m 1 M After the developers of the side branch fix their mistakes, the history may look like this: $ git revert -m 1 M侧分支的开发者修复错误后,历史可能是这样的:
---o---o---o---M---x---x---W---x
/
---A---B-------------------C---D
where C and D are to fix what was broken in A and B, and you may already have some other changes on the mainline after W.其中 C 和 D 用于修复 A 和 B 中损坏的内容,并且在 W 之后您可能已经在主线上进行了一些其他更改。
If you merge the updated side branch (with D at its tip), none of the changes made in A or B will be in the result, because they were reverted by W. That is what Alan saw.如果合并更新后的分支(D 在其尖端),在 A 或 B 中所做的任何更改都不会出现在结果中,因为它们已被 W 还原。这就是 Alan 所看到的。
Linus explains the situation: Linus 解释了这种情况:
Reverting a regular commit just effectively undoes what that commit did, and is fairly straightforward.恢复常规提交只是有效地撤消了该提交所做的事情,而且相当简单。 But reverting a merge commit also undoes the data that the commit changed, but it does absolutely nothing to the effects on history that the merge had.但是还原合并提交也会撤消提交更改的数据,但它对合并对历史的影响绝对没有任何作用。 So the merge will still exist, and it will still be seen as joining the two branches together, and future merges will see that merge as the last shared state - and the revert that reverted the merge brought in will not affect that at all.所以合并仍然存在,它仍然会被视为将两个分支连接在一起,未来的合并将把合并视为最后一个共享的 state - 并且恢复引入的合并的恢复根本不会影响它。 So a "revert" undoes the data changes, but it's very much not an "undo" in the sense that it doesn't undo the effects of a commit on the repository history.因此,“还原”撤消了数据更改,但从某种意义上说,它不是“撤消”,因为它不会撤消提交对存储库历史的影响。 So if you think of "revert" as "undo", then you're going to always miss this part of reverts.因此,如果您将“还原”视为“撤消”,那么您将永远错过这部分还原。 Yes, it undoes the data, but no, it doesn't undo history.是的,它会撤消数据,但不,它不会撤消历史记录。 In such a situation, you would want to first revert the previous revert, which would make the history look like this:在这种情况下,您可能希望首先还原先前的还原,这将使历史看起来像这样:
---o---o---o---M---x---x---W---x---Y
/
---A---B-------------------C---D
where Y is the revert of W. Such a "revert of the revert" can be done with:其中 Y 是 W 的恢复。这种“恢复的恢复”可以通过以下方式完成:
$ git revert W This history would (ignoring possible conflicts between what W and W..Y changed) be equivalent to not having W or Y at all in the history: $ git revert W这段历史将(忽略 W 和 W..Y 更改的内容之间可能发生的冲突)等同于历史中根本没有 W 或 Y:
---o---o---o---M---x---x-------x----
/
---A---B-------------------C---D
and merging the side branch again will not have conflict arising from an earlier revert and revert of the revert.并且再次合并侧分支不会因为之前的revert和revert的revert而产生冲突。
---o---o---o---M---x---x-------x-------*
/ /
---A---B-------------------C---D
Of course the changes made in C and D still can conflict with what was done by any of the x, but that is just a normal merge conflict.当然,在 C 和 D 中所做的更改仍然可能与任何 x 所做的冲突,但这只是正常的合并冲突。
This is a very old thread, but I am missing another in my opinion convenient solution:这是一个非常古老的线程,但在我看来,我错过了另一个方便的解决方案:
I never revert a merge.我从不恢复合并。 I just create another branch from the revision where everything was ok and then cherry pick everything that needs to picked from the old branch which was added in between.我只是从一切正常的修订版中创建另一个分支,然后从中间添加的旧分支中挑选需要挑选的所有内容。
So, if the GIT history is like this:所以,如果 GIT 历史是这样的:
I create a new branch from a, cherry pick c and d and then the new branch is clear from b.我从 a 创建一个新分支,樱桃挑选 c 和 d,然后从 b 清除新分支。 I can ever decide to do the merge of "b" in my new branch again.我可以决定再次在我的新分支中合并“b”。 The old branch becomes deprecated and will be deleted if "b" is not necessary anymore or still in another (feature/hotfix) branch.如果不再需要“b”或仍在另一个(功能/修补程序)分支中,旧分支将被弃用,并将被删除。
The only problem is now one of the very hardest things in computer science: How do you name the new branch?现在唯一的问题是计算机科学中最困难的事情之一:你如何命名新分支? ;) ;)
Ok, if you failed esp.好的,如果你失败了,尤其是。 in devel, you create newdevel as mentioned above, delete old devel and rename newdevel to devel.在 devel 中,您如上所述创建 newdevel,删除旧的 devel 并将 newdevel 重命名为 devel。 Mission accomplished.任务完成。 You can now merge the changes again when you want.您现在可以在需要时再次合并更改。 It is like never merged before....就像以前从未合并过一样......
I found creating a reverse patch between two know end-points and applying that patch would work.我发现在两个已知端点之间创建一个反向补丁并应用该补丁会起作用。 This presumes that you have created snapshots (tags) off of your master branch or even a back up of your master branch say master_bk_01012017.这假定您已经从主分支创建了快照(标签),甚至是主分支的备份,例如 master_bk_01012017。
Say the code branch you merged into master was mycodebranch.假设您合并到 master 的代码分支是 mycodebranch。
git diff --binary master..master_bk_01012017 > ~/myrevert.patch
git apply --check myrevert.patch
检查你的补丁git apply --check myrevert.patch
git am --signoff < myrevert.patch
应用带有签名的补丁git am --signoff < myrevert.patch
git branch mycodebranch_fix
git checkout mycodebranch_fix
如果您需要在修复后再次引入此代码,您将需要分支恢复的 master 并检查修复分支git branch mycodebranch_fix
git checkout mycodebranch_fix
git revert [SHA]
在这里你需要找到revert的SHA密钥并revert the revert git revert [SHA]
The correctly marked answer worked for me but I had to spend some time to determine whats going on.. So I decided to add an answer with simple straightforward steps for cases like mine..正确标记的答案对我有用,但我不得不花一些时间来确定发生了什么。所以我决定为像我这样的案例添加一个简单直接的步骤的答案。
Lets say we got branches A and B.. You merged branch A into branch B and pushed branch B to itself so now the merge is part of it.. But you want to go back to the last commit before the merge.. What do you do?假设我们有分支 A 和 B..您将分支 A 合并到分支 B 并将分支 B 推送到自身,所以现在合并是它的一部分..但是您想 go 回到合并前的最后一次提交.. 怎么办你做?
git log
Go 到您的 git 根文件夹(通常是项目文件夹)并使用git log
You will see the history of recent commits - the commits have commit/author/date properties while the merges also have a merge property - so you see them like this:您将看到最近提交的历史记录 - 提交具有提交/作者/日期属性,而合并也具有合并属性 - 因此您会看到它们:
commit: <commitHash> Merge: <parentHashA> <parentHashB> Author: <author> Date: <date>
Use git log <parentHashA>
and git log <parentHashB>
- you will see the commit histories of those parent branches - the first commits in the list are the latest ones使用git log <parentHashA>
和git log <parentHashB>
- 你会看到这些父分支的提交历史 - 列表中的第一个提交是最新的
<commitHash>
of the commit you want, go to your git root folder and use git checkout -b <newBranchName> <commitHash>
- that will create a new branch starting from that last commit you've chosen before the merge.. Voila, ready!将您想要的提交的<commitHash>
go 放到您的 git 根文件夹中,然后使用git checkout -b <newBranchName> <commitHash>
从最后一次提交之前选择的新分支。瞧,准备好了!git doc about git revert -m provide a link exactly explain this: https://github.com/git/git/blob/master/Documentation/howto/revert-a-faulty-merge.txt git doc 关于 git revert -m 提供一个链接准确解释这一点: https://github.com/git/gitvert/blob/master/Documentation/howto.reault/
-m1 is the last parent of the current branch that is being fixed, -m 2 is the original parent of the branch that got merged into this. -m1 是当前正在修复的分支的最后一个父级,-m 2 是合并到此分支的原始父级。
Tortoise Git can also help here if command line is confusing.如果命令行令人困惑,Tortoise Git 也可以在这里提供帮助。
When you view a merge commit in the output of git log
, you will see its parents listed on the line that begins with Merge
:当您在git log
的 output 中查看合并提交时,您将看到其父项列在以Merge
开头的行上:
commit 8f937c683929b08379097828c8a04350b9b8e183
Merge: 8989ee0 7c6b236
Author: Ben James <ben@example.com>
Date: Wed Aug 17 22:49:41 2011 +0100
Merge branch 'gh-pages'
Conflicts:
README
In this situation, git revert 8f937c6 -m 1
will get you the tree as it was in 8989ee0
, and git revert -m 2
will reinstate the tree as it was in 7c6b236
.在这种情况下, git revert 8f937c6 -m 1
将为您提供 8989ee0 中的树,而8989ee0
git revert -m 2
将恢复7c6b236
中的树。
To better understand the parent IDs, you can run:为了更好地理解父 ID,您可以运行:
git log 8989ee0
and和
git log 7c6b236
Take a backup branch建立一个备份分支
git checkout -b mybackup-brach
git reset --hard 8989ee0
git push origin -u mybackup-branch
So now you have the changes before the merge, If everything Okay, checkout into previous branch and reset with backup branch因此,现在您在合并之前进行了更改,如果一切正常,请签出到上一个分支并使用备份分支重置
git reset --hard origin/mybakcup-branhc
I also faced this issue on a PR that has been merged to the master branch of a GitHub repo.我在已合并到 GitHub 存储库的主分支的 PR 上也遇到了这个问题。
Since I just wanted to modify some modified files but not the whole changes the PR brought, I had to amend
the merge commit
with git commit --am
.由于我只想修改一些修改过的文件,而不是 PR 带来的全部更改,因此我不得不使用git commit --am
amend
merge commit
。
Steps:脚步:
git add *
or git add <file>
运行git add *
或git add <file>
git commit --am
and validate运行git commit --am
并验证git push -f
运行git push -f
Why it's interesting:为什么有趣:
A very simple answer if you are looking to revert the change that you pushed just now:如果您希望恢复刚才推送的更改,这是一个非常简单的答案:
commit 446sjb1uznnmaownlaybiosqwbs278q87
Merge: 123jshc 90asaf
git revert -m 2 446sjb1uznnmaownlaybiosqwbs278q87 //does the work
For me, I had a PR on repository from my forked master branch to origin master, when I fetched upstream it added a merge commit, because my branch was 1 commit ahead, and several 100 commit behind.对我来说,我有一个从我的分叉主分支到源主分支的存储库 PR,当我在上游获取时,它添加了一个合并提交,因为我的分支提前 1 个提交,后面有几个 100 个提交。 So it automatically add the merge commit.所以它会自动添加合并提交。
So to remove that I had to just run this command:所以要删除它,我只需要运行这个命令:
git reset --hard HEAD~1
git push -f origin
It removed that merge.它删除了该合并。 And everything went back to normal.一切都恢复了正常。
As Ryan mentioned, git revert
could make merging difficult down the road, so git revert
may not be what you want.正如 Ryan 所提到的, git revert
可能会使合并变得困难,因此git revert
可能不是您想要的。 I found that using the git reset --hard <commit-hash-prior-to-merge>
command to be more useful here.我发现使用git reset --hard <commit-hash-prior-to-merge>
命令在这里更有用。
Once you have done the hard reset part, you can then force push to the remote branch, ie git push -f <remote-name> <remote-branch-name>
, where <remote-name>
is often named origin
.完成硬重置部分后,您可以强制推送到远程分支,即git push -f <remote-name> <remote-branch-name>
,其中<remote-name>
通常被命名为origin
。 From that point you can re-merge if you'd like.从那时起,您可以根据需要重新合并。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.