为什么重新定位的提交ID与樱桃挑选的ID不同?

时间:2016-07-18 21:46:09

标签: git rebase cherry-pick

这个问题源于一个令人讨厌的小合并冲突,当我不小心从我的跟踪分支机构挑选到我的跟踪分支而不是重新调整它时,我进入了这个冲突。修复它很容易,但仍然试图解决为什么它首先发布。

假设我有以下分支(tracking基于tracked),一系列提交,括号中有哈希,箭头指向父提交。

tracked: a(123) <- b(234) <- c(345)

tracking: a(123) <- b(234) <- c(345)

假设提交标识d的新提交456进入tracked,以便分支的状态如下:

tracked: a(123) <- b(234) <- c(345) <- d(456)

tracking: a(123) <- b(234) <- c(345)

我现在cherry-pick 456进入tracking,导致以下跟踪状态:

tracking: a(123) <- b(234) <- c(345) <- d(somethingnot456)

但是,如果我只是执行git rebase tracked,那本来应该是:

tracking: a(123) <- b(234) <- c(345) <- d(456)

那么为什么上面的ID不同?

我见过很多关于rebase vs cherry-pick的问题,但我没有设法找到这个具体问题的答案。感谢。

2 个答案:

答案 0 :(得分:4)

Rebase和(重复)樱桃选择本质上是相同的,但它们不是100%完全相同的东西。在这种特殊情况下,关键是被复制的东西,这一点都没有。

让我以我喜欢表达Git图形片段的方式重绘您的示例。而不是:

tracked: a(123) <- b(234) <- c(345)

tracking: a(123) <- b(234) <- c(345)

让我们把它画成:

A(123) <- B(234) <- C(345)   <-- tracking, tracked

因为毕竟每次提交都是唯一的:只有一份A,一份B,一份C,很快就会成为{{1}之一}}。同时,两个标签(Dtracking)都指向提交tracked,其哈希值为C

现在您将新提交345whatever添加到D(456)(因此tracked仍然指向tracking

C(345)

Cherry-pick总是复制

A(123) <- B(234) <- C(345) <-- tracking \ D(456) <-- tracked 的作用本质上是:

  1. 将给定提交与其父级进行区分(因此,git cherry-pick <commit> vs D
  2. 在当前分支(C)上,应用相同的更改,
  3. 使用相同的消息进行提交,但ID不同。
  4. 这当然就是你以前见过的。您当前的分支(tracking)获取新提交trackingD'的副本,但编号不同。

    Rebase查找要复制需要的提交

    另一方面,Rebase的工作原理是获取当前分支(D)具有的所有提交的列表,而tracking分支(<upstream>)则没有。具体来说,这些是tracked将列出的提交:

    git rev-list

    没有这样的提交,从图纸中很容易看出。我们甚至不需要哈希:

    $ git rev-list tracked..tracking
    $ 
    

    A <- B <- C <-- tracking \ D <-- tracked 开始,我们按照标记提交的箭头向左移动,但是从tracking开始,我们按照箭头和 un 标记再次向左移动提交。由于tracked会返回D,因此会显示所有内容,而我们根本不会复制任何内容。

    如果我们在C上提交了未跟踪的

    tracking

    然后rebase将复制A--B--C--E <-- tracking \ D <-- tracked ,进行新的(不同的ID)提交EE'的副本将在E之后发布,如下所示:

    D

    然后,rebase移动分支标签

    完成所有复制A--B--C--E <-- tracking \ D <-- tracked \ E' [rebase in progress] 后,如果没有要复制的内容,则会记录它在git rebase停止的位置;在D,或者甚至是E'F'或其他任何内容,如果 提交要复制 - 然后它剥离旧的分支标签({{1} })关闭并粘贴在新点上:

    G'

    如果没有tracking要复制,我们会改为:

    A--B--C--E   [abandoned]
           \
            D    <-- tracked
             \
              E' <-- tracking
    

    ,即两个分支标签现在都指向提交E,而根本没有复制。 (没有理由在图表中保留一点点下行,并且没有放弃放弃的提交A--B--C \ D <-- tracked, tracking 不放弃D,因为E是可以找到的来自C。)

答案 1 :(得分:1)

git rebase将在另一个基本提示之上重新提交提交#34;而git cherry-pick将&#34;应用某些现有提交引入的更改&#34;。

换句话说,变基将直接在当前分支上应用提交,而樱桃挑选会将提交中的更改应用到当前分支(然后制作一个新的提交)。

rebase文档甚至在概要后明确说明了这一点:

  

如果已指定, git rebase 将在执行任何其他操作之前执行自动git checkout <branch>。否则它将保留在当前分支上。

因此,在使用git rebase tracked时,您基本上只是执行了git checkout tracked并快速转发了您的tracking分支...