如何还原已经推送到远程分支的合并提交?

Yaz*_*Yaz 827 git

git revert <commit_hash>单独行不通.-m必须指定,我对它很困惑.

以前有人经历过吗?

Ben*_*mes 993

-m选项指定父编号.这是因为合并提交具有多个父级,并且Git不会自动知道哪个父级是主线,哪个父级是您要取消合并的分支.

当您在输出中查看合并提交时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
Run Code Online (Sandbox Code Playgroud)

在这种情况下,git revert 8f937c6 -m 1将获得原样的树8989ee0,git revert -m 2并将恢复原来的树7c6b236.

为了更好地理解父ID,您可以运行:

git log 8989ee0 
Run Code Online (Sandbox Code Playgroud)

git log 7c6b236
Run Code Online (Sandbox Code Playgroud)

  • 来自两个数字`8989ee0`,`7c6b236`,哪一个去.我怎么理解? (113认同)
  • @ArupRakshit如果你运行`git log 8989ee0`和`git log 7c6b236`,你应该知道答案. (43认同)
  • 恢复后,我不认为一个人能够轻松地**纠正源分支中的代码并再次合并?http://www.kernel.org/pub/software/scm/git/docs/howto/revert-a-faulty-merge.txt (11认同)
  • 在谷歌上搜索更好的解释时,我发现这篇文章我认为很好地完成了细节.我在阅读之后发现,我真正想要的是RESET命令,然后是强制推动.也许它会帮助别人.https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting (10认同)
  • git log - 用于查看所有合并和git log --no-merges以查看没有合并的历史记录.合并分支会将合并的分支历史记录带入目标,并且很难使用普通的git日志来实现 (4认同)
  • 呃,如果没有完整的日志,这个答案实际上没有意义 (3认同)
  • 不鼓励 git push --force ,因为它可以覆盖远程上的意外工作。 (3认同)
  • 为什么这么复杂?Git 有时是一场噩梦。 (3认同)
  • 这是一个很好的答案,并致力于删除一些提交并返回合并。还原仅删除了合并,而不删除了所需的后续提交。建议:gitk可以很好地显示合并和历史记录。 (2认同)
  • 第一个哈希表示合并之前目标分支的哈希(或头)。第二个哈希表示合并到目标之前的源分支。它是否正确? (2认同)

Sah*_*eed 319

这是一个完整的例子,希望它可以帮助某人:

git revert -m 1 <commit-hash> 
git commit -m "Reverting the last commit which messed the repo."
git push -u origin master
Run Code Online (Sandbox Code Playgroud)

<commit-hash>您想要还原的合并的提交哈希在哪里,并且如此答案的说明中所述,-m 1表示您希望在合并之前还原到第一个父项的树.

git commit ...行基本上会提交您的更改,而第三行通过将更改推送到远程分支来公开您的更改.

  • 我相信`git revert`命令已经提交了创建的提交对象.为了不发生这种情况,你必须输入`--no-commit`标志 (20认同)
  • 这很令人困惑。只有 2 行,没有 git commit.. 有人可以编辑吗? (3认同)
  • 正如@Delfic所提到的,提交已经由第一行管理了(我需要一个:wq来验证它),因此第二行不是必需的。 (2认同)

Rya*_*art 162

Ben告诉你如何恢复合并提交,但是你知道这样做非常重要 "声明你永远不会希望合并带来的树更改.因此,后来的合并只会带来由树引入的树变化提交不是先前恢复的合并的祖先.这可能是也可能不是你想要的." (git-merge手册页).

从手册页链接的文章/邮件列表消息详细说明了涉及的机制和注意事项.只要确保你理解,如果你恢复合并提交,你不能再稍后再合并分支,并期望相同的更改回来.

  • 但是如果确实需要的话,你可以恢复恢复以恢复它们. (73认同)
  • 这非常重要,应该作为对其他答案的警告添加。IMO,您并没有真正反转合并本身,您正在反转合并所做的更改。 (5认同)
  • 谢谢.非常有用的知道作为撤消合并的用例 - 由于一个错误,比如说 - 然后在修复错误后重新合并整个分支是很常见的. (4认同)
  • 如果您像我一样,后来又想要合并,则可以还原该还原,也可以选择您还原的变更。 (2认同)

ssa*_*asi 69

