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

时间:2011-08-17 21:37:28

标签: git

单靠

git revert <commit_hash>无效。必须指定-m,我对此非常困惑。

以前有人经历过这个吗?

19 个答案:

答案 0 :(得分:858)

-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

在这种情况下,git revert 8f937c6 -m 1会像8989ee0中那样找到树,而git revert -m 2会恢复7c6b236中的树。

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

git log 8989ee0 

git log 7c6b236

答案 1 :(得分:291)

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

git revert -m 1 <commit-hash> 
git commit -m "Reverting the last commit which messed the repo."
git push -u origin master

其中<commit-hash>是您要恢复的合并的提交哈希值,并且如this answer的说明中所述,-m 1表示您要恢复为合并前第一个父母的树。

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

答案 2 :(得分:144)

Ben告诉你如何恢复合并提交,但是非常重要你意识到这样做“声明你永远不会希望合并带来的树更改。结果,以后的合并只会带来由不是先前恢复合并的祖先的提交所引入的树更改。这可能是也可能不是你想要的。“ (git-merge man page)

从手册页链接的article/mailing list message详细说明了所涉及的机制和注意事项。只要确保你理解,如果你还原合并提交,你不能再稍后再合并分支,并期望相同的更改回来。

答案 3 :(得分:66)

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

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

      

    输出:

         

    提交7cd42475d6f95f5896b6f02e902efab0b70e8038&#34;合并分支&#39;错误提交&#39;进入&#39;发展&#39;&#34;
      commit f9a734f8f44b0b37ccea769b9a2fd774c0f0c012&#34;这是一个错误的提交&#34;
      提交3779ab50e72908da92d2cfcd72256d7a09f446ba&#34;这是正确的提交&#34;

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

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

答案 4 :(得分:37)

git revert -m 1 <merge-commit>

答案 5 :(得分:20)

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

git checkout <branch>
git reset --hard <commit-hash-before-merge>
git push -f origin HEAD:<remote-branch>

&#39;提交-散列之前合并&#39;来自合并后的日志(git log)。

答案 6 :(得分:16)

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

git log

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

git checkout -b newbranch <HASH>

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

git branch -D oldbranch
git checkout -b oldbranch newbranch

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

答案 7 :(得分:2)

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

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

我有一个主分支。我们有一些分支 开发人员正在努力。他们声称已经准备好了。我们合并 进入master分支。它破坏了某些内容,因此我们还原了合并。 他们对代码进行更改。他们说到了点 可以,我们再次合并。 经过检查,我们发现还原之前所做的代码更改是 不是在master分支中,而是在master之后进行代码更改 科。 并寻求帮助以从这种情况中恢复过来。

“合并还原”之后的历史记录如下:

---o---o---o---M---x---x---W
              /
      ---A---B

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

可以通过以下方式对合并进行“还原”:

$ git revert -m 1 M 分支机构的开发人员纠正错误后,历史记录可能如下所示:

---o---o---o---M---x---x---W---x
              /
      ---A---B-------------------C---D

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

如果合并更新的边分支(在其顶端带有D),则对A或B所做的任何更改都不会在结果中,因为它们已由W恢复。这就是Alan看到的。

Linus解释了这种情况:

还原常规提交只会有效撤消该提交 做到了,而且非常简单。但是还可以还原合并提交 撤消提交已更改的 data ,但绝对可以 合并对 history 的影响不大。 因此合并仍将存在,并且仍将被视为加入 这两个分支在一起,将来的合并将看到该合并为 最后的共享状态-以及还原了合并带来的还原 完全不会影响。 因此,“还原”撤消了数据更改,但是不是 “撤消”在某种意义上说不会撤消提交对 储存库历史记录。 因此,如果您将“还原”视为“撤消”,那么您将始终 错过这部分还原。是的,它撤消数据,但是不,它不会 撤消历史记录。 在这种情况下,您需要首先还原以前的还原,这会使历史记录看起来像这样:

---o---o---o---M---x---x---W---x---Y
              /
      ---A---B-------------------C---D

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

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

---o---o---o---M---x---x-------x----
              /
      ---A---B-------------------C---D

并再次合并侧分支不会因先前的还原和还原而引起冲突。

---o---o---o---M---x---x-------x-------*
              /                       /
      ---A---B-------------------C---D

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

答案 8 :(得分:1)

正确标记的答案对我有用,但是我不得不花一些时间来确定发生了什么。.因此,我决定为简单的简单步骤添加答案,例如我的情况。

