缐上手册git-rebase(1)指出:
- 米
--合并
使用合并策略来重新建立基础。[...]
当然,在不使用--merge
选项的情况下,也可能会遇到“合并冲突”,所以在这种情况下,也必须有“合并策略”来处理这些冲突。
--merge
选项与重定基有何不同。
这似乎是一件相当基本的事情:对于rebase --merge
,Git将其工作文件存储在一个名为$GIT_DIR/rebase-merge
的文件夹中(与交互式rebase一样)。如果没有使用--merge
选项(并且rebase是非交互式的),则该文件夹名为$GIT_DIR/rebase-apply
。
2条答案
按热度按时间yftpprvb1#
简言之,
-m
或--merge
对git rebase
的作用是确保rebase在内部使用git cherry-pick
。强制使用
-m
标志进行选择通常是多余的,但并不总是如此。特别是,任何 interactive rebase总是使用选择。正如joanis在注解中指出的,指定任何-s
或-X
选项也会强制使用选择。-k
也是如此,如下所述。长(或至少更长)
Rebase在Git中有着悠久的历史:第一次重定基操作是通过将每个要重定基的提交格式化为补丁,然后将补丁应用于其他提交来完成的。
(除了参数处理、所有的错误检查,以及
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
标志就非常重要了。举一个具体的例子,考虑下面这一系列提交:假设从
A
到B
、从B
到C
以及从C
到D
的差异都在一个名为lib-foo.ext
的文件中处理,但是在提交F
时,这个文件被 * 重命名 * 为lib/foo.ext
。A..D
的git format-patch
将显示对文件lib-foo.ext
所做的更改,因为没有lib-foo.ext
文件,所以这些都不能正确应用于提交G
。整个重定基操作将失败。然而,当
HEAD
识别提交G
时,提交B
的git cherry-pick
将找到重命名,并将A
-vs-B
更改应用于提交G
中的lib/foo.ext
版本:当
HEAD
标识B'
时,C
的下一个挑选将发现B
到C
到libfoo.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?,正如于尔根所指出的。)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 advantage和room 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中合并)签署人:菲利普伍德
当开始或完成一个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)和2ac0d62(rebase
:将默认后端从,2020年2月15日,Git v2.26.0-rc 0--batch #8中列出的merge更改为(重定基:将默认后端从“am”更改为“merge”,2020-02-15)。此提交对“
git rebase --apply
”(man)进行的更改与2ac0d62对git rebase
(man)进行的更改相同,但没有任何后端特定选项。当消息被更改为使用现有格式时,任何可以解析默认rebase后端的reflog消息的脚本都不会受到此更改的影响。
对来自两个后端的消息进行了现有的测试,这些测试经过调整,以确保它们在将来不会失去同步。