您可以按照以下步骤恢复不正确的提交或将远程分支重置为正确的HEAD /状态.

  1. 将远程分支签出到本地仓库.
    git checkout development
  2. 从git log中复制提交哈希(即在错误提交之前提交的id) git log -n5

    输出:

    提交7cd42475d6f95f5896b6f02e902efab0b70e8038"合并分支'错误提交'进入'开发'"
    提交f9a734f8f44b0b37ccea769b9a2fd774c0f0c012"这是一个错误的提交"
    commit 3779ab50e72908da92d2cfcd72256d7a09f446ba"这是正确的提交"

  3. 将分支重置为上一步中复制的提交哈希
    git reset <commit-hash> (i.e. 3779ab50e72908da92d2cfcd72256d7a09f446ba)

  4. 运行git status以显示作为错误提交的一部分的所有更改.
  5. 只需运行git reset --hard以还原所有这些更改.
  6. 强制将本地分支推送到远程,并注意您的提交历史记录是否在被污染之前是干净的.
    git push -f origin development

  • 如果在此期间有20位开发人员推出最新的开发合并怎么办? (4认同)
  • 当您自己工作或确定没有其他开发人员撤出您搞砸的提交时,这是一个非常好的解决方案 (4认同)
  • 当团队中有20个开发人员使用该分支时,我不会强行推动该分支。:)在这种情况下,明智的做法是执行还原提交。 (2认同)
  • 默认情况下,此答案显示在顶部,但这是一个危险的答案。许多人只是按照步骤操作,而不阅读底部的注释。我试图将注释放在顶部,但看起来编辑队列已满。 (2认同)

Nee*_*mar 46

git revert -m 1 <merge-commit>
Run Code Online (Sandbox Code Playgroud)

  • 这个答案缺乏很多细节。也许这就是它好的原因。 (29认同)
  • 为什么是“1”?根据谷歌搜索:“我们使用合并提交的 SHA1 哈希来指定合并。-m 后跟 1 表示我们要保留合并的父端(我们要合并到的分支)。” 来源:https://mijingo.com/blog/reverting-a-git-merge (4认同)
  • @GustavoStraube 这是讽刺还是你实际上意味着答案很好?它实际上对我有用。 (3认同)

nvd*_*nvd 25

为了保持日志清洁,因为没有发生任何事情(这种方法有一些缺点(由于push -f)):

git checkout <branch>
git reset --hard <commit-hash-before-merge>
git push -f origin HEAD:<remote-branch>
Run Code Online (Sandbox Code Playgroud)

'commit-hash-before-merge'来自合并后的日志(git log).

  • 提示:如果您在公司执行此操作,您可能没有获得许可。 (3认同)
  • 永远不要在共享存储库上执行`push -f` (3认同)

ppo*_*ma1 16

有时回滚最有效的方法是退后一步.

git log

使用第二个提交哈希(完整哈希,你要恢复的那个,在列出的错误之前),然后从那里重新分配.

git checkout -b newbranch <HASH>

然后删除旧分支,将newbranch复制到其位置并从那里重新启动.

git branch -D oldbranch
git checkout -b oldbranch newbranch
Run Code Online (Sandbox Code Playgroud)

如果已广播,则从所有存储库中删除旧分支,将重做分支推送到最中心,然后将其拉回到所有.

  • 关于广播的警告应该更明确地说明这是多么可怕的想法.这将破坏该分支的每个版本,并且只有在您使用只有您有权访问的远程存储库(github/bitbucket)时才真正有用. (3认同)

小智 15

所有的答案已经涵盖了大部分内容,但我会加上我的 5 美分。简而言之,恢复合并提交非常简单:

git revert -m 1 <commit-hash>
Run Code Online (Sandbox Code Playgroud)

如果您有权限,您可以将其直接推送到“master”分支,否则只需将其推送到您的“revert”分支并创建拉取请求。

您可能会在此处找到有关此主题的更多有用信息:https : //itcodehub.blogspot.com/2019/06/how-to-revert-merge-in-git.html


sar*_*n3h 9

如果你想恢复merge提交,这是你必须做的。

  1. 首先,检查git log以找到您的合并提交的 ID。您还会发现与合并关联的多个父 ID(见下图)。

在此处输入图片说明

记下黄色显示的合并提交 ID。父 ID 是写在下一行中的那些Merge: parent1 parent2。现在...

短篇故事:

  1. 切换到进行合并的分支。然后只需执行git revert <merge commit id> -m 1这将打开一个vi控制台以输入提交消息。写入,保存,退出,完成!

