这个问题源于一个令人讨厌的小 merge 冲突,当我不小心从跟踪分支中挑选到跟踪分支而不是重新定位它时,我陷入了这个冲突。修复它非常容易,但我仍然试图弄清楚为什么它首先会出现问题。
假设我有以下分支( tracking
基于 tracked
),其中包含一系列提交,括号中包含哈希值,箭头指向父提交。
tracked: a(123) <- b(234) <- c(345)
tracking: a(123) <- b(234) <- c(345)
假设一个提交 ID 为 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
与 cherry-pick
的问题,但我还没有找到这个特定问题的答案。谢谢。
最佳答案
Rebase 和(重复的)cherry-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
副本之一。同时,两个标签( tracking
和 tracked
)都指向提交 C
,其哈希值是 345whatever
。
现在,您将新的提交 D(456)
添加到 tracked
(因此 tracking
仍然指向 C(345)
:
A(123) <- B(234) <- C(345) <-- tracking
\
D(456) <-- tracked
精挑细选总是复制
git cherry-pick <commit>
的作用本质上是:
- 将给定提交与其父提交进行比较(因此,
D
与C
) - 在当前分支 (
tracking
) 上应用相同的更改,并且 - 使用相同的消息但不同的 ID 进行新提交。
这当然只是您以前见过的。您当前的分支 ( tracking
) 获取新的提交 D'
: D
的副本,但编号不同。
Rebase 发现哪些提交需要被复制
另一方面,Rebase 的工作原理是获取当前分支 ( 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
然后 rebase 将复制 E
,创建一个新的(不同 ID)提交 E'
。 E
的副本将放在 D
之后,如下所示:
A--B--C--E <-- tracking
\
D <-- tracked
\
E' [rebase in progress]
然后,rebase移动分支标签
一旦 git rebase
完成所有复制,它会记录它停止的位置 - 如果没有任何内容可复制,则在 D
处;在 E'
,或者甚至 F'
或 G'
或其他任何地方(如果有were 提交复制),然后剥离旧分支标签 ( tracking
) 并将其粘贴到新点上:
A--B--C--E [abandoned]
\
D <-- tracked
\
E' <-- tracking
当没有 E
可供复制时,我们会得到以下内容:
A--B--C
\
D <-- tracked, tracking
即,两个分支标签现在都指向提交 D
,它根本没有被复制。 (也没有理由保留图中向下的小腿,并且没有要放弃的提交 - 放弃 E
不会放弃 C
,因为 C
可以从 D
中找到。)
关于git - 为什么重新调整的提交 ID 与精心挑选的 ID 不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38446493/