我最近在运行git cherry-pick
时遇到了意外冲突:
git checkout myBranch
git cherry-pick begin..end
我认为"这毫无意义",中止了,并尝试了我所理解的等效git rebase --onto
:
git rebase --onto myBranch begin end
瞧!干净的变基,没有意外的冲突。
我感到惊讶是对的吗?您认为某处是否存在用户错误,或者rebase --onto
和cherry-pick
背后的流程是否存在根本差异,可能导致这种情况?
编辑:在cherry-pick
,begin
和end
是SHAs。在rebase
中,begin
是用于cherry-pick
begin
的SHA的同一名称,end
是一个分支的名称,其尖端位于cherry-pick
的end
提交处。
TL;DR 一行摘要:git rebase
省略了任何已经挑选的提交。
git rebase
复制的内容并不完全是你想的那样。 (我承认我在这里猜测了你的想法......但如果结果是惊喜,那一定是真的。
根据文档,从形式上讲,这些参数是[--ontonewbase]upstream[branch]
. 那是:
git rebase --onto myBranch begin end
表示end
被视为分支名称:
git checkout end
之后,根据文档(但它是谎言),要挑选的提交是由git rev-list
或git log
在给定upstream..HEAD
时产生的提交:
分支中但不在<上游>的提交所做的所有更改都将保存到临时区域。这是
git log <upstream>..HEAD
显示的同一组提交;或按git log 'fork_point'..HEAD
,如果--fork-point
处于活动状态(请参阅下面的--fork-point
说明);或按git log HEAD
,如果指定了--root
选项。上游>
--fork-point
或--root
选项都不适用,因此我们只剩下:
git log begin..HEAD
由于HEAD
现在指的是end
,这与begin..end
相同。但是,正如我刚刚指出的,文档是谎言! 嗯,至少有一点。 然后,它会更正要说的话:
请注意,HEAD中引入与HEAD中的提交相同的文本更改的任何提交。<上游>被省略...上游>
这里还应该提到,git rebase
也省略了合并提交。 我们实际需要的是更复杂的:
git rev-list --cherry-pick --right-only --no-merges begin...HEAD
(注意三个点而不是两个点)。 也就是说,我们检查begin..HEAD
,以找到可能采取的提交(--right-only
);但是,然后我们通过HEAD..begin
(begin...HEAD
中的三个点)查看我们可以接受但决定不这样做的提交,因为它们已经被采用(--cherry-pick
)。 从生成的提交列表中,我们还抛出任何合并提交1(--no-merges
)。
鉴于两个两点X..Y
公式(begin..HEAD
和begin..end
)将产生相同的列表,并且我们开始复制提交(newBranch
)的点也是相同的,因此任何行为的改变都必须是由于省略步骤。 如果您要签出myBranch
的原始提示提交并运行:
git rev-list ... | git cherry-pick --stdin
(其中...
使用--cherry-pick --right-only --no-merges
三点公式并指定begin
和end
在所有这些更改之前用于标识的提交),它也应该正常工作,就像git rebase
所做的那样。
1合并提交不是这里的问题。 若要挑选合并,git cherry-pick
要求您提供-m
参数。 但是,如果有任何非合并提交,git cherry-pick
禁止-m
参数。 由于显然有一些非合并,也没有关于-m
的投诉,我们没有进行合并提交。