很长的故事:

  1. 切换到进行合并的分支。就我而言,它是test分支,我试图从中删除feature/analytics-v3分支。

  2. git revert是恢复任何提交的命令。但是在恢复merge提交时有一个讨厌的技巧。您需要输入-m标志,否则它将失败。从这里开始,你需要决定是否要恢复您的分行,并使它看起来像它到底是对parent1还是parent2通过:

git revert <merge commit id> -m 1(恢复为parent2

git revert <merge commit id> -m 2(恢复为parent1

你可以 git log 这些父母来找出你想要走的路,这就是所有混乱的根源。


Ani*_*ilS 9

当您在 的输出中查看合并提交时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
Run Code Online (Sandbox Code Playgroud)

在这种情况下,git revert 8f937c6 -m 1将为您提供树的原样8989ee0,并将git revert -m 2树恢复为原样7c6b236

为了更好地了解父 ID,您可以运行:

git log 8989ee0 
Run Code Online (Sandbox Code Playgroud)

git log 7c6b236
Run Code Online (Sandbox Code Playgroud)

建立一个备份分支

git checkout -b mybackup-brach

git reset --hard 8989ee0 
git push origin -u mybackup-branch
Run Code Online (Sandbox Code Playgroud)

所以现在你已经在合并之前进行了更改,如果一切正常,请检出到上一个分支并使用备份分支重置

git reset --hard origin/mybakcup-branhc
Run Code Online (Sandbox Code Playgroud)


Aks*_*ran 9

接受的答案和其他一些答案演示了如何使用该命令恢复合并提交git revert。然而,关于父提交存在一些混乱。这篇文章旨在通过图形表示和真实示例来阐明这一点。

\n

恢复合并提交并不像使用 那样简单git revert <commit-hash>,因为在从合并提交回看时,由于其两个父提交,Git 会感到困惑。要指定所需的父级,请使用该-m标志。由于 git 无法自动确定哪个父级是主线,哪个是要自动取消合并的分支,所以必须指定这一点。

\n

git 提交图

\n

iss53分支被合并到master,创建了Merge Commit, C6C6有两个父母,C5并且C4.

\n

需要将C6存储库恢复到其在 的状态C4。因此它必须指定哪个父级用于恢复命令。

\n
    \n
  • 为此,请检查git log此处代表实际提交哈希,其中包含图中的代码名称

    \n
    > git log\n\ncommit C6\nMerge: C4 C5\nAuthor: Mozz <mozz@example.com>\nDate:   Wed Feb 29 23:59:59 2020 +0100\n\nMerge branch \'iss53\' to master\n...\n
    Run Code Online (Sandbox Code Playgroud)\n
  • \n
  • git log输出中,记下 附带的父 ID Merge: - -。其格式为Merge: parent1 parent2,此处Merge: C4 C5

    \n
  • \n
  • 提交C4位于master分支中,我们需要恢复到该分支,即父分支 1,并且-m 1此处需要(用于git log C4验证之前的提交以确认父分支)。

    \n
  • \n
  • 切换到进行合并的分支(这是这里的分支,我们的目标是从中master删除该分支)iss53

    \n

    执行 git revert with -m 1flag。

    \n
    # To revert to C4 in master branch\ngit revert C6 -m 1\n\n# C6 - is the merge commit hash\n
    Run Code Online (Sandbox Code Playgroud)\n
  • \n
\n

对于其他一些情况,如果需要的话恢复为C5,

\n
# revert to C5 in iss53 branch\ngit revert C6 -m 2\n\n# General\ngit revert <merge commit id> -m 1 (reverts to parent1)\ngit revert <merge commit id> -m 2 (reverts to parent2)\n# remember to check and verify the parent1 and parent2 with git log command.\n
Run Code Online (Sandbox Code Playgroud)\n

实际例子

\n

revert-test在只有分支的现有项目上创建了一个新分支main,提交图现在看起来像这样。

\n

之前的 git 树

\n

(对于提交的图形视图,请\xe2\x80\x94graphgit log [ SO ans ref ] 或这个更具交互性的 VS 代码扩展 - git graph一起使用)

\n

现在,我添加了一些新文件,修改了现有文件,并在每个分支上创建了单独的提交,然后将它们推送到原点。该图现在看起来像这样:

\n

提交后的 git 树

\n

然后,从 GitHub 创建拉取请求并将revert-test分支合并到main.

\n

合并后的git树

\n

我想撤消合并提交并返回到分支中的最后一次提交main- 这是12a7327

\n

请注意,合并提交 -2ec06d9现在有两个父级 - 12a7327(in main) 和15bde47(in revert-test),git log现在检查,

\n
> git log\n\ncommit 2ec06d9d315a3f7919ffe4ad2c2d7cec8c8f9aa3 (HEAD -> main, origin/main, origin/HEAD)\nMerge: 12a7327 15bde47\nAuthor: Akshay <63786863+akshay@users.noreply.github.com>\nDate:   Sun Feb 5 00:41:13 2023 +0530\n\n    Merge pull request #1 from Akshay/revert-test\n    \n    Revert test\n
Run Code Online (Sandbox Code Playgroud)\n

要恢复合并提交并返回12a7327需要执行的操作,

\n
# To the First parent\ngit revert 2ec06d9 -m 1\n
Run Code Online (Sandbox Code Playgroud)\n

现在编辑器中将显示一条提交消息,指定详细信息、检查和验证。

\n

git 恢复提交验证消息

\n

这样就创建了一个恢复提交,它执行合并提交的反向更改。

\n

恢复提交

\n

最后推送更改,现在合并提交更改消失了,日志将如下所示,

\n

最终的git树

\n


MK4*_*446 7

我从这个链接找到了关于如何恢复合并的很好的解释,我复制粘贴了下面的解释,以防万一下面的链接不起作用。

如何恢复错误的合并 Alan(alan@clueserver.org) 说:

我有一个主分支。我们有一个分支,一些开发人员正在做这项工作。他们声称它已经准备好了。我们将其合并到 master 分支中。它破坏了某些东西,所以我们恢复了合并。他们对代码进行更改。他们到了他们说没问题的地步,我们再次合并。检查时,我们发现在恢复之前所做的代码更改不在 master 分支中,但在 master 分支中更改后的代码。并请求帮助从这种情况中恢复过来。

“合并恢复”之后的历史记录如下所示:

---o---o---o---M---x---x---W
              /
      ---A---B
Run Code Online (Sandbox Code Playgroud)

其中 A 和 B 是不太好的副开发,M 是将这些过早的更改带入主线的合并,x 是与副分支所做的和已经在主线上所做的无关的更改,W 是“恢复合并 M”(W 看起来 M 不是倒过来的吗?)。IOW,“diff W^..W”类似于“diff -RM^..M”。

这种合并的“恢复”可以通过以下方式进行:

$ git revert -m 1 M 侧分支的开发者修复他们的错误后,历史可能是这样的:

---o---o---o---M---x---x---W---x
              /
      ---A---B-------------------C---D
Run Code Online (Sandbox Code Playgroud)

其中 C 和 D 将修复 A 和 B 中损坏的内容,并且在 W 之后您可能已经在主线上进行了一些其他更改。

如果您合并更新的侧分支(D 在其尖端),则 A 或 B 中所做的任何更改都不会在结果中,因为它们已被 W 还原。这就是 Alan 看到的。

Linus 解释了这种情况:

恢复常规提交只会有效地撤消该提交所做的事情,并且相当简单。但是恢复合并提交也会撤消提交更改的数据,但它对合并对历史的影响绝对没有任何影响。所以合并仍然存在,它仍然会被视为将两个分支连接在一起,未来的合并会将合并视为最后一个共享状态 - 恢复引入的合并的恢复根本不会影响它。因此,“还原”会撤消数据更改,但它非常重要并非如此从某种意义上说,“撤消”不会撤消提交对存储库历史记录的影响。因此,如果您将“还原”视为“撤消”,那么您将总是会错过还原的这一部分。是的,它会撤消数据,但不,它不会撤消历史记录。在这种情况下,您可能希望首先还原先前的还原,这将使历史记录如下所示:

---o---o---o---M---x---x---W---x---Y
              /
      ---A---B-------------------C---D
Run Code Online (Sandbox Code Playgroud)

其中 Y 是 W 的还原。这种“还原的还原”可以通过以下方式完成:

$ git revert W 此历史记录(忽略 W 和 W..Y 更改的内容之间可能存在的冲突)等同于历史记录中根本没有 W 或 Y:

---o---o---o---M---x---x-------x----
              /
      ---A---B-------------------C---D
Run Code Online (Sandbox Code Playgroud)

并且再次合并侧分支不会因为之前的revert和revert的revert而产生冲突。

---o---o---o---M---x---x-------x-------*
              /                       /
      ---A---B-------------------C---D
Run Code Online (Sandbox Code Playgroud)

当然,在 C 和 D 中所做的更改仍然可能与任何 x 所做的发生冲突,但这只是正常的合并冲突。