git rebase

rebase ⇒ 将一系列节点移动到目标分支的最后 ⇒ 也叫变基

rebase vs cherry-pick

rebase 和 cherry-pick 的操作角度是不一样的

  • cherry-pick 是把别的分支提交合并到当前分支
  • rebase 是把自己提交合并到目标分支

基本原理

初始分支结构为

此时在dev 分支执行 git rebase main

  1. 复制 c2 和 c3 生成内容完全一致,但sha-1不一致的节点
  2. dev 分支移动到了复制后的c3'
  3. c2 和 c3 没有使用,被称之为 悬挂提交,再下次 git 自动执行 git gc 时会被自动移除

此时看起来就像是 dev分支是基于 main分支的最新提交来开发的

这样的好处是

  1. 整个开发分支线变成线性的了,相对简单
  2. 在main 分支执行 git merge dev 的时候就变成了 快进合并

这也是rebase 和 merge 的最大区别

  1. merge 如果不是快进会产生新的提交节点
  2. rebase 是让节点尽可能的线性,使merge 可以快进合并

其中 c3' 是和c3 节点内容完全一致的节点,之所以不复用之前的节点是因为,节点的parent 发生了改变,即改变了历史

在变基的过程中,是需要变基节点依次进行变基操作

  1. c2 执行变基,将c2 相对于c1 的变动作用于c5 ,并依次为基础生成c2'
  2. c3 执行变基,将c3 相对于c2 的变动作用于c2' ,并依次为基础生成c3'
  3. 如果有其余节点指向类似操作

所以其本质也是依次执行三路合并

  1. 第一次 ⇒ 三路为 c1 、c2 、c5
  2. 第二次 ⇒ 三路为 c3 、c2 、c2'
  3. 依次类推

既然是三路合并,就可能会产生冲突,解决方法如下

  1. 解决冲突:用编辑器(比如 vi)修改冲突文件,保留需要的改动,然后用以下命令继续:

    shell 复制代码
    git add .
    git rebase --continue
  2. 忽略冲突::

    shell 复制代码
    git rebase --skip

    意思是冲突了,就将当前提交视为空提交,直接跳过,不合并 ⇒ 不推荐

  3. 终止变基:不想继续变基,恢复到变基前的状态:

    shell 复制代码
    git rebase --abort

    此时会和数据库的事务一样,依次回滚,将之前的变基操作都还原

rebase vs merge

并列分支

单人维护分支推荐使用rebase ,假设分支结构如下

shell 复制代码
A---B---C---D (main)
     \   \
      \   H---I (fix/log)
       \
        E---F---G (fix/login)

此时在 fix/login 分支执行 git rebase main ,再切到 main 执行git merge fix/login

shell 复制代码
A---B---C---D---E'---F'---G' (main)
         \
          H---I (fix/log)

此时别的分支不会受到任何影响,使用rebase 还可以让分支合并是线性的,而merge 合并后会生成新节点

例如在 main 分支直接执行 git merge fix/login ,此时将会生成一个新合并节点 M

shell 复制代码
A---B---C---D----------M  (main)
     \   \           /
      \   E---F---G-/   (fix/login)
       \
        H---I          (fix/log)

分支上的分支(依赖分支)

shell 复制代码
A---B---C---D (main)
     \
      E---F---G 
          \
           X---Y 

此时就需要团队协商确认,大家统一使用merge 还是 rebase

假设初始分支如下

shell 复制代码
A---B---C---D (main)
     \
      E

张三从 E 开始继续开发,生成F 和 G

shell 复制代码
A---B---C---D (main)
     \
      E---F---G (fix/zs)

但此时李四,从E 开了一个新分支进行开发, 结构变成了

shell 复制代码
A---B---C---D (main)
     \
      E---F---G (fix/zs)
          \
           X---Y (fix/ls)

此时如果在 fix/zs 执行 git rebase main

对于张三而言,分支就变成了

shell 复制代码
A---B---C---D---E'---F'---G' (main)

此时张三进行了更新推荐,李四执行了git pull 此时对于李四而言,她的分支变成了

shell 复制代码
A---B---C---D---E'---F'---G' (main)
     \
      E---F---G 
          \
           X---Y (fix/ls)

原分支不变,E' 、F'、G' 会新增提交

如果此时在 fix/ls 执行 git rebase main

  • 因为 E、F、G 和 E'、F'、G' 内容一致

    所以 E、F、G 会被抛弃,直接使用 E'、F'、G'

    所以 E、F、G 也被称之为 空提交

最终分支结构如下

shell 复制代码
A---B---C---D---E'---F'---G' (main)
											\
						           X---Y (fix/ls)

此时并不会有很大的问题

但如果此时 李四在main执行的git merge fix/ls , 分支结构就变成了

shell 复制代码
A---B---C---D---E'---F'---G'---M  (main)
     \                   \     /
      E---F---G           \   /
          \                X---Y (fix/ls)
           \                    /
            --------------------

此时很明显 存在很多重复的 parent 节点

所以一般情况下,推荐分支的开发模式是 git flow模型 + git rebase

  1. 只 rebase 单人维护开发的分支

  2. 如果一个分支是多人一起维护的,就不能随意使用rebase

    • 此时要么都用merge ,要么都用rebase
    • 不应该混用merge 和 rebase
相关推荐
挖掘狂人2 天前
Git 从 0 到 1:用一个小项目走完 add / commit / reset / merge / rebase / push
git·后端·github
codigger2 天前
Git 三区域模型:把 add、commit、reset、merge 一次讲透
git·github·编程·编程语言
水饺编程2 天前
第1章:开发环境搭建,在 Windows 中安装 Git
linux·c语言·汇编·git·ubuntu
idanzk2 天前
Git 推送 GitHub 报 SSL_READ /src refspec main 不匹配 完整踩坑记录
git·github·ssl
星恒随风2 天前
Linux开发工具详解(二):Git版本控制、GitHub协作与GDB调试实战
linux·笔记·git·学习·github
寺中人3 天前
Xshell 完全入门指南:从安装到实战,远程连接+文件传输+会话管理全拆解
git·ssh·github·php·远程连接·xshell·运维工具
酬谢神明则必安3 天前
git学习记录01
linux·git·学习
lingchen19063 天前
版本控制 Git源代码项目管理
git
虫无涯3 天前
Coverity 如何结合 GJB8114-2013使用?
git·单元测试·嵌入式测试·coverity·静态扫描
喵本喵叁肆3 天前
Git 深度解读:从对象模型到分支指针,把版本控制的内核讲透
git