www.cnblogs.com Open in urlscan Pro
2400:3200:1300::ec2  Public Scan

URL: https://www.cnblogs.com/michael-xiang/p/13179837.html
Submission: On March 29 via api from US — Scanned from DE

Form analysis 1 forms found in the DOM

GET https://zzk.cnblogs.com/s

<form id="zzk_search" class="navbar-search dropdown" action="https://zzk.cnblogs.com/s" method="get" role="search">
  <input name="w" id="zzk_search_input" placeholder="代码改变世界" type="search" tabindex="3" autocomplete="off">
  <button id="zzk_search_button" onclick="window.navbarSearchManager.triggerActiveOption()">
    <img id="search_icon" class="focus-hidden" src="//assets.cnblogs.com/icons/search.svg" alt="搜索">
    <img class="hidden focus-visible" src="//assets.cnblogs.com/icons/enter.svg" alt="搜索">
  </button>
  <ul id="navbar_search_options" class="dropdown-menu quick-search-menu">
    <li tabindex="0" class="active" onclick="zzkSearch(event, document.getElementById('zzk_search_input').value)">
      <div class="keyword-wrapper">
        <img src="//assets.cnblogs.com/icons/search.svg" alt="搜索">
        <div class="keyword"></div>
      </div>
      <span class="search-area">所有博客</span>
    </li>
    <li tabindex="1" onclick="zzkBlogSearch(event, 'michael-xiang', document.getElementById('zzk_search_input').value)">
      <div class="keyword-wrapper">
        <img src="//assets.cnblogs.com/icons/search.svg" alt="搜索">
        <div class="keyword"></div>
      </div>
      <span class="search-area">当前博客</span>
    </li>
  </ul>
</form>

Text Content

 * 
 * 会员
 * 周边
 * 新闻
 * 博问
 * AI培训
 * 云市场

 *  * 
      所有博客
    * 
      当前博客

 * 我的博客 我的园子 账号设置 简洁模式 ... 退出登录
   注册 登录


MICHAEL翔


公众号『CODER魔法院』,效率软件控,欢迎关注! 因上努力,果上随缘,做好自己!

 * 博客园
 * 首页
 * 标签
 * 归档
 * 导航
   * 谷歌
   * 百度
 * 
 * 联系
 * 订阅
 * 管理

随笔 - 158  文章 - 0  评论 - 38  阅读 - 50万
 


图解 GIT 基本命令 MERGE 和 REBASE


图解 Git 的 merge 与 reabse 命令,彻底弄懂它们!


GIT 基本命令 MERGE 和 REBASE,你真的了解吗?


前言#

Git 中的分支合并是一个常见的使用场景。

 * 仓库的 bugfix 分支修复完 bug 之后,要回合到主干分支,这时候两个分支需要合并;
 * 远端仓库的分支 A 有其他小伙伴合入了代码,这时候,你需要和远端仓库的分支 A 进行合并;

以上只是列举了分支合并的一些常见场景,关于 merge 和 rebase 命令你足够了解吗?


HEAD 的理解#

在介绍本文的主要内容之前,我们先理解一下 HEAD 。

HEAD 指向当前所在的分支,类似一个活动的指针,表示一个「引用」。例如当前在 develop 分支,HEAD 内容就是 ref:
refs/heads/develop。

HEAD 既可以指向「当前分支」的最新 commit,也可以指向历史中的某一次 commit (「分离头指针」的情况)。归根结底,HEAD
指向的就是某个提交点。

当我们做分支切换时,HEAD 会跟着切换到对应分支。


FAST-FORWARD 与 --NO-FF 的区别#

假如有一个场景:有两个分支,master 分支和 feature 分支。现在,feautre 分支需要合并回 master 分支。



fast-forward 合并方式是条件允许的情况,通过将 master 分支的 HEAD 位置移动到 feature
分支的最新提交点上,这样就实现了快速合并。这种情况,是不会新生成 commit 的。



--no-ff 的方式进行合并,master 分支就会新生成一次提交记录。



> 如果条件满足时,merge 默认采用的 fast-forward 方式进行合并,除非你显示的加上 --no-ff 选项;而条件不满足时,merge
> 也是无法使用 fast-forward 合并成功的!


