为什么 Git rebase 不像 Darcs 那样需要指数时间?
Why doesn't Git rebase take exponential time like Darcs?
因此根据 this 维基百科关于版本控制合并的页面,Darcs 使用补丁交换,Git 在变基时也是如此。
我很想知道为什么 Git rebase 在某些情况下不像 Darcs 那样花费指数时间?
This 页面列出了 Darcs 何时可能发生的一系列案例以及如何尝试解决这些问题。
我没有使用过 darcs 并且可能在这里偏离了基础,但是通过浏览维基百科文章,我发现它在这里的说法具有误导性:
Patch commutation is used in Darcs to merge changes, and is also implemented in git (but called "rebasing"). Patch commutation merge means changing the order of patches (i.e. descriptions of changes) so that they form a linear history. In effect, when two patches are made in the context of a common situation, upon merging, one of them is rewritten so that it appears to be done in the context of the other.
Git既不存储补丁,也不对其重新排序。1您可以根据需要手动重新排序补丁。当您使用 git rebase
将提交(即快照)转换为变更集时,转换本身以一种简单的方式完成,即 其中 n 是行数,d 是编辑的长度脚本。 (这是作为补丁还是作为合并处理的 cherry-pick,取决于您选择的变基算法;合并案例往往会使用更多的 CPU 时间,因为它还会查找全树范围的重命名操作。)
因此,如果您的总提交数为 C,则 git rebase -i
的最坏情况大致为 O(Cnd)。2 Git 不会发生尝试任何其他的提交顺序:由你来做任何重新排序。如果你的变基失败,你可以尝试所有可能的重新排序,这将是提交次数的阶乘函数,但 Git 不会为你这样做。
1如果您对一组内部有一个或多个合并的提交执行 git rebase
,Git 会 "flatten"它们并消除合并——但它不会尝试很多命令,它只是对整个事物进行一次拓扑遍历。没有试图对此变得聪明,而且通常这会导致可怕的合并冲突,即,这通常是一个坏主意。如果您使用新的 --rebase-merges
标志,Git 将尝试保留合并,但 re-performing 它们会这样做。它只是构建一个相同的拓扑结构,使用迷你脚本语言,然后让您根据需要手动编辑它。
2如果涉及到rename-detection,即O(n2)个 文件 可能是 rename-detected。 Git 试图通过多种方式限制这一点,包括重命名队列的最大长度,当前默认为 4000 个文件。
你可以在我记得的某个例子中看到发生了什么:从六行 A B C D E F 开始,在一个分支上在前面插入三行 G G G,然后在前面再插入六行 A B C D E F;在另一个分支上(从第一个 patch/commit)将 C 更改为 C4。现在合并这两个分支。
Git 会产生 A B C4 D E F G G G A B C D E F; darcs 会改变第二个 C,前提是它的身份跟踪比 Git 的 context-and-location 跟踪产生更好的结果。如果“4”是块的初始化代码,Git的结果是错误的;如果它是函数或文件的初始化代码,darcs 是错误的。
正是身份跟踪占用了时间。
因此根据 this 维基百科关于版本控制合并的页面,Darcs 使用补丁交换,Git 在变基时也是如此。
我很想知道为什么 Git rebase 在某些情况下不像 Darcs 那样花费指数时间?
This 页面列出了 Darcs 何时可能发生的一系列案例以及如何尝试解决这些问题。
我没有使用过 darcs 并且可能在这里偏离了基础,但是通过浏览维基百科文章,我发现它在这里的说法具有误导性:
Patch commutation is used in Darcs to merge changes, and is also implemented in git (but called "rebasing"). Patch commutation merge means changing the order of patches (i.e. descriptions of changes) so that they form a linear history. In effect, when two patches are made in the context of a common situation, upon merging, one of them is rewritten so that it appears to be done in the context of the other.
Git既不存储补丁,也不对其重新排序。1您可以根据需要手动重新排序补丁。当您使用 git rebase
将提交(即快照)转换为变更集时,转换本身以一种简单的方式完成,即
因此,如果您的总提交数为 C,则 git rebase -i
的最坏情况大致为 O(Cnd)。2 Git 不会发生尝试任何其他的提交顺序:由你来做任何重新排序。如果你的变基失败,你可以尝试所有可能的重新排序,这将是提交次数的阶乘函数,但 Git 不会为你这样做。
1如果您对一组内部有一个或多个合并的提交执行 git rebase
,Git 会 "flatten"它们并消除合并——但它不会尝试很多命令,它只是对整个事物进行一次拓扑遍历。没有试图对此变得聪明,而且通常这会导致可怕的合并冲突,即,这通常是一个坏主意。如果您使用新的 --rebase-merges
标志,Git 将尝试保留合并,但 re-performing 它们会这样做。它只是构建一个相同的拓扑结构,使用迷你脚本语言,然后让您根据需要手动编辑它。
2如果涉及到rename-detection,即O(n2)个 文件 可能是 rename-detected。 Git 试图通过多种方式限制这一点,包括重命名队列的最大长度,当前默认为 4000 个文件。
你可以在我记得的某个例子中看到发生了什么:从六行 A B C D E F 开始,在一个分支上在前面插入三行 G G G,然后在前面再插入六行 A B C D E F;在另一个分支上(从第一个 patch/commit)将 C 更改为 C4。现在合并这两个分支。
Git 会产生 A B C4 D E F G G G A B C D E F; darcs 会改变第二个 C,前提是它的身份跟踪比 Git 的 context-and-location 跟踪产生更好的结果。如果“4”是块的初始化代码,Git的结果是错误的;如果它是函数或文件的初始化代码,darcs 是错误的。
正是身份跟踪占用了时间。