Git rebase的--merge选项有什么作用?

t8e9dugd  于 2022-11-20  发布在  Git
关注(0)|答案(2)|浏览(151)

缐上手册git-rebase(1)指出:


  • --合并
    使用合并策略来重新建立基础。[...]
    当然,在不使用--merge选项的情况下,也可能会遇到“合并冲突”,所以在这种情况下,也必须有“合并策略”来处理这些冲突。

--merge选项与重定基有何不同。

这似乎是一件相当基本的事情:对于rebase --merge,Git将其工作文件存储在一个名为$GIT_DIR/rebase-merge的文件夹中(与交互式rebase一样)。如果没有使用--merge选项(并且rebase是非交互式的),则该文件夹名为$GIT_DIR/rebase-apply

yftpprvb

yftpprvb1#

简言之,-m--mergegit rebase的作用是确保rebase在内部使用git cherry-pick
强制使用-m标志进行选择通常是多余的,但并不总是如此。特别是,任何 interactive rebase总是使用选择。正如joanis在注解中指出的,指定任何-s-X选项也会强制使用选择。-k也是如此,如下所述。

长(或至少更长)

Rebase在Git中有着悠久的历史:第一次重定基操作是通过将每个要重定基的提交格式化为补丁,然后将补丁应用于其他提交来完成的。

branch=$(git symbolic-ref --short HEAD)
target=$(git rev-parse ${onto:-$upstream})
git format-patch $upstream..HEAD > $temp_file
git checkout $target
git am -3 $temp_file
git checkout -B $branch HEAD

(除了参数处理、所有的错误检查,以及git am可能因错误而停止的事实,需要手动修复和git rebase --continue;另外,上面的脚本是我简化的可读性版本,可能与原始脚本不太相似)。
这种rebase处理大多数情况都很好。最常见的情况是它 * 不能 * 很好地处理一些文件重命名的rebase。它也不能复制一个“空”的commit-一个补丁是空的,也就是说-因为git format-patch不允许省略补丁部分。
这些空提交通常被git rebase忽略,即使在使用-m时也是如此;您必须添加-k来保留它们。要保留它们,git rebase必须切换到cherry-pick变体(如果它尚未这样做)。
要传递-s-X参数,rebase必须调用git cherry-pick而不是git am,因此这些标志中的任何一个都需要cherry-pick变量。
使用git format-patch不会进行任何重命名检测。因此,如果你正在复制的提交流都应用了与HEAD相关的重命名检测,那么-m标志就非常重要了。举一个具体的例子,考虑下面这一系列提交:

B--C--D   <-- topic
         /
...--o--A--E--F--G   <-- mainline

假设从AB、从BC以及从CD的差异都在一个名为lib-foo.ext的文件中处理,但是在提交F时,这个文件被 * 重命名 * 为lib/foo.extA..Dgit format-patch将显示对文件lib-foo.ext所做的更改,因为没有lib-foo.ext文件,所以这些都不能正确应用于提交G。整个重定基操作将失败。
然而,当HEAD识别提交G时,提交Bgit cherry-pick将找到重命名,并将A-vs-B更改应用于提交G中的lib/foo.ext版本:

B--C--D   <-- topic
         /
...--o--A--E--F--G   <-- mainline
                  \
                   B'   <-- HEAD [detached]

HEAD标识B'时,C的下一个挑选将发现BClibfoo.ext的更改应应用于重命名的lib/foo.ext,并且D的最后一个挑选将执行相同的操作,以便重定基将成功。
重命名检测代码很慢,所以一个不需要重命名,也不需要保留“空”提交的rebase在git format-patch | git am系统上运行起来要快得多。这大概是原始方法优于cherry-pick变体的唯一原因:在有约束的情况下速度会更快。(然而,只有当有很多重命名 * 候选者 *,但其中没有一个是实际的 * 重命名 *,或者它们都不重要时,速度才会提高。)
(Side注:-3参数或--3way(使用较长的拼写)告诉git am将该标志传递给每个git apply,如果需要,apply将尝试使用diff中index行中的blob散列执行三路合并。在某些情况下,这似乎 * 可能 * 足以处理重命名的文件-特别是当blob哈希完全匹配时。cherry-pick方法执行完全重命名检测,它处理不完全匹配; -3无法做到这一点。另请参见What is the difference between git cherry-pick and git format-patch | git am?,正如于尔根所指出的。)

