git revert a merge: determine which parent is which (-m 1 vs -m 2)

时间:2017-04-13 14:52:42

标签: git git-merge git-log git-revert

I am trying to revert a merge, but I don't know whether to use git revert -m 1 <merge commit's sha> or git revert -m 2 <merge commit's sha>. How do I find out which parent is -m 1 and which parent is -m 2?

1 个答案:

答案 0 :(得分:9)

嗯,超短的回答是,它总是-m 1。 :-)但这值得一些解释:

  • 订购了父母,git loggit show等命令显示了订单:

    commit c13c783c9d3d7d3eff937b7bf3642d2a7fe32644
    Merge: 3f7ebc6ec 39ee4c6c2
    

    所以这里3f7ebc6ec是父#1,39ee4c6c2是父#2。

  • 后缀^操作采用以下相同的值:

    $ git rev-parse c13c783c9d3d7d3eff937b7bf3642d2a7fe32644^1
    3f7ebc6ece46f1c23480d094688b8b5f24eb345c
    

    (当然...^2将是另一个)。

  • 绘制图表的程序(包括git log --graph)将向您展示这些连接方式。

  • 但最重要的是,任何合并的第一个父项是您进行合并时当前的提交。

特别是,这意味着如果您在分支main并运行git merge sidebranch,那么您现在提交的提交(如果一切顺利)或最终(如果您必须手动解决合并)拥有第一个父级,main分支的上一个提示。因此,它的第二个父母是sidebranch的提示。

那么,假设我们从头开始:

...--o--*--A--B------C   <-- main
         \
          D--E--F--G--H   <-- sidebranch

当我们运行git merge时。公共基础提交是*,Git通过这样做来实现新的合并提交M:

  1. git diff * C(我们改变了什么?)
  2. git diff * H(他们改变了什么?)
  3. 然后合并这两组更改并将其应用到*,为我们提供最终结果:

    ...--o--*--A--B------C--M   <-- main
             \             /
              D--E--F--G--H   <-- sidebranch
    

    现在,如果A-B-C中的所有内容都发生了变化,那么完全独立于D-E-F-G-H中所有内容的变化,那么 Git如何做到这一点并不重要因为它在放弃A-B-C更改的同时保持D-E-F-G-H更改。

    但是,如果BF大致相同,即BF修复错误,该怎么办?在这种情况下,我们想要撤消BF的共享更改,即Git获取了一份副本。 这是-m 1部分的来源。

    git revert撤消某些更改时,它会运行自己的git diff。它运行的git diff将您要还原的提交与其父级进行比较。对于任何普通的非合并提交,这很容易:比较B vs A,或E vs D,或者其他什么,看看发生了什么,然后退出。但是,使用合并提交,要比较哪个父项并不明显(除了它是:-))。这里的第一个父级是C,所以,如果我们运行,请查看我们得到的内容:

    git diff C M
    

    CM之间的变化是我们通过添加D-E-F-G-H到我们已经拥有的变更的变化而获得的变化A-B-C与M进行比较,请在*中找到em>。换句话说:

    • 如果BF重叠100%,则C - vs - M中的更改为D-E-G-H:所有内容除外重叠。所以我们最终会恢复那些。

    • 如果F更多更改<{1}},则B - vs - C中的更改为{{ 1}}:我们最终还原了这些更改,但不是M中的更改。

    • 如果D-E-(some-of-F)-G-H更少更改<{1}},则B - vs - F中的更改仅为{ {1}}再次,我们最终还原那些。

    由于第一个父级是B,我们要退出C更改(不包括我们已经通过M获得的任何更改),我们希望D-E-G-H在此还原