git rebase 是否需要一个共同的提交祖先?
Does git rebase ever require a common commit ancestor?
在试验 git 时,我创建了两个没有共同提交祖先的分支。我们称他们为“主人”和“其他”。当前分支是“master”。
正如预期的那样,尝试通过以下方式合并“其他”:
git merge other
制作:fatal: refusing to merge unrelated histories
这正是我所期望的。令我惊讶的是,运行 通过以下方式变基:
git rebase other
成功。
这让我感到惊讶,因为我认为变基需要一个共同的提交祖先,就像 git 合并一样。 git rebase 是否需要一个共同的祖先?
我认为理解这一点的方法,就像很多关于 rebase
的内容一样,是理解两件事:
rebase
只是 cherry-pick
:它根据连续的差异创建新的提交,将旧的留在原地,并将它们附加到目标。不同之处仅在于,之后,cherry picking 会推进目标分支名称,而 rebasing 会转移源分支名称。
git rebase xxx
是一个shorthand。因此,结果可能会令人惊讶。
git rebase
的完整形式是 git rebase --onto x y z
,意思是:“从(但不包括)y
开始,挑选每个连续的提交到 x
直到您精心挑选 z
."
当你使用shorthand形式时,x
通常是你指定的提交,z
是当前分支,y
是共同祖先两人
但在某些情况下 shorthand 无法正常工作。在this的情况下,没有共同的祖先。因此,对于 y
,Git 选择“根”,即虚无 — 就像您使用 --root
选项的完整形式一样。
为了说明,让我们假设分支 one
由提交 a
和 b
组成,分支 two
由提交 c
组成,然后d
:
a <-- b (one)
c <-- d (two)
那么如果你在two
,你说git rebase one
,one
就是b
,所以Git从two
向后走(d
) 到 c
并自言自语:我可以挑选 diff “nothingness-to-c
”到 b
吗?如果是这样(因为没有冲突),它确实如此。然后它说:我可以选择差异“c
-to-d
”到我刚刚创建的提交上吗?如果是这样,它确实如此。这就是结束——我们已经到达当前分支提交——所以它停止,并将当前分支指针(HEAD
)移动到它创建的最后一个新提交:
a <-- b <-- c' <-- d' (two)
^
(one)
请注意 c'
和 d'
是副本(即由 Git 创建的新提交)。原来的 c
和 d
仍然存在,但现在没有分支名称指向它们,最终它们将通过垃圾收集被删除。
在试验 git 时,我创建了两个没有共同提交祖先的分支。我们称他们为“主人”和“其他”。当前分支是“master”。
正如预期的那样,尝试通过以下方式合并“其他”:
git merge other
制作:fatal: refusing to merge unrelated histories
这正是我所期望的。令我惊讶的是,运行 通过以下方式变基:
git rebase other
成功。
这让我感到惊讶,因为我认为变基需要一个共同的提交祖先,就像 git 合并一样。 git rebase 是否需要一个共同的祖先?
我认为理解这一点的方法,就像很多关于 rebase
的内容一样,是理解两件事:
rebase
只是cherry-pick
:它根据连续的差异创建新的提交,将旧的留在原地,并将它们附加到目标。不同之处仅在于,之后,cherry picking 会推进目标分支名称,而 rebasing 会转移源分支名称。git rebase xxx
是一个shorthand。因此,结果可能会令人惊讶。
git rebase
的完整形式是 git rebase --onto x y z
,意思是:“从(但不包括)y
开始,挑选每个连续的提交到 x
直到您精心挑选 z
."
当你使用shorthand形式时,x
通常是你指定的提交,z
是当前分支,y
是共同祖先两人
但在某些情况下 shorthand 无法正常工作。在this的情况下,没有共同的祖先。因此,对于 y
,Git 选择“根”,即虚无 — 就像您使用 --root
选项的完整形式一样。
为了说明,让我们假设分支 one
由提交 a
和 b
组成,分支 two
由提交 c
组成,然后d
:
a <-- b (one)
c <-- d (two)
那么如果你在two
,你说git rebase one
,one
就是b
,所以Git从two
向后走(d
) 到 c
并自言自语:我可以挑选 diff “nothingness-to-c
”到 b
吗?如果是这样(因为没有冲突),它确实如此。然后它说:我可以选择差异“c
-to-d
”到我刚刚创建的提交上吗?如果是这样,它确实如此。这就是结束——我们已经到达当前分支提交——所以它停止,并将当前分支指针(HEAD
)移动到它创建的最后一个新提交:
a <-- b <-- c' <-- d' (two)
^
(one)
请注意 c'
和 d'
是副本(即由 Git 创建的新提交)。原来的 c
和 d
仍然存在,但现在没有分支名称指向它们,最终它们将通过垃圾收集被删除。