MERGE 操作#

上面用图解的方式介绍了 fast-forward 和 --no-ff 的区别。下面,结合实际的代码仓进行合并操作,举几个栗子理解一下。

> git merge
> 操作是区分上下文的。当前分支始终是目标分支,其他一个或多个分支始终合并到当前分支。这个注意点记住了,方便记忆!所以,当需要将某个分支合并到目标分支时,需要先切到目标分支上。


FAST-FORWARD 合并#

刚刚一直在强调条件允许的时候,fast-forward 才能合并成功。条件指的是什么呢?

其实指的是源分支和目标分支之间没有分叉(单词 diverge),这种情况才可以进行快速合并。如果是下图中的场景,无法通过 HEAD 的快速移动实现分支的合并!



下面进行一个不分叉的场景的示例:



现在需要将 feature 分支合入到 master 分支,默认使用 fast-forward 方式:

Copy# 切到目标分支
git checkout master
git merge feature


命令行里显示了 Fast-forward 的提示:



看一眼 master 分支合入的前后对比(注意 HEAD 的位置):






NO-FF 合并#

不分叉的场景是否可以强制采用 --no-ff 方式合并呢?可以!

Copy# master 回到合入前的状态
git reset --hard d2fa1ae
git merge feature --no-ff




这次命令行没有 Fast-forward 的提示了。

看一眼 master 分支图:



这个图和上面讲解 no-ff 命令时的示意图一致,果然会有新 commit 生成。


分叉场景的合并#



上面的图展示了我们经常遇到的一个场景,特性分支创建之后,源分支也会有新的提交。这就是形成分叉了。

这时候如果我们进行合并呢?

Copygit merge feautre




可以看到,虽然默认会尝试 fast-forward 的方式进行合并,但是因为分叉了,所以此时会采用 no-ff 的方式进行合并!有新的 commit 生成了!

> fast-forward 方式对应的合并参数是 --ff

我们试试这个参数 --ff-only,顾名思义,就是强制只使用 ff 方式进行合并:

Copy# 回到合并前
git reset --hard 3793081
git merge feature --ff-only




经过测试,当分叉时,因为无法使用 ff 方式合并,即使你强制指定使用该方式合并也不行,会提示终止!

附上 Git 官方文档中的解释,方便理解:

CopyWith --ff, when possible resolve the merge as a fast-forward (only update the branch pointer to match the merged branch; do not create a merge commit). When not possible (when the merged-in history is not a descendant of the current history), create a merge commit.



REBASE 操作#

rebase 命令是一个经常听到,但是大多数人掌握又不太好的一个命令。rebase 合并往往又被称为 「变基」,我称为
「基化」🤣。「基」的理解很重要,理解了它,其实 rebase 命令你就掌握了。

我的描述可能并不准确,只是为了能够帮助你理解。这里的「基」就是一个「基点」、「起点」的意思。「变基」就是改变当前分支的起点。注意,是当前分支! rebase
命令后面紧接着的就是「基分支」。

变基前:



git reabse master feature 变基后:



> git rebase 命令通常称为向前移植(forward porting)。


变基提交示例#

我们接下来进行实际的测试,将代码库状态构造成分叉的状态,状态图如下:



以 master 分支为基,对 feautre 分支进行变基:

Copygit checout feature
git rebase master


以上两行命令,其实可以简写为:git rebase master feature

> 特性分支 feature 向前移植到了 master 分支。经常使用 git rebase 操作把本地开发分支移植到远端的 origin/<branch>
> 追踪分支上。也就是经常说的,「把你的补丁变基到 xxx 分支的头」



可以发现,在 master 分支的最新节点(576cb7b)后面多了 2 个提交(生成了新的提交记录,仅仅提交信息保持一致),而这两个提交内容就是来自变基前
feature 分支,feature 分支的提交历史发生了改变。

观察上图还可以发现,变基后,改变的只是 feature 分支,基分支(master 分支)的 HEAD 指针依然在之前的 commit
(576cb7b)处。这时候要将 feature 分支合入到 master 分支上,就满足 fast-forward 的条件了,master
分支执行快速合并,将 HEAD 指针指向刚刚最新合入的提交点:

Copygit checkout master
git merge feature




看下图 master 分支图,观察 HEAD 指针的位置:


rebase 变基操作最适合的是本地分支和远端对应跟踪分支之间的合并。这样理解可能会更清晰一点。比如,远端仓库里有一个特性分支
feature,除了你开发之外,还有其他人往这个分支进行合入。当你每次准备提交到远端之前,其实可以尝试变基,这时候基分支就是远端的追踪分支。

下图是仓库的分支图:



Copygit fetch
git rebase origin/feature feature




观察上图,我们本地的提交以远端分支的最新提交为「基」,将差异提交重新进行了提交!远端分支的提交记录依然是一条直线~如果分叉的情况,不采用这种「变基操作」,而直接采用
merge 的方式合并,就会有如下这种分支提交图:



因为分叉了,采用 git pull 时也没法 fast-forward 合并,只能采用 no-ff
方式合并,最后的提交历史就会像上图那样。会产生一个合并提交。同时,分支图也显得稍微杂乱了一点,因为 feature
分支不是一条直线了。但是,其实也有好处,可以实际的看出来合并的提交历史。该选择哪个,往往取决于团队的选择策略。


REBASE 总结#

rebase 命令其实关键在于理解「基」,git rebase
<基分支>,就是将当前基分支与当前分支的差异提交获取到,然后在「基分支」最新提交点后面将差异提交逐个再次提交,最后将当前分支的 HEAD 指针指向最新的提交点。

「基分支」的 HEAD 位置是不变的。要想完成分支合并,完成变基之后,需要再进行分支间的合并等操作。

rebase 命令的用法也不止于此,计划后期会专门写一篇介绍她的文章。本文本来是计划介绍 merge
命令的,但是合并的方式中,其实也经常涉及变基操作之后的合并,因此,干脆就放一起比较好了,这样易于理解记忆。


补充#

 * git merge --abort 当合并的过程中,由于冲突难解决,你想放弃合并,回到未合并之前的状态;
 * git log --graph --pretty=oneline --abbrev-commit 可以在命令行方便地查看提交图


一言#

在 Git 这个专辑里有一篇介绍 cherry-pick 的文章,有个小伙伴给了如下的留言,说明自己分享的内容获得了肯定,欣慰啊!



今天肝的这篇文章,介绍了 Git 中的 merge 和 rebase
的基本概念和用法,同时,又自己手动绘制了图!俗话说,一图胜千言,但写完才发现,是真的耗时啊……不过,总结绘图的过程,自己也加深了理解,有些概念也变得更加清晰了!希望,我的总结也能让其他人读懂~

之前我经常会开启文章的「赞赏」,但发现收效甚微,很少有小伙伴会打赏。后来我就每次发文就关闭了这个选项。本文应该是 6
月份的「月末总结」了,就开启一次「月末赞赏」吧!期待小伙伴的支持与鼓励!


参考#

我将本文的参考文章也都注明了,他们也都很有阅读的价值。但由于微信外链的缘故,可以点击右下角的「阅读原文」浏览!

 * StackoverFlow-What is the difference between git merge and git merge --no-ff?
 * git-scm-git-merge
 * 分支的合并
 * Gitlab-Fast-forward merge requests
 * 颜海镜-图解4种git合并分支方法

--------------------------------------------------------------------------------

> 生命不息,折腾不止!关注 「Coder 魔法院」,祝你 Niubilitiy !🐂🍺




分类: IT基础
标签: git
Sponsor
 * PayPal
 * AliPay
 * WeChat


好文要顶 关注我 收藏该文 微信分享
Michael翔
粉丝 - 65 关注 - 105



+加关注
10
0



« 上一篇: 将博客搬至CSDN
» 下一篇: 2020 疫情年一次说走就走的端午重庆游
posted @ 2020-06-22 23:49  Michael翔  阅读(21915)  评论(2)  编辑  收藏  举报

会员力量,点亮园子希望
刷新页面返回顶部
登录后才能查看或发表评论,立即 登录 或者 逛逛 博客园首页

【推荐】阿里巴巴全球数学竞赛,首次向AI开放,期待您的参加
【推荐】园子周边第二季:更大的鼠标垫,没有logo的鼠标垫
【推荐】阿里云云市场联合博客园推出开发者商店,欢迎关注
【推荐】会员力量,点亮园子希望,期待您升级成为园子会员



