GIT科普系列4:仓库/缓冲区/工作副本,傻傻分不清楚?

背景:

公司内部主要以Git作为版本管理工具,在日常工作中发现大家使用Git很不熟练,而且学习的积极性不高,似乎GIT给人以一种望而却步的感觉。究其根源(个人臆测)有几点:

一、以为GIT相较于SVN新颖很多,是很高端高大上的工具,上手很难;
二、习惯于传统的图形化GUI操作(这应该得利于Windows的全球普及),对于GIT的诸多bash指令没有好感,自动降低了学习和掌握的信心;
三、对GIT整体概念不清晰,或盲目背诵指令,或完全依赖于各种图形化Git工具。

鉴于此,博主希望尽可能的从底层机制来讲解GIT的原理,使得大家能够对GIT有一个宏观的认识,进而打消莫名的恐惧,达到熟练使用GIT进行代码版本管理的目的。本文之前GIT科普系列1:git如何放弃本地working directory的修改,以及回滚GIT科普系列2:git代码检出与日常维护GIT科普系列3:底层存储机制Internal Objects三篇已经对GIT的底层机制有了一个简单的介绍,此次作为一个总结篇,借助于图解GIT中的示意图再次介绍几个概念,详情如下。

仓库、缓冲区、工作副本:

同样以系列博文GIT科普系列3:底层存储机制Internal Objects中的整体示意图为例,介绍这三个概念。

《GIT科普系列4:仓库/缓冲区/工作副本,傻傻分不清楚?》

从上图可以看出
工作副本(之所以叫做工作副本是相对于版本仓库而言的,其实就是你本地的工作目录)、
缓冲区(Stage,或者Index)、
仓库(Commit之后)是三个完全独立的存储空间(当然对于GIT管理系统自身而言,这三个区间的内容都以Content-based方式存储在.git目录下,详情参见博文
GIT科普系列3:底层存储机制Internal Objects)。

下面我们就以
仓库
缓冲区
工作副本三个存储空间为基础,详细看一下GIT版本管理的流程,以及常见git指令完成的具体操作。

【备注】:
非特殊说明,下文截图均来自于Visual git guide项目

1. git add

《GIT科普系列4:仓库/缓冲区/工作副本,傻傻分不清楚?》

git add指令是日常使用最多的基础指令(当然如果使用图形化GIT工具的话,可能会很少用到,都会集成到commit指令中。所以我一再强调最好使用Git Bash来完成相关操作)。以
仓库
缓冲区
工作副本三个存储空间为出发点来看,git add指令实现的功能就是将
工作副本中的非.gitignore排除的files
“添加”
备注:这里虽然常常用添加来描述,但是可能最符合语义的应该是“拷贝”,因为git add指令后会在缓冲区存储空间新增一个二进制BLOB文件,也就是通常认为的快照snapshot)到
缓冲区。该指令中支持Bash中常见的通配符,诸如*.jpg、*.txt等,可以快速筛选要添加或过滤不要添加的文件。

2. git commit

《GIT科普系列4:仓库/缓冲区/工作副本,傻傻分不清楚?》

git commit是几乎所有图形化GIT工具最常用的指令。同样以三种存储空间角度出发,git commit就是将
缓冲区的内容“添加”到
仓库中,这里的
“添加”同样具有“拷贝”的含义

上面介绍的git add和git commit指令都是“添加”类指令,也就是如何向GIT的基于内容检索的文件系统(Content-Basd Filesystem)写入数据。有写入就还要有读取,下面看几个读取的指令:

3. git checkout

由于仓库缓冲区工作副本三个存储空间都是以链表的形式来存储记录每一次的改动,因此在读取(上文提到的写入数据也会跟三个存储空间具体所在的不同节点有关,但是总体来说数据写入只要记住一点,都是写入到当前空间对应的当前节点,所以情况比较简单)上需要根据三个存储空间所在的具体节点来进行判别。这也就是git checkout指令复杂的地方,下面分别看几种checkout指令结果图:
指令1:

git checkout HEAD~ files #HEAD~代表HEAD的父节点,即~符号表示指针前向移动

《GIT科普系列4:仓库/缓冲区/工作副本,傻傻分不清楚?》

上图所示此刻实现的功能是将当前HEAD(当前分支处于master,分支名是永远指向一个分支的最后一个节点)指向的父节点中
仓库的files文件
读取并覆盖
缓冲区
工作副本,此刻这两个存储空间中与
仓库中相同的文件内容保持一致,而往往
缓冲区
工作副本两个存储空间的内容会比
仓库多,因为很多还未完成的任务没有提交。

指令2:

git checkout maint #maint代表另一个分支的最后一次提交

《GIT科普系列4:仓库/缓冲区/工作副本,傻傻分不清楚?》

