在Git rebase期间使用什么算法?

时间:2016-09-01 19:55:42

标签: git

我找不到任何关于Git如何在内部制作rebase的解释。虽然,我没有考虑消息来源。 :)

最常见的答案是在基础提交上应用补丁但不是真的。无法将补丁正确应用于(可能)完全更改的文件。还提到了三向合并,但没有确切地说明实际合并的是什么。

由于

2 个答案:

答案 0 :(得分:7)

如果你仔细研究Git代码,你会发现实际上有多种不同的内部算法用于rebase。

首先,将rebase拆分为一个非形容词修改版本(内部为git-rebase--am,默认使用git am来应用Git使用git format-patch生成的补丁,并且交互式 rebase(内部,git-rebase--interactive)。

反过来,交互式rebase 代码使用自己的多种不同算法。 (就非交互式代码而言,仅限于使用-k时。)

你可以想到这一点,因为每个提交都像git cherry-pick一样复制了 。基于git am的版本存在一些细微差别,但说明它们很棘手,而在交互式rebase的情况下,大多数提交都使用git cherry-pick(请参阅$(git --exec-path)/git-rebase--interactive并查找Git命令; fixup和squash use git commit --amend)。 编辑:在现代Git(2.12及更高版本)中,Git现在使用其“音序器”代替交互式脚本,但效果是一样的。

然后,更有趣的是git am和/或git cherry-pick的工作方式。答案很长而且很无聊,可能最好缩短为“查看源代码”,但简短的回答是:git am 尝试首先将更改应用为补丁,并且只有当失败时,才会回到完全三向合并。有关简要说明,请参阅-3中的git am标记。同时git cherry-pick只进行直接的三向合并。

此处使用的合并基础通常不是那么有用。考虑这个初始DAGlet和git rebase打算将A复制到A'BB',在提交D之后附加这些:< / p>

       A--B        <-- branch
      /
...--*------C--D   <-- origin/branch

第一个樱桃选择操作正在挑选A,因此它针对提交A(两个分支的合并基础)区分提交*。使用git am方法,Git会尝试将其应用为D上的补丁。如果失败,或者您正在使用导致git cherry-pick的交互式rebase,则提交(如果是挑选)或每个失败的文件(如果git am - ing)-get通过三向运行合并过程。

这实际上非常合理:在处理* - 至 - A后,我们真的想重播* - 至 - D。最终结果是A'

       A--B        <-- branch
      /
...--*------C--D   <-- origin/branch
                \
                 A'    [detached HEAD]

但现在我们复制Bgit am表示生成从AB的补丁。对于适用的补丁部分,我们只应用它们。对于存在冲突的文件,这次我们从A - vs - BA - vs - A'区分文件,为每个文件进行低级文件合并使用这些差异无法修补文件。 A在这里不是一个很好的合并基地;它总比没有好。

对于actul git cherry-pick rebase,Git使用整个提交A作为合并基础,并在整个树上进行正常的三向合并。每个文件的合并基础都是提交A的文件版本。

(如果我们有更多提交超过B,那么剩下的将继续提交。)

很容易看出必须是非交互式的情况:

git format-patch -k --stdout --full-index --cherry-pick --right-only \
    --src-prefix=a/ --dst-prefix=b/ --no-renames --no-cover-letter \
    "$revisions" ${restrict_revision+^$restrict_revision} \
    >"$GIT_DIR/rebased-patches"
...
git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" \
    ${gpg_sign_opt:+"$gpg_sign_opt"} <"$GIT_DIR/rebased-patches"

代码,因为git am只获取用于构造基本文件的Index:行。找到git rebase代码更加棘手,因为关键位埋在sequencer.c深处。

答案 1 :(得分:4)

  

最常见的答案是在基础提交上应用补丁但不是真的。没有办法正确地将补丁应用于(可能)完全更改的文件。

是真的 - rebase基本上正在执行cherry-pick以及其他一些簿记。

但你的第二句话也是正确的 - 如果文件已完全改变,当你尝试改变时,你可能会遇到冲突。