为什么变基的提交 ID 与精心挑选的 ID 不同



这个问题源于一个令人讨厌的小合并冲突,当我不小心从我的跟踪分支中挑选到我的跟踪分支而不是变基时,我自己陷入了这种冲突。修复它很容易,但仍然试图让我弄清楚为什么它首先是一个问题。

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

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

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

假设一个提交 ID 456 的新提交d进入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 会有所不同呢?

我见过很多关于rebasecherry-pick的问题,但我还没有找到这个特定问题的答案。谢谢。

变基和(重复(樱桃采摘本质上是一回事,但它们不是 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副本,很快就会成为D之一。 同时两个标签(trackingtracked(都指向提交C,其哈希值为345whatever

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

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

樱桃采摘总是复制

git cherry-pick <commit>所做的本质上是:

  1. 将给定的提交与其父提交进行比较(因此,D vs C (
  2. 在当前分支 ( tracking 上 (,应用相同的更改,并且
  3. 使用相同的消息但不同的 ID 进行提交。

这当然只是你以前看到的。 你当前的分支(tracking(获取新的提交D'D的副本,但编号不同。

变基查找需要复制的提交

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

$ git rev-list tracked..tracking
$ 

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

A <- B <- C     <-- tracking
           
            D   <-- tracked

tracking 开始,我们按照标记提交的箭头向左工作,但从tracked开始,我们再次按照箭头和取消标记提交向左工作。 由于D导致回到C,这取消了所有内容,我们根本不复制任何东西。

如果我们在tracking上有一个被跟踪的提交:

A--B--C--E   <-- tracking
       
        D    <-- tracked

然后变基将复制E,使一个新的(不同的ID(提交E'E的副本将在D之后,如下所示:

A--B--C--E   <-- tracking
       
        D    <-- tracked
         
          E' [rebase in progress]

然后,变基移动分支标签

一旦git rebase完成了所有的复制,它就会记下它停止的位置——在D,如果没有要复制的东西;在E',或者甚至可能是F'G',或者如果有要复制的提交——然后它剥离旧的分支标签(tracking(并将其粘贴到新点上:

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

当没有要复制E时,我们会得到这个:

A--B--C
       
        D   <-- tracked, tracking

也就是说,两个分支标签现在都指向提交D,而提交根本没有被复制。 (也没有理由在图表中保留向下的小腿,也没有要放弃的提交 - 放弃E不会放弃C,因为可以从D中找到C

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

换句话说,变基将直接在当前分支之上应用提交,而樱桃采摘会将提交中的更改应用到当前分支上(然后进行新的提交(。


变基文档甚至在概要之后明确指出了这一点:

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

所以,当使用git rebase tracked时,你基本上只是做了git checkout tracked并快进你的tracking分支......

相关内容

  • 没有找到相关文章

最新更新