大家好,今天我们来聊git当中一个非常非常重要的特性,就是branch

git branch可以说是git当中最重要的概念了,甚至没有之一。因为git最重要的使用场景就是协同开发,大家一起在一个项目当中开发不同的功能。正是由于有了分支的概念,可以让大家在开发的时候互不影响。如果没有这个功能,git的其他功能做的再好,可能都没有用。

所以某种程度上可以理解为,学git最重要的就是学习分支的相关内容。当然分支的相关内容和命令非常多,我们想要瞬间全部都学会显然不太现实。但对这个概念有一些理解,懂得一些基本命令的用法应该还是做得到的。

在理解分支这个概念之前,我们需要先来介绍一下Git的结构。

Git的结构

branch的英文就是树枝,后来衍生出了分叉、支路等意思。这个单词非常形象,因为git仓库的所有提交节点之间的关系,其实就是一棵树,所以一个分支也可以看成是树上的一条链路。但是这样有一个小问题是,如果说分支是一条链路的话,那么这个链路上的每一个节点代表的是一个commit提交,意味着一份代码快照,有些像是游戏存档。

一个branch上有多个commit,一个游戏也可以有多个存档,但是当下显然只能加载一个。所以git当中用一个指针指向当前加载的commit,也就是说纵向来看一个分支代表的是一连串的提交,但在git当中我们使用的分支其实是一个指针,一个在commit当中切换的指针。

我们来看个例子,比如一开始的时候我们只有默认分支master,它指向当前的一个提交。

现在我们使用git branch test命令创建一个测试分支,执行之后,其实只不过是多了一个指针也指向当前的commit。git当中的结构变成这样:

当我们在test分支上做了改动提交之后,git会产生一个新的提交,并且移动test指针,而master指针会留在原地。

如果我们再回到master也进行了改动和提交之后,又会产生新的节点,并且这个节点会和test的节点区分开,形成新的链路,于是就形成了一棵树的样子。

分支与HEAD指针

怎么分支创建,我们刚才已经讲过了,可以通过git branch加上我们想要的分支名来完成。使用了这个命令之后,git内部会创建一个新的指针指向当前的commit。

有一个问题是git怎么知道我们当前的代码在哪里呢?即使知道了代码在哪个分支上,又怎么确定在哪一个节点呢?其实git内部还有一个特殊的指针叫做HEAD,它指向的是当前代码仓库的位置。当我们提交代码的时候,不止只有分支的这些指针会往前移动,HEAD指针也会随着移动。

其实HEAD指针不仅可以往前移动,还可以移动到任意节点上,哪怕不再当前的分支上也可以。移动HEAD指针需要用到git checkout命令,它可以指定HEAD指针移动到其他位置。既可以是某一个分支,也可以是根据commit id来确定的节点。

比如我们当前在master分支,我们要切换到test分支上,我们只需要运行:

git checkout master

另外,使用git checkout命令加上参数-b,我们还可以创建分支。比如假如当前test分支不存在,我们可以通过git checkout -b test来创建,并且还会自动切换到新建出的test分支上。

我们在新的分支上做了提交之后,可以通过git log --oneline --decorate命令来查看每一个分支所指向的位置。这里的oneline是将log压缩到一行展示,decorate用来查看分支所指向的位置。

我们可以发现test和master分支指向的提交不同,并且当前我们的HEAD在test上,说明我们当前在test分支。我们前面说了git checkout命令可以改变HEAD指针指向的位置,假如我们在当前目录下执行git checkout 18a417,这个18a417对应的是add article 6这个提交。这个提交是在master分支的,是test分支的上游,我们使用命令会自动将HEAD跳转到master分支。

使用之后我们发现的确到了master分支,这里由于我配置了zsh工具,它会提示我当前所处的位置是比master分支指向的最新位置落后3个提交。

这也验证了我们说的,HEAD指针可以随意跳转。现在想必你们应该能理解上一篇文章当中介绍的,撤销当前分支的命令git reset HEAD^的含义了,HEAD指的就是HEAD指针,^表示的上一个提交。如果是前多个提交,我们可以用~加数字的形式来表示。比如上图当中划了红线标注的master~3,就表示master节点上3个提交。

