Help us learn about your current experience with the documentation. Take the survey.

变基(Rebase)与解决合并冲突

Git 变基(rebase)通过将你的提交移动到目标分支的顶端,将一个分支的变更合并到另一个分支。这个操作:

  • 用目标分支的最新代码更新分支。
  • 保持干净、线性的提交历史,便于调试和代码审查。
  • 在提交级别解决 合并冲突,用于冲突解决。
  • 保持代码变更的时间顺序。

当你进行变基时:

  1. Git 导入在你最初从目标分支创建分支后,提交到目标分支的所有提交。

  2. Git 将你分支的提交应用到导入的提交之上。在此示例中,在创建了一个名为 feature 的分支(橙色)后,来自 main 的四个提交(紫色)被导入到 feature 分支:

    Git rebase illustration

虽然大多数变基都是针对 main 进行的,但你也可以针对任何其他分支进行变基。你还可以指定不同的远程仓库。 例如,使用 upstream 而不是 origin

git rebase 会重写提交历史。它可能导致共享分支中的冲突和复杂的合并冲突。 与其将你的分支变基到默认分支,不如考虑使用 git pull origin master。拉取操作有类似的效果,但风险较小,不会影响他人的工作。

变基(Rebase)

当你使用 Git 进行变基时,每个提交都会应用到你的分支上。 当出现合并冲突时,系统会提示你解决它们。

要提交更高级的选项,请使用 交互式变基

先决条件:

  • 你必须拥有 权限 才能强制推送到分支。

要使用 Git 将你的分支变基到目标分支:

  1. 打开终端并切换到你的项目目录。

  2. 确保你拥有目标分支的最新内容。 在此示例中,目标分支是 main

    git fetch origin main
  3. 切换到你的分支:

    git checkout my-branch
  4. 可选。创建你的分支备份:

    git branch my-branch-backup

    如果从备份分支恢复,此之后添加到 my-branch 的变更将会丢失。

  5. 针对 main 分支进行变基:

    git rebase origin/main
  6. 如果存在合并冲突:

    1. 在你的编辑器中解决冲突。

    2. 暂存变更:

      git add .
    3. 继续变基:

      git rebase --continue
  7. 强制推送你的变更到目标分支,同时保护他人的提交:

    git push origin my-branch --force-with-lease

交互式变基(Interactive rebase)

使用交互式变基来指定如何处理每个提交。 以下说明使用 Vim 文本编辑器来编辑提交。

要进行交互式变基:

  1. 打开终端并切换到你的项目目录。

  2. 确保你拥有目标分支的最新内容。在此示例中,目标分支是 main

    git fetch origin main
  3. 切换到你的分支:

    git checkout my-branch
  4. 可选。创建你的分支备份:

    git branch my-branch-backup

    如果从备份分支恢复,此之后添加到 my-branch 的变更将会丢失。

  5. 在 GitLab UI 中,在你的合并请求中,确认要在 Commits 选项卡中变基的提交数量。

  6. 打开这些提交。例如,要编辑最后五个提交:

    git rebase -i HEAD~5

    Git 在你的终端文本编辑器中打开提交,按时间顺序从旧到新。 每个提交显示要执行的操作、SHA 和提交标题。例如:

    pick 111111111111 第二轮结构修订
    pick 222222222222 更新到此更改页面的入站链接
    pick 333333333333 从 H4 转换为 H3
    pick 444444444444 添加编辑修订
    pick 555555555555 修订继续构建概念部分
    
    # Rebase 111111111111..222222222222 onto zzzzzzzzzzzz (5 commands)
    #
    # Commands:
    # p, pick <commit> = use commit
    # r, reword <commit> = use commit, but edit the commit message
    # e, edit <commit> = use commit, but stop for amending
    # s, squash <commit> = use commit, but meld into previous commit
    # f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
  7. i 切换到 Vim 的编辑模式。

  8. 使用方向键将光标移动到你要编辑的提交。

  9. 对于除第一个提交外的每个提交,将 pick 更改为 squashfixup(或 sf)。

  10. 对剩余的重复此操作。

  11. 结束编辑模式,保存并退出:

    • ESC
    • 输入 :wq
  12. 当压缩提交时,Git 会提示你编辑提交消息:

    • # 开头的行将被忽略,不包含在提交消息中。
    • 要保留当前消息,请输入 :wq
    • 要编辑提交消息,切换到编辑模式,进行更改,然后保存。
  13. 将你的变更推送到目标分支。

    • 如果在变基前没有将提交推送到目标分支:

      git push origin my-branch
    • 如果已经推送了提交:

      git push origin my-branch --force-with-lease

      某些操作需要强制推送才能对分支进行更改。有关更多信息,请参阅 强制推送到远程分支

