我正在尝试了解git revert
如何从
https://stackoverflow.com/a/37151159
假设当前分支为B
,命令git revert C
是否创建提交D
,因此B
是{{1}的三向合并的结果}和C
相对于D
吗?
答案 0 :(得分:1)
我不知道你如何看待它...但是我是这样看的:
git revert C
,当您站在B上时,要求git在B和C〜之间进行三向合并,假设(迫使git认为)两个修订版的分支点为C。
定义:分支点在正常情况下,这是两个分支的历史记录中存在的最后一个修订。修订后,两个分支的历史不再共享另一个共同祖先。
答案 1 :(得分:1)
git revert
的作用是使用非常规选择的合并基础进行三向合并。除了选择的合并基础不同之外,其他操作与git cherry-pick
相同。
在所有情况下,我们都可以绘制出提交图:
...--o--o--C1--C2--...--o <-- somebranch
\
o--o--L <-- our-branch (HEAD)
或:
...--o--C1--C2--o--...--L <-- our-branch (HEAD)
或类似的图形(绘制任何您的图的样子)。
您告诉Git:樱桃选择C2
或还原C2
。您的当前提交是L
,可通过HEAD
找到。 Git现在继续执行三向合并操作。与此不同的是,以下称为 B 的 merge base 是C1
或C2
,而另一个提交是 R 也为C1
或C2
-并非合并基础。对于git cherry-pick
, B = C1
和 R = C2
。对于git revert
, B = C2
和 R = C1
。
所有Git合并都以相同的方式实现。 1 我们从三个提交开始 2 :
--ours
提交 L 。 git mergetool
代码将其称为“本地”,但大多数Git命令仅将其称为HEAD
或--ours
。--theirs
提交 R 。 git mergetool
代码将其称为“远程”,而git merge
本身则使用MERGE_HEAD
。从图中可以明显看出许多实际合并的合并基础:
o--...--L <-- our-branch (HEAD)
/
...--o--B
\
o--...--R <-- their-branch
对于樱桃选择或还原,强制将 B 和 R 提交至某些特定的提交。例如,如果您运行git revert <hash>
,则 B 是您标识的提交,而 R 是其父级:
...--o--R--B--o--...--L <-- our-branch (HEAD)
现在,有了三个提交 B , L 和 R 或它们的哈希ID,Git将实际上,运行两次 git diff
操作:
git diff --find-renames B L
git diff --find-renames B R
第一个差异查找在底部和左侧之间不同的文件(包括该间隙中所有重命名的文件)。第二个差异查找的是底部和右侧之间不同的文件,同样包括任何重命名的文件。
任何在 端均未更改的文件在所有三个提交中均相同。合并结果是所有三个提交共享的文件的(单个)版本。
任何仅在一个一侧进行过更改的文件,Git都会从该侧获取文件的版本。
任何在双方上都更改过但内容相同的文件,Git可以使用 L 或 R 复制。根据定义,这两个副本是相同的,因此Git选择一个(实际上总是 L ,因为它更方便-Git直接在索引中完成所有这些工作,并且这避免了移动 L 文件首先从插槽0移出!)。
最后,对于在两端进行了任何更改的文件,Git都会尝试-可能成功或失败-组合两个更改集。合并的更改将应用于来自基本提交 B 的文件副本。如果合并成功,那就是合并的结果。否则,Git会尽最大努力在工作树中进行合并,并因合并冲突而停止。 3 添加-X ours
或-X theirs
会告诉Git:而不是停止发生冲突时,请通过从差异中选择我们的请求来解决此冲突。请注意,这是 only 情况,实际上必须填充文件的三个索引槽,并且然后调用低级合并代码(或设置为.gitattributes
的合并驱动程序)。
成功的结果会自动由git merge
提交为合并提交,或者由git cherry-pick
或git revert
作为普通提交,除非您告诉Git不要提交结果。失败(由于冲突)合并将停止,在索引和工作树中留下一团糟,您必须清除它们。
1 Git所谓的章鱼合并仍然可以像这样工作,但是它是迭代的,反复将多个分支提示合并到索引中,而没有提交结果。这使得它有点特殊,因为在索引中ours
状态仅是 ,而不是实际的提交。其他Git命令通常检查索引和HEAD
提交是否匹配,除了git cherry-pick -n
和git revert -n
只是使用索引就像是提交一样,章鱼合并的方式相同。在上面的主要答案文本中,您可以将索引的内容视为ours
提交:在内部,Git只是将所有处于阶段0的条目都移到了阶段2来实现此目的。
2 对于git merge -s recursive
或git merge
调用的递归合并,Git首先为您查找合并基础。这可能会出现多个提交。如果发生这种情况,Git将使用git merge
(的内部版本)合并合并基础。这是“递归合并”的递归部分:合并合并基础,以便提出单个提交。这样,该一次提交就是最外面的git merge
的合并基础。
如果您使用git merge -s resolve
,并且Git找到多个合并基础,则Git选择一种更简单的方法:它以(看起来像)随机(不是真正随机)选择一个合并基础。哪一个最容易从其合并基础查找算法中得出,但并没有受到仔细控制;没有内在的理由偏爱任何一个候选合并基础。
3 对于在合并两个合并库时发生的递归(内部)合并期间的合并冲突,Git只会提交冲突的文本。结果不是很漂亮。