git cherry-pick为何选取意外提交?解析Git提交范围逻辑
Git提交范围的核心处理逻辑解析
我尝试使用git cherry-pick选取特定提交时,原本以为命令按提交时间选取,但实际操作出现意外,以下是三个测试场景及核心逻辑分析:
场景1
提交图:
* c666151 e6 * 14aed05 Merged commit |\ | * db8fb8c e5 | * 79fa382 e4 * | a1fde5a e3 (test1) |/ * 05e10f7 e2
执行命令:
git cherry-pick 79fa382..a1fde5a # 当前HEAD指向c666151
结果:
* gfkj56l e3(cherry-picked version of test1 branch) * c666151 e6 * 14aed05 Merged commit |\ | * db8fb8c e5 | * 79fa382 e4 * | a1fde5a e3 (test1) |/ * 05e10f7 e2
原以为会选取e5和e3,但仅得到e3,与时间顺序假设矛盾。
场景2
提交图同场景1,执行命令:
git cherry-pick a1fde5a..db8fb8c # 当前HEAD指向c666151
结果:
* jdg98df e5(cherry-picked version of db8fb8c) * gfkj56l e4(cherry-picked version of 79fa382) * c666151 e6 * 14aed05 Merged commit |\ | * db8fb8c e5 | * 79fa382 e4 * | a1fde5a e3 (test1) |/ * 05e10f7 e2
此场景中e3比e5新,但命令成功选取e4、e5,看似按拓扑顺序,但场景1的结果又不符合该猜测。
场景3
提交图同场景1,执行命令:
git cherry-pick a1fde5a..14aed05 # 当前HEAD指向c666151
结果:
* qwjk56s Merged commit(cherry-picked version of 14aed05) * jdg98df e5(cherry-picked version of db8fb8c) * gfkj56l e4(cherry-picked version of 79fa382) * c666151 e6 * 14aed05 Merged commit |\ | * db8fb8c e5 | * 79fa382 e4 * | a1fde5a e3 (test1) |/ * 05e10f7 e2
a1fde5a与14aed05间有线性路径,但命令却选取了e4、e5,令人困惑。
核心逻辑:基于拓扑关系的提交范围计算
Git处理A..B这类提交范围时,核心依据是提交的拓扑祖先/后代关系,而非提交时间。A..B的本质等价于B ^A,即:
所有能从提交B遍历到,但无法从提交A遍历到的提交(排除A及其所有祖先提交)
逐个解释场景:
- 场景1:
79fa382..a1fde5a等价于a1fde5a ^79fa382。a1fde5a的祖先链是a1fde5a → 05e10f7,79fa382的祖先链是79fa382 → 05e10f7。e5(db8fb8c)是79fa382的后代,属于79fa382的遍历范围,因此被排除;只有a1fde5a不在79fa382的遍历范围内,所以仅选中e3。 - 场景2:
a1fde5a..db8fb8c等价于db8fb8c ^a1fde5a。db8fb8c的祖先链是db8fb8c →79fa382 →05e10f7,a1fde5a的祖先链是a1fde5a →05e10f7。db8fb8c和79fa382都不在a1fde5a的遍历范围内,因此两者都被选中,即e4和e5。 - 场景3:
a1fde5a..14aed05等价于14aed05 ^a1fde5a。14aed05是合并提交,能遍历到的提交包括自身、db8fb8c、79fa382、05e10f7。排除a1fde5a及其祖先(a1fde5a、05e10f7)后,剩下14aed05、db8fb8c、79fa382,因此这三个提交都被cherry-pick。
这个拓扑优先的逻辑适用于所有支持范围语法的Git命令,包括git cherry-pick、git revert、git log等。
内容的提问来源于stack exchange,提问作者teo77
相关产品推荐
相关产品推荐

