【发布时间】:2017-09-09 18:24:38
【问题描述】:
我正在尝试还原合并,但我不知道是使用git revert -m 1 <merge commit's sha> 还是git revert -m 2 <merge commit's sha>。如何找出哪个父级是-m 1,哪个父级是-m 2?
【问题讨论】:
标签: git git-merge git-log git-revert
我正在尝试还原合并,但我不知道是使用git revert -m 1 <merge commit's sha> 还是git revert -m 2 <merge commit's sha>。如何找出哪个父级是-m 1,哪个父级是-m 2?
【问题讨论】:
标签: git git-merge git-log git-revert
嗯,超级简短的答案是它始终是-m 1。 :-) 但这值得解释一下:
父母是有序的,像git log和git show这样的命令会显示顺序:
commit c13c783c9d3d7d3eff937b7bf3642d2a7fe32644 Merge: 3f7ebc6ec 39ee4c6c2
所以这里3f7ebc6ec 是父#1,39ee4c6c2 是父#2。
后缀^ 操作采用这些相同的值:
$ git rev-parse c13c783c9d3d7d3eff937b7bf3642d2a7fe32644^1 3f7ebc6ece46f1c23480d094688b8b5f24eb345c
(当然...^2 是另一个)。
绘制图形的程序(包括git log --graph)将向您展示它们之间的联系方式。
但最重要的是,任何合并的第一个父级是您进行合并时的当前提交。
特别是,这意味着如果您在分支 main 并运行 git merge sidebranch,那么您现在(如果一切顺利)或最终(如果您必须手动解决合并)所做的提交,因为它first 父级,main 分支的前一个提示。因此,它的第二个父节点是sidebranch 的尖端。
然后,假设我们有这样的开始:
...--o--*--A--B------C <-- main
\
D--E--F--G--H <-- sidebranch
当我们运行git merge。常见的基本提交是*,Git 通过做一个新的合并提交 M,本质上是:
git diff * C(我们改变了什么?)git diff * H(他们改变了什么?)然后结合这两组更改并将它们应用到*,给我们这个最终结果:
...--o--*--A--B------C--M <-- main
\ /
D--E--F--G--H <-- sidebranch
现在,如果 A-B-C 中更改的所有内容都完全独立于 D-E-F-G-H 中更改的所有内容,那么只要保留A-B-C 更改,同时放弃 D-E-F-G-H 更改。
但是如果B 与F 基本相同,即B 和F 都修复了一个错误怎么办?在这种情况下,我们不想要撤消 Git 复制一份来自 B 和 F 的共享更改。 这就是-m 1 部分的用武之地。
当git revert 撤消某些更改时,它会运行自己的git diff。它运行的git diff 将您要恢复的提交与其父级进行比较。对于任何普通的非合并提交,这很容易:比较B 与A,或E 与D,或其他任何东西,看看发生了什么,然后退出。但是,通过合并提交,与哪个父级进行比较并不明显(除了它是 :-) )。这里的第一个父级是C,所以让我们看看如果我们运行会得到什么:
git diff C M
C 和 M 之间的更改是我们通过添加从D-E-F-G-H 到我们在A-B-C 中已经拥有的更改而获得的更改,如果我们比较 M 和 *。换句话说:
如果 B 和 F 重叠 100%,则 C-vs-M 中的变化是 D-E-G-H:所有 除了重叠。所以我们最终只恢复了那些。
如果F 比B 有更多 个变化,那么C-vs-M 的变化就是D-E-(some-of-F)-G-H:我们最终会恢复这些变化,但不是B 中的那些。
如果F 的变化比B 少,那么C-vs-M 的变化又是D-E-G-H,我们结束了只还原那些。
由于第一个父级是 C,并且我们想要撤销 D-E-F-G-H 的更改(不包括我们已经通过 A-B-C 进行的任何更改),我们希望 -m 1 在此还原中。
【讨论】: