⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 juejin.cn/post/7587017021314498595 「Dolphin_海豚」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

写这篇文章的契机也是因为有次组内技术分享会里面讨论过这个话题,这两个指令都是用来合并分支代码的,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 上

git checkout master
git merge feature/A

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

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

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

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,别人再去合代码必然导致冲突

文章目录
  1. 1. 结论