Skip to content

git-rebase

在另一个基础提交之上重新应用提交。

概要

bash
'git rebase' [-i | --interactive] [<options>] [--exec <cmd>]
	[--onto <newbase> | --keep-base] [<upstream> [<branch>]]
'git rebase' [-i | --interactive] [<options>] [--exec <cmd>] [--onto <newbase>]
	--root [<branch>]
'git rebase' (--continue|--skip|--abort|--quit|--edit-todo|--show-current-patch)

描述

将一系列提交移植到不同的起点。您也可以使用 git rebase 来重新排序或合并提交:有关如何执行此操作,请参阅下面的交互模式。

例如,假设您一直在处理 topic 分支,并且想要"追赶"到 master 分支上已完成的工作:

          A---B---C topic
         /
    D---E---F---G master

您想要将在 topic 上自与 master 分叉以来所做的提交(即 A、B 和 C)移植到当前 master 的顶部。您可以在检出 topic 分支时运行 git rebase master 来执行此操作。如果您想在另一个分支上变基 topicgit rebase master topicgit checkout topic && git rebase master 的快捷方式。

              A'--B'--C' topic
             /
    D---E---F---G master

如果在此过程中发生合并冲突,git rebase 将在第一个有问题的提交处停止并留下冲突标记。如果发生这种情况,您可以执行以下操作之一:

  1. 解决冲突。您可以使用 git diff 查找标记(<<<<<<)并进行编辑以解决冲突。对于您编辑的每个文件,您需要告诉 Git 冲突已解决。您可以使用 git add <filename> 将冲突标记为已解决。解决所有冲突后,您可以使用 git rebase --continue 继续变基过程。

  2. 使用 git rebase --abort 停止 git rebase 并将分支返回到其原始状态。

  3. 使用 git rebase --skip 跳过导致合并冲突的提交。

如果您未指定要变基到的 <upstream>,将使用 branch.<name>.remotebranch.<name>.merge 选项中配置的上游,并假定 --fork-point 选项。如果您当前不在任何分支上,或者当前分支没有配置的上游,变基将中止。

以下是 git rebase <upstream> 执行操作的简化描述:

  1. 制作当前分支上自 <upstream> 分叉以来的所有提交列表,这些提交在 <upstream> 中没有等效提交。
  2. 使用等同于 git checkout --detach <upstream> 的方式检出 <upstream>
  3. 按顺序逐个重放提交。这类似于对每个提交运行 git cherry-pick <commit>
  4. 使用等同于 git checkout -B <branch> 的方式更新分支以指向最终提交。

使用 --ONTO 移植主题分支

以下是使用 rebase --onto 将基于一个分支的主题分支移植到另一个分支的方法,假装您从后一个分支分叉了主题分支。

首先让我们假设您的 topic 分支基于 next 分支。例如,在 topic 中开发的功能依赖于 next 中的某些功能。

    o---o---o---o---o  master
         \
          o---o---o---o---o  next
                           \
                            o---o---o  topic

我们希望使 topicmaster 分支分叉;例如,因为 topic 所依赖的功能已合并到更稳定的 master 分支中。

我们可以通过以下命令获得此结果:

bash
git rebase --onto master next topic

模式选项

本节中的选项不能与任何其他选项一起使用,包括彼此之间:

  • --continue:在解决合并冲突后重新启动变基过程。
  • --skip:通过跳过当前补丁重新启动变基过程。
  • --abort:中止变基操作并将 HEAD 重置为原始分支。
  • --quit:中止变基操作,但 HEAD 不会重置回原始分支。
  • --edit-todo:在交互式变基期间编辑待办事项列表。
  • --show-current-patch:在交互式变基中或当变基因冲突而停止时显示当前补丁。

