- LOCAL: 我的分支中的版本
- REMOTE: 其他分支中的版本
- BASE: 两个分支共同祖先的版本(特别是,我的分支HEAD和其他分支HEAD的共同祖先)
挑选
除非我自己误导了自己,否则如果您执行 "git cherry-pick <commit C>",则会得到以下结果:
如果不清楚为什么 BASE 应该是 C^,请参阅下面的“why”部分。
同时,让我们举一个例子,并查看在挑选过程中 BASE 可能是,但通常不是常见祖先。假设提交图像如下:
E <-- master
|
D
| C <-- foo_feature(*)
|/
B
|
A
你现在在foo_feature分支(因此有星号)。如果你执行命令“git cherry-pick <commit D>”,那么该cherry-pick的BASE将是提交B,它是C和D的共同祖先。(C将是LOCAL,D将是REMOTE。)然而,如果你改为执行“git cherry-pick <commit E>”,那么BASE将是提交D。(C将是LOCAL,E将是REMOTE。)
变基
为了提供背景信息,变基大致上是迭代式地进行 Cherry-pick。特别是,在主分支上重置topic分支(即“git checkout topic; git rebase master”)意味着大约执行以下操作:
git checkout master # switch to master's HEAD commit
git checkout -b topic_rebased # create new branch rooted there
for each commit C in master..topic # for each topic commit not already in master...
git cherry-pick C # bring it over to the new branch
finally, forget what "topic" used to mean and now defined "topic" as the HEAD of topic_rebased.
在此过程中应用的标签是常规 Cherry-pick 规则的扩展:D <-- foo_feature(*)
|
| C <-- master
B |
|/
|
A
我们目前在foo_feature分支上(由“*”表示)。如果运行“git rebase master”,则rebase将分两步进行:
首先,B的更改将被重放在C之上。此期间,C为LOCAL,B为REMOTE,A为BASE。请注意,A是B和C的实际共同祖先。完成第一步后,您将获得一个大致如下的图形:
B' <-- foo_feature
D |
| |
| C <-- master
B /
|/
|
A
(在现实生活中,B和D可能已经在这个阶段被剪枝了,但为了更容易地发现任何可能的共同祖先,我将它们留在这里。)
其次,D所做的更改将会在B'的基础上重新应用。此时,B'是LOCAL,D是REMOTE,而B是BASE。请注意,B并不是任何内容的相关共同祖先。(例如,它不是当前LOCAL和REMOTE(即B'和D)的共同祖先,也不是原始分支头C和D的共同祖先)。在此步骤之后,您将得到一个类似于以下的分支:
D' <-- foo_feature
|
B'
D |
| |
| C <-- master
B /
|/
|
A
为了完整起见,需要注意的是,在变基结束时,图表中的 B 和 D 被删除,结果如下:
D' <-- foo_feature
|
B'
|
C <-- master
|
A
为什么 BASE 被定义为它现在的样子?
如上所述,无论是 cherry-pick 还是 rebase,BASE 都是要被拉入的提交 C 的父提交 (C^)。在一般情况下,C^ 并不是一个共同的祖先,那么为什么称之为 BASE? (在普通合并中,BASE 是一个共同的祖先。而 git 在合并中成功的部分原因是能够找到一个好的共同祖先。)
基本上,这样做是为了通过常规的三方合并算法实现“补丁”功能。特别是你会得到以下“补丁”的属性: