到底是选 merge 还是选 rebase

写这篇文章的契机也是因为有次组内技术分享会里面讨论过这个话题,这两个指令都是用来合并分支代码的,rebase 可以把分支记录弄成一条线性,而 merge 保留了分支树状图,以我的习惯是更倾向于 merge,因为我大部分场景用不上 rebase

我们先看个大家开发中非常常见的场景,两个人基于 master 的同一个 commit 节点各自拉起一个新的 feature 分支,其中一个人 A 有多个 commit,并率先完成任务合入 master,B 也有多个 commit ,在他完成任务准备合入 master 时,发现有冲突,这里我模拟的每个提交都是针对同一个文件,每个 commit 都会有冲突

在 A 合并 master 前的分支图如下

可以看到 feature/A 分支 和 feature/B 分支都是基于 master 最新的 commit 拉起的分支,两条分支并行开发,这里我为了跟随时间线,用顺序数字模拟 commit 信息,两条分支各自新增了 3 个 commit

现在我们把 A 通过 merge 合并到 master 上

bash 复制代码
git checkout master
git merge feature/A

可以看到 A merge 到 master 后,master 和 feature/A 保持一致了

好了,开头说的场景已经出现了,这个时候你是 B 你会怎么做,要是我会选择 merge,那就先看下 merge 的表现

bash 复制代码
git checkout master
git merge feature/B

由于我的每个 commit 都是针对同一个文件做出更改,所以最终汇入必然要去解决冲突

可以看到这里的冲突是让你一次性解决的,解决完冲突后提交看 分支图

可以看到,merge 会创建一个新的合并提交,把两个分支平行的合并,保留了分支历史

这里顺带解释下为啥有时候 merge 没有 mr 节点,有时候又有,其实大部分情况下都会有。比如这里的 feature/A 合入 master 就没产生 mr 节点,feature/B 后合入 master 就产生了 mr 节点

merge 节点有没有取决于 git 是否需要创建一个新的合并提交

可能你体感上是永远会有 mr 节点,因为远程合作大部分场景 master 都是一直在前进的

  • fast-forward 合并
    • master 还停留在你分支起点的那个提交,比如 feature/A 合入到 master 的时候,master 和 feature/A 同一个起点,这就是 fast-forward 提交,就不会产生 mr 节点
  • 非 fast-forward 合并
    • master 相较于你的分支有了新的提交,比如 feature/B 的起点是最初的 docs: add README ,在 feature/B 准备合入 master 时,master 最新的提交却是 feature/A 的 dosc: 5

估计这个时候就小盆友要说了,我的这个 mr 节点是在我解决冲突时提交的,其实就算没有冲突,非 fast-forward 合并就是会产生 mr 节点

好,我们现在撤回 feature/B merge 到 master,我们改用 rebase 再来看下对比

撤回之后的分支图如下,master 还是停留在 docs: 5

现在使用 rebase

bash 复制代码
git checkout feature/B
git rebase master

可以看到 vscode 编辑器让我去解决冲突,这还是第一个

要是每个 commit 都有冲突那就每个 commit 都要单独解决一次冲突

一旦解决冲突并 git add,再运行 git rebase --continue,git 就会继续重放下一个提交,若同一段代码在多个提交中都改过,就会感觉是在重复解决冲突

现在回过头来看 git 树

可以看到 最终的 git 记录成一条直线了,看着确实顺眼不少,并且你的分支所有提交都会提前,你也不会产生 合并 的 mr 节点 ,但是你分支上原本的 commit hash (docs:3, dosc: 4, dosc: 6)会发生变化

结论

从 git 提交记录看

  • merge 保留历史记录,非线性,容易产生 mr 节点
  • rebase 将自己的 commit 记录提前并更改你之前的 commit hash,线性,不产生多余的 mr 节点

从 解决冲突 看

  • merge 在汇入那一刻解决所有的冲突,直接对比两个分支代码的终极形态
  • rebase 会按顺序重放你的所有 commit,但凡有冲突的提交都会让你挨个去解决

用 rebase 是有使用场景的,要是不清楚无脑 merge 就好。只有你一个人使用的分支,并且还没 push 到远端,可以去使用 rebase 整理下 git 历史,否则其余所有情况都可以用 merge

git rebase -i 可以整理提交顺序,合并多个小提交,改写提交信息

rebase 一定不能在公共分支上使用,因为这会篡改共有分支的 commit hash,别人再去合代码必然导致冲突

相关推荐
阿蒙Amon11 分钟前
C#每日面试题-常量和只读变量的区别
java·面试·c#
程序员小白条40 分钟前
面试 Java 基础八股文十问十答第八期
java·开发语言·数据库·spring·面试·职场和发展·毕设
xlp666hub2 小时前
Linux 设备模型学习笔记(1)
面试·嵌入式
A half moon2 小时前
【从开发到上线-全栈开发教程】Git上传本地项目到仓库
git
三水吉吉3 小时前
git commit 后,取消其中一个文件的提交
git
南囝coding3 小时前
CSS终于能做瀑布流了!三行代码搞定,告别JavaScript布局
前端·后端·面试
踏浪无痕4 小时前
Go 的协程是线程吗?别被"轻量级线程"骗了
后端·面试·go
Albert Edison4 小时前
【Git】多人协作二(不同分支下)
git·elasticsearch·svn·github
一只叫煤球的猫5 小时前
为什么Java里面,Service 层不直接返回 Result 对象?
java·spring boot·面试
求梦8205 小时前
字节前端面试复盘
面试·职场和发展