选项

  • --onto <newbase>:创建新提交的起点。如果未指定 --onto 选项,则起点为 <upstream>
  • --keep-base:将创建新提交的起点设置为 <upstream><branch> 的合并基础。
  • <upstream>:要比较的上游分支。可以是任何有效的提交,而不仅仅是现有的分支名称。
  • <branch>:工作分支;默认为 HEAD
  • --apply:使用应用策略进行变基(内部调用 git-am)。
  • --empty=(drop|keep|stop):如何处理在变基后变为空的提交。
  • --no-keep-empty:不在结果中保留开始时为空的提交。
  • --keep-empty:保留开始时为空的提交(默认)。
  • --reapply-cherry-picks:重新应用所有上游提交的干净 cherry-pick。
  • --no-reapply-cherry-picks:预先删除干净的 cherry-pick。
  • --allow-empty-message:允许变基带有空消息的提交。
  • -m, --merge:使用合并策略进行变基(默认)。
  • -s <strategy>, --strategy=<strategy>:使用给定的合并策略,而不是默认的 ort
  • -X <strategy-option>, --strategy-option=<strategy-option>:将策略选项传递给合并策略。
  • --rerere-autoupdate:允许 rerere 机制使用记录的解决方案自动更新文件。
  • --no-rerere-autoupdate:不自动更新。
  • -S[<keyid>], --gpg-sign[=<keyid>]:GPG 签名提交。
  • --no-gpg-sign:不 GPG 签名。
  • -q, --quiet:安静。隐含 --no-stat
  • -v, --verbose:详细。隐含 --stat
  • --stat:显示自上次变基以来上游更改的 diffstat。
  • -n, --no-stat:不显示 diffstat。
  • --no-verify:绕过 pre-rebase 钩子。
  • --verify:允许运行 pre-rebase 钩子(默认)。
  • -C<n>:确保每个更改前后至少有 <n> 行周围的上下文匹配。
  • --no-ff, --force-rebase, -f:单独重放所有变基的提交,而不是快进未更改的提交。
  • --fork-point:使用 reflog 在计算哪些提交已由 <branch> 引入时,在 <upstream><branch> 之间找到更好的公共祖先。
  • --no-fork-point:不使用 fork-point 逻辑。
  • --ignore-whitespace:在尝试调和差异时忽略空白差异。
  • --whitespace=<option>:此标志传递给应用补丁的 git apply 程序。
  • --committer-date-is-author-date:使用被变基提交的作者日期作为提交者日期。
  • --ignore-date:使用当前时间作为变基提交的作者日期。
  • --reset-author-date:同 --ignore-date
  • --signoff:向所有变基的提交添加 Signed-off-by 尾部。
  • --trailer=<trailer>:向每个变基的提交消息追加给定的尾部。
  • -i, --interactive:制作即将变基的提交列表。让用户在变基之前编辑该列表。
  • -r, --rebase-merges[=(rebase-cousins|no-rebase-cousins)]:尝试保留要变基的提交中的分支结构。
  • --no-rebase-merges:不保留分支结构。
  • -x <cmd>, --exec <cmd>:在最终历史中创建提交的每行之后追加 "exec <cmd>"。
  • --root:变基从 <branch> 可达的所有提交。
  • --autosquash:自动将具有特殊格式消息的提交压缩到正在变基的先前提交中。
  • --no-autosquash:不自动压缩。
  • --autostash:在操作开始前自动创建临时 stash 条目,并在操作结束后应用它。
  • --no-autostash:不自动 stash。
  • --reschedule-failed-exec:自动重新安排失败的 exec 命令。
  • --no-reschedule-failed-exec:不自动重新安排。
  • --update-refs:自动强制更新指向正在变基的提交的任何分支。
  • --no-update-refs:不自动更新引用。

不兼容的选项

以下选项彼此不兼容:--apply--whitespace-C--merge--strategy--strategy-option--autosquash--rebase-merges--interactive--exec--no-keep-empty--empty=--update-refs--root(不与 --onto 一起使用时)、--trailer

此外,以下选项对不兼容:--keep-base--onto--keep-base--root--fork-point--root

行为差异

git rebase 有两个主要后端:applymerge。这两个后端在行为上有一些细微的差异:

空提交

apply 后端会丢弃有意为空的提交。merge 后端默认保留有意为空的提交。

目录重命名检测

由于缺乏准确的树信息,apply 后端中禁用了目录重命名检测。merge 后端中的目录重命名检测可为此类情况提供警告。

上下文

apply 后端通过创建一系列补丁来工作,如果代码的多个区域具有相同的周围上下文行,则可能会选择错误的区域。merge 后端使用每个相关文件的完整副本,使其免受此类问题的影响。

