我知道我可以使用git merge-base
来确定执行git merge
,时的共同祖先,但看起来这不适用于 git rebase
< / p>
以下是rebase
之前的设置:
master branch
:A--Y--(C)
和dev branch
:A-----C--D
(C)是我将A - C变为A - Y的结果,相同的内容,但不同的提交信息
git merge-base master dev
会返回A,如果我git merge dev
,我会在历史记录中看到(C)和C
git rebase master
,结果是:
A - Y - (C) - (D)其中(D)在rebase后是D
git rebase
是否认为(C)是共同的祖先? (这在代码中很难做到)我猜它仍然使用A,但是当它选择C,D追加到master
的末尾时,C最终成为 no-op
答案 0 :(得分:3)
让我们从这开头:git rebase
做什么是复制一些提交。在您的情况下,它似乎复制提交C
但不提交D
。 (我想你问为什么,但是假设它与合并基础有关,这可能不正确。)
git rebase
选择复制的提交集合主要是但不完全,由以下结果决定:
git rev-list <upstream>..HEAD
其中<upstream>
是您传递给git rebase
或已配置上游的参数。例如,对于git rebase master
,此序列中的<upstream>
为master
。您当前的分支是dev
,因此HEAD
引用dev
。因此,要复制的提交集是按以下列出的:
git rev-list master..dev
(虽然增加了其他选项;见下文)。
如果我正确阅读你的图表,输入图表是:
...--A--Y <-- master
\
C--D <-- dev
这样git rev-list
的输出就会提交C
和D
。
Rebase然后继续:
git checkout
目标分支的提示(此处提交Y
); git cherry-pick
和C
时,有时字面上,有时比喻性地D
;最后checkout -B dev HEAD
(不完全相同,但效果相同:在dev
移动到指向最终复制的提交后,返回dev
。我认为你直接询问的是 - 我认为这不是你应该要求的 - 在采摘过程中哪个提交被用作合并基础。这里的答案是,樱桃选择的合并基础是樱桃选择的父提交。因此,对于git cherry-pick C
步骤,合并基础(如果需要合并)是提交A
:C
的父级。对于git cherry-pick D
步骤,合并基础(如果需要合并)是提交C
:D
的父级。
现在,我列出了几个&#34;其他选项&#34;上面的项目。这些是指提交选择过程。特别是,git rebase
有两种方法可以提交 off 的提交#34;复制&#34;名单。 (它还会按照通常的向后顺序生成列表,因此它会在转发顺序中进行挑选。)
它消除to-copy列表提交的主要方式是使用git patch-id
。 git patch-id
命令计算一个ID号,人们希望它足够独特&#34;,基于通过比较提交到其直接父级而找到的补丁,丢弃行号和其他一些可能的项目影响樱桃挑选的提交。如果提交已被挑选,则结果应为相同的 ID,否则不同。
因此,在列出C
和D
之后,Git继续将其补丁ID与提交Y
的补丁ID进行比较。
有两个命令可以执行此类操作,一个用于用户,另一个用于git rev-list
。面向用户的命令是git cherry
,但我想在这里,面向计算机的git rev-list
实际上更容易解释。
这里有趣的是Git知道如何将提交C
和D
的所有修补程序ID与提交Y
的修补程序ID进行比较,当初始图形是我们的时候如上所示。或者,如果图表是:
...--A--E--F--G <-- master
\
C--D <-- dev
要比较的两组补丁ID将是(C,D)与(E,F,G)的补丁ID。如果我们有:
H--I
/ \
...--A--G---J--K <-- master
\
\ D
\ / \
C F <-- dev
\ /
E
要比较的集合将是(C,D,E,F)vs(G,H,I,J,K)。我认为,这使得整个概念更加清晰:它的工作方式是git rev-list
可以检查两个分支到他们遇到的点,并收集一组提交每个&#34; side&#34;。
我们git rev-list
执行此操作的方式是:
git rev-list --left-right master...dev
(请注意此处的三个点,dev
和master
的顺序仅用于确定哪些提交是&#34;左侧&#34; -on master
但不是在dev
上 - dev
上的&#34;右侧&#34;,但master
上没有。
这个三点符号以及这个--left-right
的想法是Git如何计算出哪些提交放在哪个集合中,以便计算完整的补丁ID集。如果左侧提交的修补程序ID与右侧提交的修补程序ID相同,那些提交虽然在某种程度上有所不同,但代表相同的更改:它们是具有的已被挑选出来。
git rebase
命令跳过这些预先挑选的樱桃。它只是挑选剩余的提交,无论那些是什么。 git rebase
代码运行git rev-list --right-only --cherry-pick --no-merges <upstream>..HEAD
以获取要在步骤2中复制的提交列表。然后它运行这三个步骤。如果C
或D
的修补程序ID与提交Y
的修补程序ID匹配,则该提交永远不会被复制。在这种情况下,似乎提交D
的修补程序ID可能与提交Y
匹配。
我还说有两种方法可以消除提交。这种樱桃检测就是其中之一,我怀疑它是你看到我认为你看到的结果的原因。另一个是Git所谓的--fork-point
,这有点复杂。我不打算在这里介绍它。它只省略了早期&#34;提交:也就是说,它在C--D
链上找到了一个点 - 如果链条更长 - 这会更有意义 - 它认为它应该丢弃,只有副本提交在之后。由于提交C
被复制,因此它不能是导致提交D
被省略的fork-point代码。