此刻实现的功能是将maint分支最后节点对应的
仓库内的所有文件
读取并覆盖
缓冲区
工作副本

指令3:

git checkout master~3#~代表前向移动,3代表移动的节点数

《GIT科普系列4:仓库/缓冲区/工作副本,傻傻分不清楚?》

同样,此刻实现的功能是将master分支最后节点向前跳跃3个节点对应的
仓库内的所有文件
读取并覆盖
缓冲区
工作副本

【备注1】:上述git checkout指令的三种格式都是实现从仓库“读取并覆盖”缓冲区和工作副本。这里要强调一下“读取并覆盖”。我们以当前态表示缓冲区工作副本中的文件、以下一状态表示所获取的目标仓库的内容来详细讲解“读取并覆盖”的含义,主要分为几种:
– 1)当前状态与下一状态相同的文件:“读取并覆盖”后没有任何变化
– 2)当前状态存在但下一状态不存在的文件:“读取并覆盖”后删除该类文件
– 3)当前状态不存在当下一状态存在的文件:“读取并覆盖”后最新增该类文件

对于第二种情况要额外小心,因为这会导致你本地未提交处于中间状态的文件丢失,工作白白忙活了。
【备注2】:上述指令3会出现一种状态,叫做detached HEAD,言外之意HEAD指针没有指向任何一个分支(即没有指向任何一个链表的最后节点)。此刻如果提交的话会导致此次提交处于不稳定状态,如果不进行进一步操作,GIT管理系统会在下一次启动垃圾回收时刻将该节点删除。详情如下:

《GIT科普系列4:仓库/缓冲区/工作副本,傻傻分不清楚?》

上图在detached HEAD状态下,运行了git commit在git仓库中创建了一个新的编号为2eecb的节点,关联到之前checkout后指向的b325c节点,并以此作为父节点。由上图可以看出,除了HEAD指针指向2eecb节点以外,没有任何分支指向该节点。这就是所谓的detached HEAD状态。(为什么只有HEAD指向某个节点时,会被认为是detached HEAD状态呢?因为HEAD是用来实现多个分支之间跳转的,即多个链表跳转,而不能为某个链表所独有。只有分支才能属于某个链表,而且都制定分支所在链表的最后一个节点)。

此时如果我们执行git checkout master,将HEAD重新移动到master分支时,如下图所示:

《GIT科普系列4:仓库/缓冲区/工作副本,傻傻分不清楚?》

此刻上面新建的2eecb节点就变成了GIT仓库链表的
叶子节点
即该节点没有下一级子节点。对于这种没有被任何分支或者HEAD所指向的叶子节点,GIT垃圾回收会认为该节点无效,因为从理论上来看你是无法再跳转到2eecb节点的(当然直接输入git checkout 2eecb是可以实现这个功能的,谁天天没事记这个是吧?)。

如果你还是希望保留2eecb这个叶子节点,那么要不你就把HEAD指针移过去(但是此刻你就不能再其它分支进行工作了,因为HEAD要永远指向当前工作分支),其实这里HEAD指向2eecb时,可以理解为一个“无名分支”或者“匿名分支”。显然依靠HEAD指针是不合理的,那么只有一种办法,给2eecb叶子节点建立一个分支,即执行git checkout -b new,如下图所示即可。

《GIT科普系列4:仓库/缓冲区/工作副本,傻傻分不清楚?》

此刻2eecb叶子节点有了new分支指向,就不会被GIT垃圾回收给清理掉了,当然你又多了一个分支。

4. git reset

除了git checkout是读取类指令以外,还有一个比较很常用的指令,git reset,同样可以实现“读取并覆盖”的功能。

git reset HEAD~3#这个与git checkout的类似,HEAD是当前分支最新节点,~3表示前向移动3个节点

《GIT科普系列4:仓库/缓冲区/工作副本,傻傻分不清楚?》

如上图所示:git reset相较于git checkout来说更灵活了一些,增加了–soft和–hard两个参数,可以分别控制“读取和覆盖”的工作区间,可同时覆盖
缓冲区
工作副本或只覆盖
缓冲区

【备注】
仔细观察git reset与git checkout的两个读取指令的示意图,你会发现git reset强大的地方不单单在于新增了–soft和–hard参数,而是git reset是同时操作分支和HEAD,而git checkout只操作HEAD——这也就是我们之前提到了GIT实现回滚的底层依据,详情参见博文
GIT科普系列1:git如何放弃本地working directory的修改,以及回滚

总结:

仓库缓冲区工作副本三个独立存储空间为基础,就比较容易理解git的版本管理机制,以及各个指令所实现的功能。在此基础上,再熟背git指令,你就可以自由的、轻松的来管理的文档了。fighting!

作者:zssure@163.com
时间:2016-09-17

    原文作者:zssure
    原文地址: https://blog.csdn.net/zssureqh/article/details/52564305
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