git revert <commit_hash>
单独使用不起作用。显然,必须指定-m
。
当你在git log
的输出中查看一个合并提交时,你会看到它的父提交在以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
在这种情况下,git revert 8f937c6 -m 1
将使您得到与8989ee0
相同的树形结构,而git revert -m 2
则会将树形结构恢复到 7c6b236
的状态。
为了更好地理解父ID,您可以运行:
git log 8989ee0
并且
git log 7c6b236
选取备份分支
git checkout -b mybackup-brach
git reset --hard 8989ee0
git push origin -u mybackup-branch
现在你已经得到了合并前的更改,如果一切正常,请切换到以前的分支并使用备份分支进行重置。
git reset --hard origin/mybakcup-branhc
被接受的答案和其他答案演示了如何使用 git revert
命令还原合并提交。然而,关于父提交存在一些混淆。这篇文章旨在通过图形表示和一个真实例子来澄清这个问题。
还原合并提交不像使用 git revert <commit-hash>
那么简单,因为 Git 在查看合并提交时会因其有两个父提交而感到困惑。要指定所需的父提交,请使用 -m
标志。由于 Git 无法自动确定哪个父提交是主干线,哪个是分支以进行取消合并,因此必须明确说明。
iss53
分支已合并到 master
,创建了一个 Merge Commit
,C6
。 C6
有两个父级,C5
和 C4
。
需要还原 C6
并将存储库返回到其在 C4
的状态。因此,必须指定要用于还原命令的父级。
请检查 git log
(用来表示实际提交哈希值的代码名称图形在此处)
> git log
commit C6
Merge: C4 C5
Author: Mozz <mozz@example.com>
Date: Wed Feb 29 23:59:59 2020 +0100
Merge branch 'iss53' to master
...
从git log
输出中,注意记录下带有Merge:- -
的父ID。它将是Merge: parent1 parent2
的格式,在这里是Merge: C4 C5
。
C4
提交位于master
分支中,我们需要还原到该分支,也就是需要使用父1和-m 1
(使用git log C4
来验证以前的提交以确认父分支)。
切换到合并所在的分支(这里是master
分支,我们的目标是从中删除iss53
分支)
使用-m 1
标志执行git revert。
# 要还原到主分支中的C4
git revert C6 -m 1
# C6-是合并提交哈希值
对于其他一些情况,如果需要,请回退到C5
。
# revert to C5 in iss53 branch
git revert C6 -m 2
# General
git revert <merge commit id> -m 1 (reverts to parent1)
git revert <merge commit id> -m 2 (reverts to parent2)
# remember to check and verify the parent1 and parent2 with git log command.
在一个只有main
分支的现有项目上创建了一个名为revert-test
的新分支,现在提交图看起来像这样。
(要查看提交的图形视图,请在git log
命令中使用--graph
选项[SO ans ref]或使用更交互式的VS Code扩展程序 - git graph)
现在,我已经添加了一些新文件,修改了现有文件,并在每个分支上创建了单独的提交,然后将它们推送到了源。现在的图形如下:
然后,从GitHub创建了一个拉取请求,并将revert-test
分支合并到main
。
我想撤销合并提交并返回到main
分支中的上一个提交 - 即12a7327
请注意,合并提交 - 2ec06d9
现在有两个父提交 - main
中的12a7327
和revert-test
中的15bde47
,现在检查git log
,
> git log
commit 2ec06d9d315a3f7919ffe4ad2c2d7cec8c8f9aa3 (HEAD -> main, origin/main, origin/HEAD)
Merge: 12a7327 15bde47
Author: Akshay <63786863+akshay@users.noreply.github.com>
Date: Sun Feb 5 00:41:13 2023 +0530
Merge pull request #1 from Akshay/revert-test
Revert test
要撤销合并提交并回到12a7327
,需要执行以下操作:
# To the First parent
git revert 2ec06d9 -m 1
这样就创建了一个还原提交,它会执行合并提交的相反更改。
最后将更改推送,现在合并提交的更改已经消失,日志将如下所示:commit 446sjb1uznnmaownlaybiosqwbs278q87
Merge: 123jshc 90asaf
git revert -m 2 446sjb1uznnmaownlaybiosqwbs278q87 //does the work
对于我来说,正确标记的答案起了作用,但我花了一些时间确定发生了什么。所以我决定添加一个简单明了的步骤,适用于像我这样的情况。
假设我们有分支A和B。你将分支A合并到分支B,并将分支B推送到自身,因此现在合并是其中的一部分。但你想回到合并之前的最后一次提交。你该怎么做?
git log
你将看到最近提交的历史记录——提交具有提交/作者/日期属性,而合并还具有合并属性——因此你会看到它们像这样:
commit: <commitHash>
Merge: <parentHashA> <parentHashB>
Author: <author>
Date: <date>
使用git log <parentHashA>
和git log <parentHashB>
——你将看到这些父分支的提交历史记录——列表中的第一个提交是最新的
<commitHash>
,进入你的git根目录,使用git checkout -b <newBranchName> <commitHash>
——这将创建一个新分支,从你在合并之前选择的最后一次提交开始。完成!关于 git revert -m
的 git 文档提供了一个链接,详细解释了这种情况:
https://github.com/git/git/blob/master/Documentation/howto/revert-a-faulty-merge.txt
git diff --binary master..master_bk_01012017 > ~/myrevert.patch
3. 检查您的补丁
git apply --check myrevert.patch
4. 用签名应用补丁
git am --signoff < myrevert.patch
5. 如果您需要在修复后再次引入此代码,则需要从还原的主分支分支并检出修复分支
git branch mycodebranch_fix
git checkout mycodebranch_fix
6. 在此处,您需要找到还原的SHA密钥并还原还原
git revert [SHA]
7. 现在,您可以使用mycodebranch_fix来解决问题,提交并完成后重新合并到主分支。-m1是当前正在修复的分支的最后一个父分支,-m2是已合并到此分支的原始父分支。
如果命令行让您感到困惑,Tortoise Git也可以提供帮助。
我也遇到了这个问题,它发生在一个 GitHub 仓库的主分支中已经合并了的 PR 上。
因为我只想修改一些已被修改的文件而不是整个 PR 带来的更改,所以我必须使用 git commit --am
命令对 merge commit
进行 amend
。
操作步骤:
git add *
或 git add <file>
git commit --am
并验证git push -f
它的有趣之处:
这对我有效 ::
git reset --merge HEAD~1
。
git
的设计与每个人都使用的git-flow
工作流不匹配。如果你已经检出了develop
分支,那么你肯定想要还原引入错误的 2 次提交的特性分支,而不是多年共享的开发分支。感觉需要用-m 1
来选择它非常荒谬。 - pkamb