更快捷的方式`git rebase --preserve-merges`

时间:2017-10-01 22:09:25

标签: git merge rebase

我通过创建一系列功能分支来使用git,并在使用git merge --no-ff完成后将它们合并到主控。这将创建空的合并提交,用于标识先前功能分支的起点和终点。

为了处理多个并发分支,甚至是嵌套分支,我使用rebase。我从不合并,我总是在最新提交时修改我的分支,测试并在完成所有操作后最终与--no-ff合并。使用嵌套分支,我也这样做:多个分支按顺序合并到主分支上,主分支本身最终合并为主分支。

为了保留有关嵌套分支的合并信息,我经常使用git rebase --preserve-merges。这完全符合我的要求,我的工作流程也没有问题。

我对git的主要问题是git rebase --preserve-merges非常慢(每次提交有时需要大约2秒)。在阅读What exactly does git's "rebase --preserve-merges" do (and why?)后,我意识到git必须执行大量工作来保留合并,因为git必须处理任意图形。

我想知道的是:由于我的工作流程几乎导致图形等效于线性历史记录,有没有办法以更快的方式执行git rebase --preserve-merge等价物,因为我保证&#34 ;线性"只有空合并提交的历史记录?我不介意使用脚本或奇怪的命令,只要最终结果是正确的。

     A-B-C
    /     \   
(1)--------D-- master
    \
     \---F-----I-- feature
      \ / \   /
       E   G-H

     A-B-C   E   G-H
    /     \ / \ /   \
(2)--------D---F-----I-feature
         master

TL;博士:如何将(1)转换为(2)知道基础历史是线性的,因此git rebase --preserve-merges不需要做多少工作并且快速完成?

2 个答案:

答案 0 :(得分:1)

可能能够通过将其从bash脚本重写为更聪明的东西来加快速度(例如,在Python中运行git rev-list --parents并收集所有在开始复制操作之前的父信息),但从根本上说它很难。正如其他链接注释中的答案一样,git rebase -p也不会完全保留合并,而不是重新创建它们。在完全一般的情况下 - 我知道你忽略了更有限的特殊情况;我只提到这一点是为了完整性 - git rebase -p完全失败了已经应用了特殊选项或处理的合并(--no-commit与手动修改合并以产生“邪恶合并”,或者合并与{{1}合并或者-X rename-threshold或类似的),因为特殊情况信息实际上只存储在结果树中。 rebase代码甚至没有查找它(这将花费更长的时间:它必须首先重现原始合并,以查看无选项合并是否会重新创建原始结果。)

除此之外,这些选项的速度(或速度不足)取决于存储库及其文件的大小,以及是使用Windows(非常慢)还是使用Unixish系统(更快)。我没有理由知道Windows运行脚本的速度应该非常慢,但显然是这样,因为Git人员不断重写C中的内容,使其在Windows上表现可接受,因为脚本速度太慢。

因此,如果你在Windows上这样做,加速它的一种方法是停止使用Windows。 :-)(您可以在rebase本身的持续时间内执行此操作,使用-X oursgit push来协调Windows和Linux或其他任何内容。)

答案 1 :(得分:1)

  

我对git的主要问题是git rebase --preserve-merges非常慢