分支合并

最后来简单说说分支合并,我们在使用git进行协同开发的过程当中,虽然大家都在各自的分支。但是最后代码还是要合并到一起的,这样才可以投入使用。git当中代码的合并是通过分支合并来体现的。

比如当前的这一篇文章被我加在了test分支当中,这显然是不行的,因为使用方不可能一一去理解每一个分支做了什么,当中的代码逻辑。所以大多数的分支只是暂时的,用来暂时完成一项功能的,等功能完成之后,一般都会再合并回master分支,将所有的改动合并进去。

合并的方式非常简单,我们只需要先checkout我们想要合并的目标分支。比如我们要合并到master,就checkout到master。然后使用git merge test命令,表示和test这个分支合并。

合并之后,如果没有报错就算是合并成功了。它会展示出来合并进来的代码改动,我们注意到日志里有一个fast-forward这个单词,它表示快速合并。快速合并的意思也很简单,因为我们test分支是从master分支当中切出去的。后来master分支就再也没有进行过改动,那么当我们合并的时候,其实只需要移动一下master指针,将它移动到test分支上即可。

我们用图来展示,合并前:

合并后:

那如果我们在master分支上也有改动,不再是待合并分支的直接上游,会发生什么呢?

上图当中我们做了一系列操作,首先我们创建了一个叫做test_merge的分支,在其中创建了一个文件叫做a.txt,接着我们切回master分支创建了b.txt。最后我们把两个分支合并。

合并当然也没有问题,但是我们来用git log来查看一下日志:

会发现日志里多了一个commit,这个commit并不是我提交的,而是它自动产生的。我们一样用图来展示一下,这是合并前:

合并之后:

由于不再拥有直接上下游关系了,所以git创建了一个新的commit用来合并两个分支的代码。当我们合并完成之后,我们就可以把没用的分支都删除了。删除的命令是git branch -d test。

当然git merge的时候并不是永远都一帆风顺的,难免会遇到冲突。所谓的冲突也就是两个人修改了同一份代码,git会不知道应该保留哪一个,于是提示冲突,让程序员自己搞定。关于git merge时遇到冲突怎么办的问题,我们放到下一篇文章当中和大家分享。

