Git 变基和强制推送介绍

本指南帮助您从重新定位、强制推送和修复在本地合并冲突起步。

在深入研究本文档之前,请确保您熟悉通过命令行使用 Git

Git 变基

变基是 Git 中非常常见的操作。有以下变基选项:

变基前

cautiongit rebase 重写提交历史。在共享分支中执行它可能有害。它会导致复杂且难以解决的合并冲突。在这些情况下,不要基于默认分支变基您的分支,而是考虑拉取默认分支(git pull origin master)。它具有类似的效果,而不会影响您的贡献者的工作。

在变基之前备份您的分支更安全,以确保你不会丢失任何变化。例如,参考一个名为 my-feature-branch功能分支

  1. 在终端中打开您的功能分支:

    git checkout my-feature-branch
    
  2. 从中检出一个新分支:

    git checkout -b my-feature-branch-backup
    
  3. 回到原来的分支:

    git checkout my-feature-branch
    

现在您可以安全地对其进行变基。如果出现任何问题,您可以基于 my-feature-branch-backup 重置 my-feature-branch 来恢复您的更改:

  1. 确保您位于正确的分支 (my-feature-branch) :

    git checkout my-feature-branch
    
  2. 基于 my-feature-branch-backup 重置它:

    git reset --hard my-feature-branch-backup
    

注意,如果您在创建备份分支后更改了 my-feature-branch ,则重置时会丢失。

常规变基

使用常规变基,您可以使用默认分支(或任何其他分支)更新您的功能分支。这是基于 Git 的开发策略的重要一步。您可以确保添加到代码库的 更改不会破坏在您创建功能分支之后添加到目标分支的任何已有更改。

例如,要使用默认分支更新分支 my-feature-branch (此处使用 main):

  1. main 获取最新更改:

    git fetch origin main
    
  2. 检出您的功能分支:

    git checkout my-feature-branch
    
  3. 基于 main 变基:

    git rebase origin/main
    
  4. 强制推送到您的分支。

当您变基时:

  1. Git 导入您创建功能分支开始到现在的所有提交到 main
  2. Git 将您在功能分支中的提交放在从 main 导入的所有提交之上:

Git rebase illustration

可以用您想要的任何其他分支替换 main,例如,基于 release-10-3 进行变基。您还可以将 origin 替换为其他远端仓库,例如 upstream。要检查您链接到本地仓库的 remotes,您可以运行 git remote -v

如果有合并冲突,Git 会在继续变基前提示您修复。

要了解更多信息,请查看关于变基的 Git 文档和变基策略文档。

使用极狐GitLab UI 变基

如果满足下列所有条件,您可以在合并请求中直接使用快捷操作变基您的功能分支:

  • 您的功能分支不存在合并冲突
  • 您拥有源项目的开发者角色。此角色授予您推送到源项目的源分支的权限。
  • 如果合并请求在派生仓库中,必须允许来自上游项目的成员提交。

要从 UI 变基:

  1. 转到您的合并请求。
  2. 在评论中输入 /rebase
  3. 选择评论

极狐GitLab 会安排计划,基于默认分支对功能分支变基,并尽快执行。

执行变基操作的用户被视为向合并请求添加提交的用户。当合并请求批准设置防止添加提交的用户批准已启用,此设置可防止用户同时批准合并请求。

交互式变基

您可以使用交互式变基来修改提交。例如,修改提交消息、压缩(将多个提交合并为一个)、编辑或删除提交。使用 rebase 更改过去的提交消息,并组织分支的提交历史以保持其整洁。

note如果您想保持默认分支的提交历史整洁,不需要在合并每个合并请求前手动压缩所有提交,GitLab 会使用压缩和合并自动完成。

如果您想更改最近提交中的任何内容,请将 --interactive(或 -i)标识传递给 rebase 命令来使用交互式变基。

例如,如果您想更改分支中的最后三个提交 (HEAD~3), 运行:

git rebase -i HEAD~3

Git 在终端文本编辑器中打开最后三个提交并描述了您可以使用的所有交互式变基选项。默认选项是 pick,它保持提交不变。根据您要在每次提交中执行的操作替换关键字 “pick” 。为此,您需要编辑终端文本编辑器中的提交。

例如,如果您在 macOS 的 Zsh shell 中使用 Vim 作为文本编辑器,并且想要 squashfixup 所有三个提交(将它们合二为一):

  1. 按键盘上的 i 切换到 Vim 的编辑模式。
  2. 使用键盘箭头导航以将第二个提交关键字从 pick 编辑为 squashfixup(或 sf)。对第三个提交执行相同操作。第一个提交应该保持不变pick),因为我们想将第二个和第三个压缩到第一个中。
  3. Escape 退出编辑模式。
  4. 输入:wq 来”写入”(保存)和”退出”。
  5. 压缩时,Git 会输出提交消息,因此您有机会对其进行编辑:
    • 所有以 # 开头的行都将被忽略并且不包含在提交消息中。其他一切都包括在内。
    • 保持原样,输入:wq。编辑提交消息:切换到编辑模式,编辑提交消息,然后像刚才一样保存。
  6. 如果您在 rebase 之前没有推送提交到远端分支,正常推送更改。如果您已经推送了这些提交,请改为强制推送

注意,通过命令行编辑的步骤取决于您的操作系统和您使用的 shell。

强制推送

当您执行更复杂的操作时,例如压缩提交、重置或变基您的分支,您必须 强制 更新远端分支。这些操作意味着重写分支的提交历史。要强制更新,请将标志 --force-f 传递给 push 命令。例如:

git push --force origin my-feature-branch

当您在共享分支上工作时,推荐强制更新。

或者,您可以传递标志 --force-with-lease。它更安全,因为如果其他人向远端分支添加了更多提交,它不会覆盖远端分支上的任何内容:

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

如果要强制推送的分支是受保护的,您无法强制推送除非:

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

然后你可以强制推送并再次使其受保护。

合并冲突

由于 Git 是基于逐行比较文件的版本,因此只要分支中更改的行与目标分支中更改的同一行重合(在您从中创建功能分支的那一刻之后),Git 就会识别这些更改为合并冲突。要修复它,您需要选择保留该行的哪个版本。

大多数冲突可以通过极狐GitLab UI 解决。

对于更复杂的情况,有多种解决方法。还有 Git GUI 应用程序可以通过可视化差异来提供帮助。

要在本地修复冲突,可以使用以下方法:

  1. 打开终端并检出您的功能分支,例如,my-feature-branch

    git checkout my-feature-branch
    
  2. 基于目标分支变基您的分支,Git 会提示冲突:

    git rebase origin/master
    
  3. 在你喜欢的代码编辑器中打开有冲突的文件。
  4. 查找冲突块:
    • 它以 <<<<<<< HEAD 标记开始。
    • 下面是您更改的内容。
    • 标记 ======== 表示更改结束。
    • 下面是目标分支的最新变化内容。
    • 标记 >>>>>>> 表示冲突结束。
  5. 编辑文件:选择要保留的版本(在======之前或之后),然后删除文件中不需要的部分。
  6. 删除标记。
  7. 保存文件。
  8. 如果还有其他冲突文件,请重复此过程。
  9. 暂存您的更改:

    git add .
    
  10. 提交您的更改:

    git commit -m "Fix merge conflicts"
    
  11. 继续变基:

    git rebase --continue
    
    caution到目前为止,您可以运行 git rebase --abort 来停止该过程。Git 中止 rebase 并将分支回滚到运行 git rebase 之前的状态。在您运行 git rebase --continue 后,变基不能被中止。
  12. 强制推送到您的远端分支。