编辑推荐:
· 深度探索 .NET Feature Management 功能开关的魔法
· 线上 gc 问题 - SpringActuator 的坑
· 记一次 .NET某半导体CIM系统 崩溃分析
· 舒服了,学习了,踩到一个 Lombok 的坑!
· [MAUI]集成高德地图组件至 .NET MAUI Blazor 项目


阅读排行:
· .NET开源免费、功能强大的 Windows 截图录屏神器
· 《HelloGitHub》第 96 期
· 测试开发都这么厉害了?为啥不直接转业务开发?
· 可能是迄今为止最好用的WPF加载动画功能(没有之一)
· 达摩院中试比高:欢迎参加2024阿里巴巴全球数学竞赛(AI可参赛)




公告

昵称: Michael翔
园龄: 9年2个月
粉丝: 65
关注: 105
+加关注




搜索

 


我的标签

 * java(15)
 * springboot(7)
 * git(6)
 * tools(5)
 * shell(5)
 * js(5)
 * 效率软件(5)
 * 网络(5)
 * 绘图(5)
 * sql(4)
 * 更多


随笔分类

 * DevOps(14)
 * IT基础(10)
 * Java(28)
 * Linux(17)
 * Python(20)
 * Tools-Daily(5)
 * Tools-Dev(20)
 * Web(5)
 * 机器学习(5)
 * 容器(5)
 * 生活(2)
 * 数据库(9)
 * 数学(1)
 * 算法(4)
 * 网络(7)
 * 阅读(3)
 * 更多


随笔档案

 * 2020年10月(1)
 * 2020年9月(1)
 * 2020年8月(2)
 * 2020年7月(2)
 * 2020年6月(3)
 * 2020年5月(1)
 * 2020年4月(1)
 * 2020年3月(2)
 * 2020年2月(3)
 * 2019年10月(1)
 * 2019年9月(1)
 * 2019年7月(3)
 * 2019年6月(1)
 * 2019年5月(4)
 * 2019年4月(13)
 * 2019年3月(92)
 * 2019年2月(2)
 * 2016年8月(3)
 * 2016年7月(1)
 * 2015年12月(2)
 * 2015年9月(3)
 * 2015年7月(1)
 * 2015年6月(7)
 * 2015年5月(4)
 * 2015年4月(3)
 * 2015年3月(1)
 * 更多


阅读排行榜

 * 1. 断网环境下利用pip安装Python离线安装包(70948)
 * 2. 将Sublime Text 添加到鼠标右键菜单的教程方法(39979)
 * 3. RPM 包的构建 - SPEC 基础知识(32562)
 * 4. Spring Boot 数据库连接池 HikariCP(24155)
 * 5. 图解 Git 基本命令 merge 和 rebase(21909)


评论排行榜

 * 1. 将Sublime Text 添加到鼠标右键菜单的教程方法(7)
 * 2. Git入门私房菜(4)
 * 3. Java 诊断工具 Arthas 教程学习笔记(3)
 * 4. 断网环境下利用pip安装Python离线安装包(3)
 * 5. 深入理解JavaScript的变量作用域(3)


推荐排行榜

 * 1. 图解 Git 基本命令 merge 和 rebase(10)
 * 2. 断网环境下利用pip安装Python离线安装包(7)
 * 3. 将Sublime Text 添加到鼠标右键菜单的教程方法(7)
 * 4. RPM 包的构建 - 实例(5)
 * 5. 详尽的 Elasticsearch7.X 安装及集群搭建教程(4)



Copyright © 2024 Michael翔
Powered by .NET 8.0 on Kubernetes & Theme Silence v2.0.2
点击右上角即可分享
CONTENTS
✕
 * 1. 前言
 * 2. HEAD 的理解
 * 3. fast-forward 与 --no-ff 的区别
 * 4. merge 操作
 * 4.1. fast-forward 合并
 * 4.2. no-ff 合并
 * 4.3. 分叉场景的合并
 * 5. rebase 操作
 * 5.1. 变基提交示例
 * 5.2. rebase 总结
 * 6. 补充
 * 7. 一言
 * 8. 参考