bzzcjhmw

bzzcjhmw2#

从Git 2.26(Q1 2020)开始,“git rebase“(man)已经学会了默认使用合并后端(即驱动“rebase -i“的机器),同时允许“--apply“选项使用“apply“后端(即“format-patch piped to am“的道德等价物)。
可将rebase.backend组态变数设定为自订。
这有助于说明--merge(现在是默认值)和旧的--apply之间的区别。
请参见:2020年2月15日)和2020年1月16日(2020年1月16日)。
(由Junio C Hamano -- gitster --合并至commit 8c22bd9,2020年3月2日)
第1001章:将默认后端从“am”更改为“merge”
签署人:伊莱贾·纽伦
am后端会丢弃信息,因此限制了我们的功能:

此外,合并/交互后端有更多的功能,目前似乎有一个slight performance advantageroom for more optimizations than the am backend(正在进行的工作,以利用其中的一些可能性)。
git rebase现在在其手册页中包括:

可中断性

am后端有一个不合时宜的中断的安全问题;如果用户在错误的时间按下Ctrl-C以尝试中止变基,则变基可能会进入一种状态,在该状态下,它不能被后续的git rebase --abort中止。
交互式后端似乎没有遭受同样的缺点。(有关详细信息,请参阅this thread。)
从那时起,Git 2.39(2022年第4季度)修复了reflog消息中的一些错误,并修改了reflog消息“rebase --apply“以匹配“rebase --merge“,目的是使reflog更容易解析。
它再次说明了两个选项之间的另一个差异,现在已解决。
请参阅第一版第31页、第一版第32页、第一版第33页、第一版第34页、第一版第35页、第一版第36页、第一版第37页、第一版第38页(2022年10月12日),作者为第一版第39页。
2022年10月17日,Junio C Hamano ( gitster )发布。
(2022年10月30日,由Taylor Blau -- ttaylorr --commit 8851c4b中合并)

  • ----使reflog消息匹配rebase --merge
    签署人:菲利普伍德
    当开始或完成一个rebase和挑选提交时,apply后端创建的reflog消息与merge后端略有不同。
    这些差异使得解析reflog变得比实际需要的更困难(我有一个脚本,它从rebase中读取完成消息,必须适应两种不同的消息格式是一件痛苦的事情)。
    虽然可以从reflog消息中确定用于重定基的后端,但差异不是为该目的而设计的。
    (“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”“”drop '-i' from the reflog for interactive-based rebase”,2020-02-15,Git v2.26.0-rc 0--merge listed in batch #8)删除了两个后端的reflog消息之间的明显区别,没有任何抱怨。
    由于合并后端是默认的,它可能是现有reflog中最常见的格式。
    因此,更改应用后端以格式化其reflog消息,使其尽可能与合并后端匹配。
    请注意,在提交冲突解决方案时仍然存在差异,应用后端将使用“(pick)”而不是“(continue)”,因为当前无法更改单个提交的消息。
    除了c2417d3之外,我们还更改了68aa495中的reflog消息(“rebase:通过交互机制实现--merge”,2018-12-11,Git v2.21.0-rc 0--merge)和2ac0d62rebase:将默认后端从,2020年2月15日,Git v2.26.0-rc 0--batch #8中列出的merge更改为(重定基:将默认后端从“am”更改为“merge”,2020-02-15)。
    此提交对“git rebase --apply”(man)进行的更改与2ac0d62git rebaseman)进行的更改相同,但没有任何后端特定选项。
    当消息被更改为使用现有格式时,任何可以解析默认rebase后端的reflog消息的脚本都不会受到此更改的影响。
    对来自两个后端的消息进行了现有的测试,这些测试经过调整,以确保它们在将来不会失去同步。

相关问题