Git是一个开源的分布式版本控制系统,是目前主流的版本控制系统,很多软件项目都会用它做源代码管理。Git的常用操作想必很多人都会,但是可能了解Git内部原理的人并不多。了解一些底层的东西,可以更好的帮你理清思路,遇到问题的时候也可以更好的去解决。

准备工作

在介绍Git如何存储数据之前,我们先做一些准备工作。

首先新建一个目录git-test,然后在这个目录右键,打开Git Bash,

然后,在Git Bash,分别执行以下命令,

$ git init
$ echo 'a' > a.txt
$ echo 'b' > b.txt
$ git add .

至此,准备工作完成。我们可以看到,git-test目录下现在有一个.git目录,以及两个txt文件(a.txt、b.txt)。

Git如何存储数据

.git目录是git init后在当前目录生成的一个管理git仓库的目录,这里包含所有git操作所需要的东西。其中objects目录下存放所有的git对象。经过上面的操作后,objects目录是这样的,

其中info和pack目录是执行git init以后就已经有的,而78和61目录分别对应着a.txt和b.txt文件,这两个目录是创建了a.txt和b.txt,并执行git add .命令后才生成的。

78目录下有一个文件,查看一下这个文件的内容,执行以下命令,

$ cat .git/objects/78/981922613b2afb6025042ff6bd878ac1994e85

我们看到文件的内容是一串乱码,这是因为Git将信息压缩成二进制。Git提供了一个能够帮助探索objects的命令:git cat-file [-t] [-p], -t可以查看object的类型,-p可以查看object存储的具体内容。分别执行以下命令,

$ git cat-file -t 7898
$ git cat-file -p 7898

blob类型的object

7898就是目录名加上文件名的前两位。可以看到,这个object是一个blob类型的object,而这个object存储的内容,就是我们写入到a.txt的文本。因此,上面的乱码其实就是a.txt的内容,也就是说,这个object存储着a.txt文件的内容。

blob类型的object存储的是一个文件的内容。然后,Git根据这个文件的内容经过SHA1哈希算法得到对应的哈希值(981922613b2afb6025042ff6bd878ac1994e85),作为这个object在Git仓库中的唯一id。现在的Git仓库是这样子的,如图:

tree类型的object

接着执行下一个命令,

$ git commit -m '第一次提交'

执行git commit命令后,objects目录下又多出了两个object,如图:

首先,用git cat-file -t命令查看f4目录下object的类型,如图:

可以看到,这个object的类型是tree,利用git cat-file -p命令查看这个object的内容,如图:

可以看到,tree类型的object存储了一个目录结构的快照,从左到右分别显示了每个文件的权限、类型、object的id(SHA1值)、以及文件名。现在的Git仓库是这样子的,如图:

commit类型的object

用同样的方法,查看3c目录下的文件,如图:

这是一个commit类型的object,而这个object存储了一个tree类型的object的id,以及提交的一些信息。现在的Git仓库是这样子的,如图:

分支

实际做项目都会有很多分支,Git的分支信息就存储在/.git/refs/heads目录下,如图:

因为现在只有一个master分支,所以只有一个master文件。直接打开master这个文件,可以看到这个文件存储了3c0acd6df4df30074678a2b97967a82efd9c8acf这样一串字符串,这正是上面的commit类型object的id。现在的Git仓库是这样子的,如图:

HEAD

在/.git/HEAD这个文件下,记录内容如下:

ref: refs/heads/master

这个内容告诉Git当前修改的内容是基于哪个分支上的,我们可以理解为这是一个指针。现在的Git仓库是这样子的,如图:

至此,一个完整的Git存储结构就出来了。

Git的三个分区

Git有3个分区,分别是工作区、暂存区和版本库。

工作区: 就是项目所在目录(除去.git目录),所有代码编辑都在这上面完成。

暂存区: 英文叫 stage 或 index。一般存放在 .git 目录下的 index 文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。

Git仓库: 由Git object记录着每一次提交的快照,以及链式结构记录的提交变更历史。

有了3个分区,整个结构如下图:

Git的内部运作

现在,我们尝试修改a.txt文件,如图:

这时候,除了工作目录下的a.txt文件内容有变化,暂存区和Git仓库都是没有变化的。接着,执行git add a.txt命令,这时/.git/objects目录下又多了一个对象,如图:

这个新增的object也是blob类型,对应着新修改的a.txt文件。这时,整个结构如下图:

最后,我们执行git commit -m '修改a.txt'命令,不出意外,/.git/objects目录会生成两个object,根据上面的介绍,这两个object分别是tree和commit类型,如图:

这时,整个结构如下图:

从上图可以看到,master分支已经指向新的commit object,并且新的commit object记录着它的parent object,也就是旧的那个commit object,这使得我们可以查看Git的提交历史。