今天的文章就到这里,衷心祝愿大家每天都有所收获。如果还喜欢今天的内容的话,请来一个三连支持吧~(点赞、关注、转发

原文链接,求个关注

本文使用 mdnice 排版

- END -

图解git,用手绘图带你理解git中分支的原理和应用的更多相关文章

  1. Git复习(九)之理解git工作区和暂存区

    前言 Git和其他版本控制系统如SVN的一个不同之处就是有暂存区的概念. 版本库 在工作区目录中有一个.git文件,这个其实不是工作区而是Git的版本库 版本库中包含两个部分,一个是暂存区index/ ...

  2. 从底层带你理解Python中的一些内部机制

    下面博文将带你创建一个字节码级别的追踪API以追踪Python的一些内部机制,比如类似YIELDVALUE.YIELDFROM操作码的实现,推式构造列表(List Comprehensions).生成 ...

  3. 一文带你理解TDengine中的缓存技术

    作者 | 王明明,涛思数据软件工程师 小 T 导读:在计算机系统中,缓存是一种常用的技术,既有硬件缓存,比如我们经常听到的 CPU L2 高速缓存,也有软件缓存,比如很多系统里把 Redis 当做数据 ...

  4. 【SpringBoot】 理解Spirng中的IOC原理

    前言 前文已经介绍了Spring Bean的生命周期,在这个周期内有一个重要的概念就是: IOC容器 大家也知道IOC是Sping 的重要核心之一,那么如何理解它呢,它又是产生什么作用呢?本文就IOC ...

  5. 深入理解JDK中的Reference原理和源码实现

    前提 这篇文章主要基于JDK11的源码和最近翻看的<深入理解Java虚拟机-2nd>一书的部分内容,对JDK11中的Reference(引用)做一些总结.值得注意的是,通过笔者对比一下JD ...

  6. 深入理解spring中的AOP原理 —— 实现MethodInterceptor接口,自已动手写一个AOP

      1.前言 AOP是面向切面编程,即“Aspect Oriented Programming”的缩写.面对切面,就是面向我们的关注面,不能让非关注面影响到我们的关注面.而现实中非关切面又必不可少,例 ...

  7. 深入理解Mybatis中sqlSessionFactory机制原理

    对于任何框架而言,在使用前都要进行一系列的初始化,MyBatis也不例外.本章将通过以下几点详细介绍MyBatis的初始化过程. 1.MyBatis的初始化做了什么 2. MyBatis基于XML配置 ...

  8. 理解Git的工作流程(转)

    英文原文:Understanding the Git Workflow 如果你不理解Git的设计动机,那你就会处处碰壁.知道足够多的命令和参数后,你就会强行让Git按你想的来工作,而不是按Git自己的 ...

  9. 深入理解Git - 一切皆commit

    在对 git 有了基本理解和知道常规操作之后,如何对 git 的使用有进一步的理解? 一切皆 commit 或许是个不错的理解思路. 本文将从『一切皆 commit 』的角度,通过 git 中常见的名 ...

随机推荐

  1. 【答疑解惑】为什么你的 Charles 会抓包失败?

    作为一名 Web 开发工程师,天天都会和网络打交道.Charles 作为一款网络抓包工具,几乎成了 Web 开发的标配. 本文是我深度使用 Charles 后总结而成,不同于其它介绍 Charles ...

  2. 【转】Locust 性能测试-小案例(1)-环境搭建

    说在前面的话:从这节课开始,将讲解Locust作为一款测试工具,要怎么去应用.首先是"小案例"的系列文章,主要是给大家讲解locustfile也就是场景模拟的一些模式和方法.等到& ...

  3. 喜大普奔!GitHub中文版帮助文档上线了!

    日前,GitHub 文档的简体中文正式发布,开发者可以到官方文档上随意查阅浏览中文文档啦!   对于想要玩 GitHub,但一直苦于英语水平较差的程序员来说,这真是一个天大的好消息.下面一起来感受一下 ...

  4. Java Web学习(一)Web基础

    文章更新时间:2020/07/24 一.基本概念 web资源 Internet上供外界访问的Web资源分为两种: 静态web资源(如html 页面):指web页面中供人们浏览的数据始终是不变. 动态w ...

  5. Git的使用--码云

    Git的使用--码云 进入码云官网:https://gitee.com/ 注册or登录账号进入gitee页面(页面结构大同小异). 点击右上角加号--新建仓库,用于存放项目代码 创建项目需要注意的选项 ...

  6. 结合 Shell 对 Koa 应用运行环境检查

    在开发环境中,启动一个koa 应用服务,通常还需要同时启动数据库.比如.Mongodb.mysql 等 如果一直开着数据库服务,在不使用的话,电脑会占一定的性能.然而如果每次手动去启动服务,效率又不高 ...

  7. Python_快速安装第三方库-pip

    如何快速安装第三方库? 通过python 豆瓣园源https://pypi.douban.com/simple/进行安装,利用国内网速 如何安装? pip -i install https://pyp ...

  8. Python-装饰器中保留被装饰函数元数据

     函数的元数据包括哪些呢? 1. 函数名 .__name__ 2. 函数注释 .__doc__ ... 那,如何保留被装饰函数元数据,通过wraps装饰器保留被装饰函数的元数据 import time ...

  9. 搭建实用深度学习环境(Ubuntu16.10+Theano0.8.2+Tensorflow0.11.0rc1+Keras1.1.0)

    在动手安装之前,首先要确定硬件,系统,准备安装软件的版本,确定这些软硬件之间是否相互支持或兼容.本文安装的主要环境和软件如下: Ubuntu16.10+CUDA8.0(cudnn5.1,CNMEM)+ ...

  10. 转C++了

    积极响应"某王"的号召,联赛之后转C辣!(好吧,其实是它拿着一把西瓜刀顶在我背后逼我转的)