为什么"樱桃采摘"开始了..结束"返回冲突时"变基--onto"没有?



我最近在运行git cherry-pick时遇到了意外冲突:

git checkout myBranch
git cherry-pick begin..end

我认为"这毫无意义",中止了,并尝试了我所理解的等效git rebase --onto

git rebase --onto myBranch begin end

瞧!干净的变基,没有意外的冲突。

我感到惊讶是对的吗?您认为某处是否存在用户错误,或者rebase --ontocherry-pick背后的流程是否存在根本差异,可能导致这种情况?

 

编辑:在cherry-pickbeginend是SHAs。在rebase中,begin是用于cherry-pickbegin的SHA的同一名称,end是一个分支的名称,其尖端位于cherry-pickend提交处。

TL;DR 一行摘要:git rebase省略了任何已经挑选的提交。


git rebase复制的内容并不完全是你想的那样。 (我承认我在这里猜测了你的想法......但如果结果是惊喜,那一定是真的。

根据文档,从形式上讲,这些参数是[--ontonewbase]upstream[branch]. 那是:

git rebase --onto myBranch begin end

表示end被视为分支名称:

git checkout end

之后,根据文档(但它是谎言),要挑选的提交是由git rev-listgit 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..HEADbegin..end)产生相同的列表,并且我们开始复制提交(newBranch)的点也是相同的,因此任何行为的改变都必须是由于省略步骤。 如果您要签出myBranch的原始提示提交并运行:

git rev-list ... | git cherry-pick --stdin

(其中...使用--cherry-pick --right-only --no-merges三点公式并指定beginend在所有这些更改之前用于标识的提交),它也应该正常工作,就像git rebase所做的那样。


1合并提交不是这里的问题。 若要挑选合并,git cherry-pick要求您提供-m参数。 但是,如果有任何非合并提交,git cherry-pick禁止-m参数。 由于显然有一些非合并,也没有关于-m的投诉,我们没有进行合并提交。

最新更新