从命令行解决冲突

为了让你对每个变更有最大的控制权,你应该在本地通过命令行解决复杂的冲突,而不是在 GitLab 中。

先决条件:

  • 你必须拥有 权限 才能强制推送到分支。
  1. 打开终端并切换到你的功能分支:

    git switch my-feature-branch
  2. 将你的分支变基到目标分支。在此示例中,目标分支是 main

    git fetch
    git rebase origin/main
  3. 在你首选的代码编辑器中打开冲突文件。

  4. 定位并解决冲突块:

    1. 选择你要保留的版本(======= 之前或之后)。
    2. 删除你不保留的版本。
    3. 删除冲突标记。
  5. 保存文件。

  6. 对每个有冲突的文件重复此过程。

  7. 暂存你的变更:

    git add .
  8. 提交你的变更:

    git commit -m "Resolve merge conflicts"

    你可以运行 git rebase --abort 在此点之前停止进程。 Git 会中止变基并将分支回滚到运行 git rebase 之前的状态。运行 git rebase --continue 后,你无法中止变基。

  9. 继续变基:

    git rebase --continue
  10. 强制推送变更到你的远程分支:

     git push origin my-feature-branch --force-with-lease

强制推送到远程分支

复杂的 Git 操作,如压缩提交、重置分支或变基,都会重写分支历史。 Git 需要强制更新这些变更。

不建议在共享分支上强制推送,因为你可能会破坏他人的变更。

如果分支是 受保护的, 除非你:

  • 取消保护。
  • 允许强制推送。

否则你无法强制推送。

有关更多信息,请参阅 允许在受保护分支上强制推送

恢复你的备份分支

如果变基或强制推送失败,从备份恢复你的分支:

  1. 确保你在正确的分支上:

    git checkout my-branch
  2. 将你的分支重置为备份:

    git reset --hard my-branch-backup

变基后的审批

如果你变基了一个分支,你就添加了提交。如果你的项目配置为 防止添加提交的用户进行审批,你无法审批你变基过的合并请求。

相关主题

故障排除

有关 CI/CD 管道故障排除的信息,请参阅 调试 CI/CD 管道

/rebase 快速操作后的 Unmergeable state 状态

/rebase 命令安排了一个后台任务。该任务尝试将源分支的变更变基到目标分支的最新提交上。 如果在使用 /rebase 快速操作 后, 看到此错误,则无法安排变基:

This merge request is currently in an unmergeable state, and cannot be rebased.

如果以下任何条件为真,则会发生此错误:

  • 源分支和目标分支之间存在冲突。
  • 源分支不包含任何提交。
  • 源分支或目标分支不存在。
  • 发生错误,导致未生成差异。

要解决 unmergeable state 错误:

  1. 解决任何合并冲突。
  2. 确认源分支存在且有提交。
  3. 确认目标分支存在。
  4. 确认已生成差异。

/rebase 后忽略 /merge 快速操作

如果使用了 /rebase,则忽略 /merge,以避免竞态条件,即源分支在变基之前被合并或删除。