让我们说我们有分支A和B。您将分支A合并为分支B,并将分支B推到自身,所以现在合并是它的一部分。。但是您想回到之前的最后一次提交 合并。.你做什么?

  1. 转到您的git根文件夹(通常为项目文件夹)并使用git log
  2. 您将看到最近提交的历史记录-提交具有commit / author / date属性,而合并也具有merge属性-因此您将看到这样的情况:

    commit: <commitHash> Merge: <parentHashA> <parentHashB> Author: <author> Date: <date>

  3. 使用git log <parentHashA>git log <parentHashB>-您将看到那些父分支的提交历史记录-列表中的第一个提交是最新的提交

  4. 获取所需提交的<commitHash>,转到git根文件夹并使用git checkout -b <newBranchName> <commitHash>-这将从您在合并之前选择的最后一个提交开始创建一个新分支。瞧,准备好了!

答案 9 :(得分:1)

如果您想恢复刚才推送的更改,这是一个非常简单的答案:

commit 446sjb1uznnmaownlaybiosqwbs278q87
Merge: 123jshc 90asaf


git revert -m 2 446sjb1uznnmaownlaybiosqwbs278q87 //does the work

答案 10 :(得分:1)

-m1是当前分支的最后一个父级,-m 2是已合并到该分支的原始父级。

如果命令行令人困惑,Tortoise Git也可以提供帮助。

答案 11 :(得分:1)

这是一个非常老的线程,但我认为方便的解决方案缺少另一个线程:

我从不还原合并。我只是从修订版本中创建了另一个分支,一切正常,然后从其中添加的旧分支中挑选了所有需要选择的事物。

因此,如果GIT历史记录是这样的:

  • d
  • c
  • b <<<合并
  • a
  • ...

我从a,樱桃接枝c和d创建一个新分支,然后从b中清除该新分支。我可以决定再次在新分支中合并“ b”。如果不再需要“ b”或仍在另一个(功能/修补程序)分支中,则不再使用旧分支,并将其删除。

现在唯一的问题是计算机科学中最困难的事情之一:您如何命名新分支? ;)

好吧,如果您失败了。在devel中,您可以如上所述创建newdevel,删除旧的devel,然后将newdevel重命名为devel。 任务完成。现在,您可以根据需要再次合并更改。就像以前从未合并过。...

答案 12 :(得分:1)

如果您想还原merge提交,这就是您要做的。

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

enter image description here

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

短篇小说:

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

长话短说

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

  2. git revert是用于还原所有提交的命令。但是,还原merge提交时有一个讨厌的把戏。您需要输入-m标志,否则它将失败。从这里开始,您需要确定是否要还原分支,并通过以下方式使其看起来完全像parent1parent2上的分支:

git revert <merge commit id> -m 1(还原为parent2

git revert <merge commit id> -m 2(还原为parent1

您可以git登录这些父母,以确定您想走哪条路,这是所有困惑的根源。

答案 13 :(得分:1)

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

git revert -m 1 <commit-hash>

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

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

答案 14 :(得分:1)

有关git revert -m的git doc提供了一个链接,准确解释了这一点: https://github.com/git/git/blob/master/Documentation/howto/revert-a-faulty-merge.txt

答案 15 :(得分:1)

我发现在两个已知端点之间创建了一个反向补丁,并且应用该补丁会起作用。这假设您已经从主分支创建了快照(标记),甚至是主分支的备份,例如master_bk_01012017。

说你合并为master的代码分支是mycodebranch。

  1. Checkout master。
  2. 在主备份和备份之间创建完整的二进制反向修补程序。 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修复问题,一旦完成就提交并重新合并为主。

答案 16 :(得分:0)

我在PR上也遇到了这个问题,该PR已合并到GitHub存储库的master分支中。

由于我只想修改一些修改过的文件,而不是PR带来的全部更改,所以我不得不amendmerge commit git commit --am

步骤:

  1. 转到您要更改/还原一些已修改文件的分支
  2. 根据修改后的文件进行所需的更改
  3. 运行git add *git add <file>
  4. 运行git commit --am并验证
  5. 运行git push -f

为什么有趣:

  • 它使PR的作者保持不变
  • 它不会破坏git树
  • 您将被标记为提交者(合并提交作者将保持不变)
  • Git就像您解决了冲突一样,它将删除/更改已修改文件中的代码,就像您手动告诉GitHub不要按原样合并它一样。

答案 17 :(得分:0)

当您在 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

答案 18 :(得分:-2)

正如Ryan所说,git revert可能会使合并困难,所以git revert可能不是你想要的。我发现使用git reset --hard <commit-hash-prior-to-merge>命令在这里更有用。

完成硬重置部分后,您可以强制推送到远程分支,即git push -f <remote-name> <remote-branch-name>,其中<remote-name>通常命名为origin。从那时起,如果您愿意,可以重新合并。