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

What does the --merge option of Git rebase do?

手册页 git-rebase(1) 说:

-m
--merge
Use merging strategies to rebase. [...]

当然,不使用 --merge 选项也可以 运行 变成 "merge conflicts"。所以在那种情况下也必须有任何 "merge strategy" 来处理这些冲突。

变基的 --merge 选项有何不同。

这似乎是相当基本的东西:对于 rebase --merge,Git 将其工作文件存储在名为 $GIT_DIR/rebase-merge 的文件夹中(就像它对交互式变基所做的那样)。如果未使用 --merge 选项(并且 rebase 是非交互式的),则该文件夹被命名为 $GIT_DIR/rebase-apply.

一句话,-m--mergegit rebase的作用是确保rebase在内部使用git cherry-pick

强制选择的 -m 标志通常是多余的,但并非总是如此。特别是,任何 interactive rebase 总是使用 cherry-pick。作为 ,指定任何 -s-X 选项也会强制使用 cherry-pick。 -k 也是如此,如下所述。

长(或至少更长)

Rebase 在 Git 中有着悠久的历史:第一个 rebase 操作是通过将每个要重新定位的提交格式化为补丁,然后将补丁应用于其他提交来完成的。也就是说,最初 git rebase 主要是:

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 可以很好地处理大多数情况。它 不能 处理的最常见的情况涉及跨一些文件重命名的变基。它也不能复制 "empty" 提交——补丁为空的提交,也就是说——因为 git format-patch 不允许省略补丁部分。

即使使用 -m,这些空提交通常也会被 git rebase 忽略;您必须添加 -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

假设ABBCCD的差异都在内部处理一个名为 lib-foo.ext 的文件。但是在提交 F 中,此文件 重命名 lib/foo.extA..Dgit format-patch 将显示对文件 lib-foo.ext 所做的更改,其中 none 将正确应用于提交 G,因为没有 [=42] =] 文件。整个变基将失败。

提交 Bgit cherry-pickHEAD 标识提交 G 时,将找到重命名并应用 A-vs-B 在提交 G:

中更改 lib/foo.ext 的版本
          B--C--D   <-- topic
         /
...--o--A--E--F--G   <-- mainline
                  \
                   B'   <-- HEAD [detached]

C 的下一个 cherry-pick,而 HEAD 标识 B',将发现 B-to-C 更改为 libfoo.ext 应该应用于重命名的 lib/foo.extD 的最后一个 cherry-pick 也会做同样的事情,这样 rebase 就会成功。

重命名检测代码很慢,因此 没有 重命名的 rebase,没有 "empty" 提交保留,可以 运行 很多通过 git format-patch | git am 系统 运行 时更快。这是原始方法优于 cherry-pick 变体的唯一方式:它在受限情况下更快。 (但是,只有当有很多重命名 候选 ,但其中 none 是实际的 renames 或none 其中很重要。)

(旁注:-3 参数,或 --3way 使用更长的拼写,告诉 git am 将该标志传递给每个 git apply,其中如果需要,apply 将尝试进行三向合并,使用 diff 中 index 行中的 blob 哈希。在某些情况下,这似乎 可能 足以处理重命名的文件——特别是如果 blob 哈希完全匹配。cherry-pick 方法进行完全重命名检测,处理不精确匹配;-3 不能那样做。另见 , as 。)