冲突标记的标签

当存在内容冲突时,合并机制会尝试用内容来源的提交注释每一方的冲突标记。apply 后端必须回退到提交摘要。merge 后端使用历史两侧的完整提交,因此没有此类限制。

钩子

两个后端目前对 post-commit 和 post-checkout 钩子的调用行为不同。

可中断性

apply 后端在不适当的中断时存在安全问题。merge 后端似乎没有同样的缺点。

提交消息修改

当变基期间发生冲突时,merge 后端会打开编辑器让用户更新提交消息。apply 后端盲目应用原始提交消息。

合并策略

合并机制(git mergegit pull 命令)允许使用 -s 选项选择后端"合并策略"。一些策略还可以接受自己的选项,可以通过向 git merge 和/或 git pull 给出 -X<option> 参数来传递。

  • ort:这是拉取或合并一个分支时的默认合并策略。此策略只能使用三向合并算法解决两个头。
  • recursive:现在是 ort 的同义词。
  • resolve:只能使用三向合并算法解决两个头。
  • octopus:解决超过两个头的情况,但拒绝执行需要手动解决的复杂合并。
  • ours:解决任意数量的头,但合并的结果树始终是当前分支头的树。
  • subtree:修改后的 ort 策略。

备注

您应该了解在共享仓库上使用 git rebase 的影响。

当运行变基时,如果存在 pre-rebase 钩子,它将首先执行该钩子。

完成后,<branch> 将是当前分支。

交互模式

交互式变基意味着您有机会编辑被变基的提交。您可以重新排序提交,也可以删除它们。

使用您希望保留原样的最后一个提交启动它:

bash
git rebase -i <after-this-commit>

一个编辑器将打开,其中包含当前分支中给定提交之后的所有提交(忽略合并提交)。您可以随意重新排序此列表中的提交,也可以删除它们。

通过将命令 "pick" 替换为命令 "edit",您可以在应用该提交后告诉 git rebase 停止,以便您可以编辑文件和/或提交消息。

要中断变基,请使用 "break" 命令。

要删除提交,请将命令 "pick" 替换为 "drop",或直接删除匹配的行。

要将两个或多个提交合并为一个,请将第二个及后续提交的 "pick" 命令替换为 "squash" 或 "fixup"。

拆分提交

在交互模式下,您可以使用 "edit" 操作标记提交。但是,这并不一定意味着 git rebase 期望此编辑的结果恰好是一个提交。实际上,您可以撤消提交,也可以添加其他提交。这可用于将一个提交拆分为两个。

从上游变基中恢复

对其他人基于其工作的分支进行变基(或任何其他形式的重写)是一个坏主意:其下游的任何人都被迫手动修复其历史。

变基合并

交互式变基命令最初设计用于处理单个补丁系列。--rebase-merges 选项允许在变基时保留合并提交。

配置

  • rebase.backend:用于变基的默认后端。可选 applymerge
  • rebase.stat:是否显示自上次变基以来上游更改的 diffstat。默认为 false。
  • rebase.autoSquash:如果设置为 true,则默认为交互模式启用 --autosquash 选项。
  • rebase.autoStash:设置为 true 时,在操作开始前自动创建临时 stash 条目。
  • rebase.updateRefs:如果设置为 true,则默认启用 --update-refs 选项。
  • rebase.missingCommitsCheck:设置为 "warn" 时打印警告,设置为 "error" 时停止变基。
  • rebase.instructionFormat:用于交互式变基期间待办事项列表的格式字符串。
  • rebase.abbreviateCommands:如果设置为 true,git rebase 将在待办事项列表中使用缩写的命令名称。
  • rebase.rescheduleFailedExec:自动重新安排失败的 exec 命令。
  • rebase.forkPoint:如果设置为 false,则默认设置 --no-fork-point 选项。
  • rebase.rebaseMerges:是否以及如何默认设置 --rebase-merges 选项。
  • rebase.maxLabelLength:从提交主题生成标签名称时,将名称截断为此长度。
  • sequence.editorgit rebase -i 用于编辑变基指令文件的文本编辑器。

Git

git 套件的一部分

基于 CC BY-NC-SA 3.0 许可发布