大家好,今天我们来聊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. element-ui upload上传文件并携带参数 使用formData对象

    需求:上传文件的时候,需要携带其他的参数 问题:使用upload上传文件时,必须使用formData对象,而其他的参数通过data获取的到的,formData和data是不能同时传输的 解决:获取到的 ...

  2. vue +signalR

    概述:ASP.NET Core SignalR是一种开放源代码库,可简化将实时 web 功能添加到应用程序的功能. 实时 web 功能使服务器端代码可以立即将内容推送到客户端. 这玩意的概念我就不多讲 ...

  3. python的快捷键

    常用快捷键 1.Ctrl + Enter:在下方新建行但不移动光标 2.Shift + Enter:在下方新建行并移到新行行首 3.Ctrl + /:注释(取消注释)选择的行 4.Ctrl + Alt ...

  4. linux操作系统网卡漂移导致网络不可用

    1.故障描述 公司有100-150台服务器安装RHEL7.4&中标麒麟7.4系统,为方便编辑配置网卡,使用脚本方式配置为biosname=0,ifname=0,目的是为将en1o2p此类长字符 ...

  5. Metasploit之令牌窃取

    令牌简介及原理 令牌(Token) 就是系统的临时密钥,相当于账户名和密码,用来决定是否允) 许这次请求和判断这次请求是属于哪一个用户的.它允许你在不提供密码或其他凭证的前提下,访问网络和系统资源.这 ...

  6. Python-随机模块-random

    random 生成随机变量 生成 [0, 1) 随机数 .random import random random_number = random.random() print(random_numbe ...

  7. 040 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 02 while循环的执行流程

    040 01 Android 零基础入门 01 Java基础语法 05 Java流程控制之循环结构 02 while循环的执行流程 本文知识点:while循环的执行流程 三种循环结构中的第一种--wh ...

  8. CSP-S 2019 游记,以及AFO

    CSP-S:Day1 195 Day2 84 滚粗,AFO. Day0 和cyl神仙打了一会儿游戏,九点半教了cyl一下LCT,开始写板子题,写到十点半,睡觉. Day1 六点半起床.吃饭.赶赴考场, ...

  9. Xnip Mac上方便好用的截图工具

    Xnip Mac上方便好用的截图工具 标注 Xnip 拥有齐全的标注功能,您可以对截取的图片进行标注,在标注的同时还能重新调整截图大小. 查看标注操作 GIF 滚动截图 Xnip 的滚动截图功能可以让 ...

  10. Oracle 和 MySQL 在显示数据库名和表名的区别

    Oracle 显示数据库名和表名 Oracle 查看表名: select table_name from user_tables; select table_name from dba_tables; ...