Git | 变基操作

基本概念

将当前分支的提交移动到另一个基端 base 上,从而重新组织提交历史

merge 不同,rebase 会创建新提交来替代旧提交,使得提交历史呈现线性结构

适用场景
  • 整理本地提交历史 ------ 在推送前用 rebase 整理杂乱的分支提交,使其更清晰
  • 避免不必要的合并提交 ------ 希望提交历史是线性结构时(如开源项目的 PR
  • 同步上游代码 ------ 将当前分支基于上游最新代码重新应用更改(如 git pull --rebase
原理
初始状态
  • 初始时,master 分支与 feature 分支均有提交,HEAD 当前分支在 feature ,此时执行指令:

    shell 复制代码
    git rebase master	# feature分支上执行,将当前分支feature变基到目标分支master上
找到共同祖先
  • 找到当前分支 feature 和目标分支 master 的最近共同祖先 common ancestor,即两个分支分叉处的提交
提取当前分支独有提交
  • 从共同祖先开始,提取当前分支 feature 之后的所有提交更改,保存为临时补丁
应用提交到目标分支
  • 移动 feature 分支的指针到 master 的最新提交(新基端)

    此时 feature 的提交历史没有指针指向,暂时丢失游离(可以通过 git reflog 找回)

  • 将之前提取的补丁应用到 master 新基端,生成新提交(内容相同,提交哈希值不同)

    如果遇到冲突,Git 暂停 rebase 过程,解决冲突后继续

    shell 复制代码
    git add
    git rebase --continue
对比 merge(合并)与 rebase(变基)
示意图
  • 变基 ------ 在当前分支 feature 执行 git rebase master,将 feature 的提交嫁接到 master上,重写历史,保持线性
  • 合并 ------ 在当前分支 feature 执行 git merge master,将 master 的提交合并到 feature上,生成合并提交,保留历史
关键区别
  • rebase 重写历史,merge 保留历史
    • rebasefeature 的提交看起来基于 master 的最新提交开发(线性历史)
    • merge 会保留分支的分叉和合并记录(非线性的历史)
  • merge 会生成新提交,rebase 不会
    • merge 一定会生成合并提交,即使没有冲突
    • rebase 只是重新应用提交,不会额外生成提交
  • rebase 更适合本地整理,merge 更适合公共分支
    • 如果在开发本地分支,并希望提交历史清晰,用 rebase
    • 如果在合并公共分支(如团队协作的 develop),用 merge 更安全

指令介绍

变基分支 git rebase
  • 语法

    sh 复制代码
    git rebase [选项] <目标分支>
    参数 说明
    -i / --interactive 进入交互式变基(可修改提交)
    --continue 解决冲突后继续变基
    --abort 终止变基,恢复到变基前的状态
    --skip 跳过当前提交(冲突无法解决时使用)
    --onto <新基端> 将提交移动到另一个基端(复杂变基场景)
    -p / --preserve-merges 保留合并提交(默认会丢弃)
    --autostash 自动暂存未提交的更改(防止变基失败)
  • 具体示例

    • 基本变基 ------ 将当前分支 feature 变基到目标分支 master

      shell 复制代码
      $ git checkout feature
      $ git rebase master
      shell 复制代码
      # 初始状态
      A---B---C (master)
      \
      D---E (feature)
      
      # 执行 git rebase master 后
      A---B---C (master)
         \
          D'---E' (feature)
    • 交互式变基(修改提交)

      shell 复制代码
      $ git rebase -i HEAD~3  # 修改最近3个提交

      进入交互式界面后,可以:

      方法 说明 方法 说明
      pick 保留提交(默认) squash 合并到前一个提交
      reword 修改提交信息 drop 删除提交
      edit 修改提交内容 --- ---
      shell 复制代码
      pick 1a2b3c Commit 1
      reword 4d5e6f Commit 2
      squash 7g8h9i Commit 3
    • 变基过程中遇到冲突

      sh 复制代码
      $ git add <冲突文件>			  # 手动解决冲突后添加文件
      sh 复制代码
      $ git rebase --continue			# 继续变基
      shell 复制代码
      $ git rebase --abort			# 放弃变基
    • 部分提交移动到另一个分支 ------ 把当前分支 topicGH)移动到目标分支 main

      shell 复制代码
      git rebase --onto main feature topic
      shell 复制代码
      # 初始状态
      A---B---C (main)
      \
      D---E---F (feature)
           \
            G---H (topic)
      
      # 把 topic 分支(G 和 H)移动到 main 分支的最新提交 C 上
      A---B---C (main)
      \   \
      \   G'---H' (topic)
       \
        D---E---F (feature)

变基

相关指令
  • git rebase ------ 将当前分支的提交变基到指定分支,重新组织提交历史
场景一:基本变基
  1. 切换分支 ------ 从 master 分支切换到 feature 分支

    shell 复制代码
    $ git checkout feature
  2. 变基 ------ 将当前分支 feature 变基到目标分支 master

    shell 复制代码
    $ git rebase master

    效果:

    shell 复制代码
    # 初始状态
    A---B---C (master)
      \
       D---E (feature)
    
    # 执行 git rebase master 后
    A---B---C (master)
          \
           D'---E' (feature)
场景二:变基时冲突
  1. 变基时报错

    shell 复制代码
    $ git rebase
    Auto-merging main.py
    CONFLICT (content): Merge conflict in main.py
    error: could not apply 2264188... add function_a
    hint: Resolve all conflicts manually, mark them as resolved with
    hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
    hint: You can instead skip this commit: run "git rebase --skip".
    hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
    Could not apply 2264188... add function_a

    冲突文件main.py 存在内容冲突

    冲突原因 :在变基过程中,提交 2264188 的修改与当前代码存在冲突

  2. 查看冲突文件 ------ 输出未合并的路径 Unmerged paths

    shell 复制代码
    $ git status
    Unmerged paths:
      (use "git add <file>..." to mark resolution)
            both modified:   main.py
  3. 手动解决冲突 ------ 打开 main.py,保留正确的代码,并添加到暂存区

    shell 复制代码
    <<<<<<< HEAD
    当前分支的代码(HEAD指向的版本)
    =======
    要应用的提交代码(2264188的修改)
    >>>>>>> 2264188... add function_a
    shell 复制代码
    $ git add main.py
  4. 继续变基

    shell 复制代码
    $ git rebase --continue
  5. 放弃变基 ------ 回到 rebase 前的状态

    shell 复制代码
    $ git rebase --abort
  6. 跳过当前提交 ------ 该提交的修改将被丢弃

    shell 复制代码
    $ git rebase --skip
场景三:检测到存在未完成的变基
  1. 检测到存在未完成的变基操作

    shell 复制代码
    fatal: It seems that there is already a rebase-merge directory, and
    I wonder if you are in the middle of another rebase.  If that is the
    case, please try
            git rebase (--continue | --abort | --skip)
    If that is not the case, please
            rm -fr ".git/rebase-merge"
    and run me again.  I am stopping in case you still have something
    valuable there.

    问题原因 ------ Git.git/rebase-merge 目录保存未完成的变基状态,可能由于:

    • 之前的 git rebase 被意外中断(如关闭终端)
    • 冲突未完全解决就停止了操作
    • 系统崩溃或强制退出
  2. 解决方案

    • 继续未完成的变基:git rebase --continue
    • 放弃当前变基:git rebase --abort
    • 跳过当前提交:git rebase --skip
    • 手动清理(仅当确认无价值内容时):rm -fr ".git/rebase-merge"

参考文献

更多内容可以参考以下文章:

相关推荐
007php0072 小时前
Git 操作偏门指南:常用和隐藏命令与问题解决
java·git·面试·职场和发展·golang·jenkins·php
可爱又迷人的反派角色“yang”3 小时前
GitLab配置与git集成实践
linux·网络·git·docker·云计算·gitlab
Apifox.3 小时前
Apifox 12 月更新| AI 生成用例同步生成测试数据、接口文档完整性检测、设计 SSE 流式接口、从 Git 仓库导入数据
前端·人工智能·git·ai·postman·团队开发
lifewange4 小时前
Git/Gitee/GitHub有什么区别
git·gitee·github
222you5 小时前
智慧社区:调用腾讯云的人脸识别接口完成人脸采集的功能
云计算·github·腾讯云
弘毅 失败的 mian5 小时前
Git 分支管理
大数据·经验分享·笔记·git·elasticsearch
逛逛GitHub6 小时前
推荐 8 个爷青回 GitHub 开源游戏,太怀念了。
github
NEXT066 小时前
从Git三连到时光机大师:我的代码终于有了后悔药
git
QQ__17646198246 小时前
Ubuntu系统克隆Github仓库项目到本地
linux·ubuntu·github