探索Git内部原理的更多相关文章

  1. Git 内部原理--初探 .git

    说到Git大家应该都非常熟悉,几乎每天都会用到它.在日常使用过程中,我们貌似并不需要关注其内部的原理,只需要记住那几个常用的命令,就可以说自己是会Git的人了.可是,事实真的是这样子的吗?今天我们就来 ...

  2. Git详解之九:Git内部原理

    Git 内部原理 不管你是从前面的章节直接跳到了本章,还是读完了其余各章一直到这,你都将在本章见识 Git 的内部工作原理和实现方式.我个人发现学习这些内容对于理解 Git 的用处和强大是非常重要的, ...

  3. git内部原理

    Git 内部原理 无论是从之前的章节直接跳到本章,还是读完了其余章节一直到这——你都将在本章见识到 Git 的内部工作原理 和实现方式. 我们发现学习这部分内容对于理解 Git 的用途和强大至关重要. ...

  4. Git详解之九 Git内部原理

    以下内容转载自:http://www.open-open.com/lib/view/open1328070620202.html Git 内部原理 不管你是从前面的章节直接跳到了本章,还是读完了其余各 ...

  5. git内部原理-第一篇

    本人计划写一些关于<git内部原理>的文章 计划每周一篇

  6. Git 内部原理 - (7)维护与数据恢复 (8) 环境变量 (9)总结

    维护与数据恢复 有的时候,你需要对仓库进行清理 - 使它的结构变得更紧凑,或是对导入的仓库进行清理,或是恢复丢失的内容. 这个小节将会介绍这些情况中的一部分. 维护 Git 会不定时地自动运行一个叫做 ...

  7. Git内部原理(1)

    Git本质上是一套内容寻址文件系统,在此之上提供了VCS的用户界面. Git底层命令(plumbing) vs 高层命令(porcelain) Git的高层命令包括checkout.branch.re ...

  8. Git内部原理探索

    目录 前言 Git分区 .git版本库里的文件/目录是干什么的 Git是如何存储文件信息的 当我们执行git add.git commit时,Git背后做了什么 Git分支的本质是什么 HEAD引用 ...

  9. Git 内部原理 - (1)底层命令和高层命令 (2Git 对象

    文章摘选自git官网,这里复制下来表示我已阅读并学习过一次这些内容: 无论是从之前的章节直接跳到本章,还是读完了其余章节一直到这——你都将在本章见识到 Git 的内部工作原理和实现方式. 我们发现学习 ...

  10. Git内部原理浅析

    Git独特之处 Git是一个分布式版本控制系统,首先分布式意味着Git不仅仅在服务端有远程仓库,同时会在本地也保留一个完整的本地仓库(.git/文件夹),这种分布式让Git拥有下面几个特点: 1.直接 ...

随机推荐

  1. python中--try except 异常捕获以及正则化、替换异常值

    1.异常处理过程 异常名称 描述 BaseException 所有异常的基类 SystemExit 解释器请求退出 KeyboardInterrupt 用户中断执行(通常是输入^C) Exceptio ...

  2. WPF性能优化:形状(Shape)、几何图形(Geometry)和图画(Drawing)的使用

    在用户界面技术中,绘图是一个绕不开的话题.WPF提供了多种可根据应用程序要求进行优化的2D图形和图像的处理功能,包括画刷(Brush).形状(Shape).几何图形(Geometry).图画(Draw ...

  3. docker 安装的jenkins如何执行宿主机的shell启动jar包

    最近在用docker做自动化部署的时候遇到一个问题,就是用docker装的jenkins可以通过映射执行宿主机脚本.但是,却无法通过shell脚本启动宿主机jar包.经排查最终用以下方案完美解决. 一 ...

  4. 小知识:解决EXP-00003的报错

    客户有个需求:某用户程序(含exp导出任务)报错EXP-00003,这个错误并不会影响整个导出任务的结束,但由于是晚上的定时任务,该错误会触发夜间告警.客户想通过数据库层面来规避掉此错误. 事实上,这 ...

  5. ASP.NET Core分布式项目实战(Identity Server 4回顾,Consent 实现思路介绍)--学习笔记

    任务17:Identity Server 4回顾 上一节我们中间留了一部分,登录之后的 RequireConsent,就是用户授权这一步没有做,直接跳过,这种情况可以理解为我们自己比较信任的客户端,这 ...

  6. Power BI 14 DAY

    快消行业销售情况分析 分析目的 帮助经销商优化进.销.存各环节业务流程行为,实现进销存一体化管理,加快资金运转速度,实现销售利润最大化的目的 重要指标 销售类指标 动销次数:在一段期间内产品的销售次数 ...

  7. CF1425F Flamingoes of Mystery 题解

    题目传送门 前置知识 前缀和 & 差分 解法 令 \(sum_k=\sum\limits_{i=1}^{k} a_k\).考虑分别输入 \(sum_2 \sim sum_n\),故可以由于差分 ...

  8. Spring Boot整合Postgres实现轻量级全文搜索

    有这样一个带有搜索功能的用户界面需求: 搜索流程如下所示: 这个需求涉及两个实体: "评分(Rating).用户名(Username)"数据与User实体相关 "创建日期 ...

  9. golang指针和结构体

    指针 指针操作 指针包括指针地址.指针类型和指针取值 &: &符号放在变量前面进行取地址操作 **:*放在变量前面根据地址进行取值 指针地址: func main() { var a ...

  10. ~Keven_He的黑历史~

    "先生,我认为文言文比白话文更加简洁" "请举例" "就好像沉鱼落雁这句成语不是比白话文更加简洁吗" "沉鱼落雁是四个字,该用白话 ...