变基(Rebase)与解决合并冲突
Git 变基(rebase)通过将你的提交移动到目标分支的顶端,将一个分支的变更合并到另一个分支。这个操作:
- 用目标分支的最新代码更新分支。
- 保持干净、线性的提交历史,便于调试和代码审查。
- 在提交级别解决 合并冲突,用于冲突解决。
- 保持代码变更的时间顺序。
当你进行变基时:
-
Git 导入在你最初从目标分支创建分支后,提交到目标分支的所有提交。
-
Git 将你分支的提交应用到导入的提交之上。在此示例中,在创建了一个名为
feature的分支(橙色)后,来自main的四个提交(紫色)被导入到feature分支:
虽然大多数变基都是针对 main 进行的,但你也可以针对任何其他分支进行变基。你还可以指定不同的远程仓库。
例如,使用 upstream 而不是 origin。
git rebase 会重写提交历史。它可能导致共享分支中的冲突和复杂的合并冲突。
与其将你的分支变基到默认分支,不如考虑使用 git pull origin master。拉取操作有类似的效果,但风险较小,不会影响他人的工作。
变基(Rebase)
当你使用 Git 进行变基时,每个提交都会应用到你的分支上。 当出现合并冲突时,系统会提示你解决它们。
要提交更高级的选项,请使用 交互式变基。
先决条件:
- 你必须拥有 权限 才能强制推送到分支。
要使用 Git 将你的分支变基到目标分支:
-
打开终端并切换到你的项目目录。
-
确保你拥有目标分支的最新内容。 在此示例中,目标分支是
main:git fetch origin main -
切换到你的分支:
git checkout my-branch -
可选。创建你的分支备份:
git branch my-branch-backup如果从备份分支恢复,此之后添加到
my-branch的变更将会丢失。 -
针对
main分支进行变基:git rebase origin/main -
如果存在合并冲突:
-
在你的编辑器中解决冲突。
-
暂存变更:
git add . -
继续变基:
git rebase --continue
-
-
强制推送你的变更到目标分支,同时保护他人的提交:
git push origin my-branch --force-with-lease
交互式变基(Interactive rebase)
使用交互式变基来指定如何处理每个提交。 以下说明使用 Vim 文本编辑器来编辑提交。
要进行交互式变基:
-
打开终端并切换到你的项目目录。
-
确保你拥有目标分支的最新内容。在此示例中,目标分支是
main:git fetch origin main -
切换到你的分支:
git checkout my-branch -
可选。创建你的分支备份:
git branch my-branch-backup如果从备份分支恢复,此之后添加到
my-branch的变更将会丢失。 -
在 GitLab UI 中,在你的合并请求中,确认要在 Commits 选项卡中变基的提交数量。
-
打开这些提交。例如,要编辑最后五个提交:
git rebase -i HEAD~5Git 在你的终端文本编辑器中打开提交,按时间顺序从旧到新。 每个提交显示要执行的操作、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 -
按 i 切换到 Vim 的编辑模式。
-
使用方向键将光标移动到你要编辑的提交。
-
对于除第一个提交外的每个提交,将
pick更改为squash或fixup(或s或f)。 -
对剩余的重复此操作。
-
结束编辑模式,保存并退出:
- 按 ESC。
- 输入
:wq。
-
当压缩提交时,Git 会提示你编辑提交消息:
- 以
#开头的行将被忽略,不包含在提交消息中。 - 要保留当前消息,请输入
:wq。 - 要编辑提交消息,切换到编辑模式,进行更改,然后保存。
- 以
-
将你的变更推送到目标分支。
-
如果在变基前没有将提交推送到目标分支:
git push origin my-branch -
如果已经推送了提交:
git push origin my-branch --force-with-lease某些操作需要强制推送才能对分支进行更改。有关更多信息,请参阅 强制推送到远程分支。
-
从命令行解决冲突
为了让你对每个变更有最大的控制权,你应该在本地通过命令行解决复杂的冲突,而不是在 GitLab 中。
先决条件:
- 你必须拥有 权限 才能强制推送到分支。
-
打开终端并切换到你的功能分支:
git switch my-feature-branch -
将你的分支变基到目标分支。在此示例中,目标分支是
main:git fetch git rebase origin/main -
在你首选的代码编辑器中打开冲突文件。
-
定位并解决冲突块:
- 选择你要保留的版本(
=======之前或之后)。 - 删除你不保留的版本。
- 删除冲突标记。
- 选择你要保留的版本(
-
保存文件。
-
对每个有冲突的文件重复此过程。
-
暂存你的变更:
git add . -
提交你的变更:
git commit -m "Resolve merge conflicts"你可以运行
git rebase --abort在此点之前停止进程。 Git 会中止变基并将分支回滚到运行git rebase之前的状态。运行git rebase --continue后,你无法中止变基。 -
继续变基:
git rebase --continue -
强制推送变更到你的远程分支:
git push origin my-feature-branch --force-with-lease
强制推送到远程分支
复杂的 Git 操作,如压缩提交、重置分支或变基,都会重写分支历史。 Git 需要强制更新这些变更。
不建议在共享分支上强制推送,因为你可能会破坏他人的变更。
如果分支是 受保护的, 除非你:
- 取消保护。
- 允许强制推送。
否则你无法强制推送。
有关更多信息,请参阅 允许在受保护分支上强制推送。
恢复你的备份分支
如果变基或强制推送失败,从备份恢复你的分支:
-
确保你在正确的分支上:
git checkout my-branch -
将你的分支重置为备份:
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 错误:
- 解决任何合并冲突。
- 确认源分支存在且有提交。
- 确认目标分支存在。
- 确认已生成差异。
/rebase 后忽略 /merge 快速操作
如果使用了 /rebase,则忽略 /merge,以避免竞态条件,即源分支在变基之前被合并或删除。