考虑到它包括用C语言重写“ rebase”机制,在Git 2.20+(2018年第四季度)中可能不会那么慢。
没有更多的shell脚本。 (请清楚:从Git 2.22开始,2019年第二季度,old rebase script is no more

请参见commit ac7f467commit c7b64aacommit 55071eaPratik Karki (prertik)(2018年8月6日)。
(由Junio C Hamano -- gitster --commit 5ae5084中合并,2018年11月2日)

  

变基:开始将其实现为内置

     

此提交模仿了用于将difftool转换为内置变量的策略。
  我们首先将Shell脚本git-rebase.sh重命名为git-legacy-rebase.sh,然后介绍一个builtin/rebase.c,它简单地执行Shell脚本版本,   除非配置设置rebase.useBuiltin设置为true

     

其背后的动机是重写   上述rebase.c中的shell脚本版本,一一并   通过配置可以方便地测试新功能   rebase.useBuiltin

     

在原始的difftool转换中,如果sane_execvp()试图   运行以非负状态返回的旧脚本版本,   命令悄无声息地退出,没有做任何成功,但是   sane_execvp()的第一个不应返回非负状态   位置,因此我们使用die()来注意到这种异常情况。

     

我们有意避免直接阅读配置以避免   当我们需要回退到GIT_*环境变量时   exec()编写Shell脚本。


请参见commit 62c2393commit d8d0a54Ævar Arnfjörð Bjarmason (avar)(2018年11月14日)。
(由Junio C Hamano -- gitster --commit 4520c23中合并,2018年11月18日)

The documentation现在指出:

rebase.useBuiltin:
     

如果false,请设置为git rebase以使用旧版shellscript实现。
  默认为true,这意味着使用C中的内置重写。

     

C重写最初包含在Git 2.20版本中
  此选项提供了逃生功能,可以在任何情况下重新启用旧版本   在重写中发现错误。
  在将来的某些发行版中,将删除此选项和shellscript版本git-rebase

     

如果您发现除一次性测试之外将此选项设置为false的其他原因,则应将行为差异报告为git中的错误。


在Git 2.21(2019年2月)中,通过重新使用用于“ git rebase --merge”的内部机制,重新实现了“ git rebase -i”。

请参见commit 68aa495commit c91c944commit 7b76ac6commit 899b49ccommit 45339f7commit 5400677commit 72ee673,{{3} }(2018年12月11日),由commit c913c59
(由Elijah Newren (newren)Junio C Hamano -- gitster --中合并,2019年2月7日)

  

rebase:通过互动机制实施--merge

     

作为使基础具有更统一行为的不断努力的一部分,通过在后端之上重新实现,将合并后端修改为类似于交互式后端。

     

交互式rebase是根据Cherry-pick而非内置的递归合并实现的,但是Cherry-pick默认情况下也调用递归合并机制,并且可以接受特殊的合并策略和/或特殊的策略选项。 >   因此,实际上并不需要同时使用git-rebase--merge和   git-rebase--interactive了。
  删除git-rebase--merge.sh,而在builtin/rebase.c中实施。

     

rebase:定义线性化顺序并强制执行

有关效果,请参见commit 8fe9c3f

此外,仍然是Git 2.21(2019年2月):“ git rebase --merge”已通过重新使用用于“ git rebase -i”的内部机制而重新实现。

请参见commit c91c944commit 29d03f8(2019年2月14日)。
(由Elijah Newren (newren)Junio C Hamano -- gitster --中合并,2019年2月14日)

  

rebase:通过交互式机器实现--merge

     

作为使基础具有更统一行为的不断努力的一部分,通过在后端之上重新实现,将合并后端修改为类似于交互式后端。

     

交互式重载是根据Cherry-pick而非内置递归合并实现的,但是Cherry-pick也调用了   递归合并机制默认情况下,可以接受特殊的合并策略和/或特殊的策略选项。
  因此,实际上并不需要同时使用git-rebase--merge和   git-rebase--interactive了。
  删除git-rebase--merge.sh,而在builtin/rebase.c中实施。

     

这会导致一些故意但很小的用户可见更改:

     
      
  • 修改进度输出(例如,请参阅t3406和t3420)
  •   
  • 现在解决了一些已知的测试失败(请参见t3421)
  •   重新设置基元时-重新合并时的
  • bash提示现在为REBASE-i,而不是REBASE-m。   原因:提示反映了正在使用的后端;这使用户可以使用适当的后端信息向git邮件列表报告问题,并允许高级用户执行以下操作:   知道在哪里搜索相关的控制文件。 (请参阅t9903)
  •   

由于通过重新使用用于“ git rebase --preserve-merge”的内部机制而重新实现了“ git rebase -i”,因此此Git 2.22(2019年第二季度)补丁很受关注:

请参见commit 6f07c7bcommit 460bc3ccommit 297b1e1commit 0ea0847commit 73fdc53commit 3389853commit 7d3488e,{{3} },commit c44c246commit 0609b74commit 6023c92(2019年4月17日)和commit 28dc09d(2019年3月19日)之前为commit 146839c
(由commit fc4a673Phillip Wood (phillipwood)中合并,2019年5月13日)

  

rebase -i:运行时无需分叉rebase --interactive

     

当内置rebase启动交互式rebase时,它将解析选项,然后将其重新打包并分叉rebase--interactive
  将cmd_rebase__interactive()中的选项解析与业务逻辑分开,以允许在不通过直接调用rebase__interactive来分叉run_rebase_interactive()的情况下运行交互式基础。

     

在不进行分叉的情况下启动交互式rebase使其易于调试   音序器,无需担心会附着在孩子身上   流程。
  Ævar还报告了一些Junio C Hamano -- gitster --

     

此补丁程序还可以轻松删除以下位置的cmd_rebase__interactive()   git-legacy-rebase.shgit-rebase--preserve-merges.sh退休的未来。