Git 设计原理

概括的讲,Git 就是一个基于快照的内容寻址文件系统。 往下慢慢看。

Git vs SVN

Git 出现前,主流版本控制系统(SVN...)一般为基于增量(delta-based)的系统,如下图:

Git 则是基于快照(snapshot),即针对每一个被修改的文件生成一个快照,没被修改的则不再重新生成快照,如下图:

直觉上讲,似乎基于增量的方式要更好些?

毕竟针对被修改的文件,Git 生成的是完全的快照,而其他系统只是生成增量文件。没错,但是当需要回滚版本或者比对多个版本间的差异时,Git 只需要取出对应版本的快照文件进行对比即可,而基于增量的系统则需要从头开始一步步应用增量文件来回溯,Git 的速度优势就很明显了。

Git 存储模型

.git 目录结构

当用git init 或者 git clone 获取一个 git 仓库时,可以发现目录下有一个隐藏目录。git,它的基本结构类似如下:

├── COMMIT_EDITMSG 仓库最后一次commit的message
├── FETCH_HEAD 每个分支的最后一次commit的SHA1值
├── HEAD 记录了HEAD指针的指向位置
├── ORIG_HEAD 针对某些危险操作,该指针记录了上一次安全版本的HEAD指针的位置,方便回退
├── config git的相关配置
├── index 暂存区,索引文件
├── packed-refs 已经压缩的分支,记录了每个分支的最后一次commit的SHA1
├── logs/ 操作日志,包括本地远程的
├── objects/ 对象存储文件夹
| ├── ... 文件夹名称根据object的SHA1值的前2个字符确定
| ├── ...
| ├── info/
| ├── pack/ 压缩后的数据
└── refs/ 记录本地和远程的最后一次commit的SHA1值
├── heads/ 分支引用
├── remotes/ 远程地址
└── tags/ 标签引用

这个目录下包含了 Git 所有信息,且都是用文件的形式存储,所以说 Git 是一个文件系统。

Git 基本数据对象

  • blob(二进制大对象):也就是前面说的基于快照存储的文件
  • tree:目录,代表了 blob 对象的集合
  • commit:提交,包含了 blob、tree 的集合
  • tag:标签对象(指 annotation 标签),还有一种轻量标签不记录创建标签人等额外信息,不需要再单独创建标签对象

上述 4 种数据对象均存储在。git/object/目录下,git 会对每一种数据对象计算哈希值来确定具体的存储路径,下面来举个例子。

> echo 'test content' | git hash-object -w --stdin
d670460b4b4aece5915caf5c68d12f560a9fe3e4
//40位的SHA-1哈希值,前2位位目录名,其他38位为文件名,存储路径即.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
> git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4
test content
> git cat-file -p master^{tree} // 输出master最新提交包含内容
100644 blob a906cb2a4a904a152e80877d4088654daad0c859 README
100644 blob 8f94139338f9404f26296befa88755fc2598c289 Rakefile
040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 lib
// 包含了2个文件的修改和1个目录的修改
> git cat-file -p 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0
100644 blob 47c6340d6459e05787f644c2447d2595f5d3a54b simplegit.rb

git hash-object 命令可以用于计算文件的哈希值

-w 表示把将对象写入到 git 数据库中

--stdin 表示从标准输入读取内容

git cat-file 命令可以根据传入哈希值取出 git 存储的对象

-p 自动判断内容的类型

一次提交的数据结构可以用下图来概括:

Git 包文件

可能有的小伙伴通过上述方式在自己项目中尝试时,发现在。git/objects/下找不到对应文件,这是什么原因呢?

可能真的不是操作出了问题,而是 Git 进行了压缩操作。

Git 最初存储对象时使用的时"松散(loose)"对象格式,即保存在。git/objects/下。

但是,Git 会时不时(或者当你手动执行git gc 命令后)地将这些对象打包成一个称为“包文件(packfile)”的二进制文件(存储在。git/objects/pack),以节省空间和提高效率。

Git 引用

引用类似于指针,除了 HEAD 存储在。git/HEAD 以外,其他指针存储在。git/refs 目录下

  • 分支
  • HEAD:一种特殊的指针,用于指向目前所在的 commit,。git/HEAD 文件里存储的就是引用的 commit 的哈希值
  • 标签(轻量标签)

可以看出,所谓的引用只是一个记录了 commit 哈希值的文件,非常的轻量,这也是为什么分支/标签的创建、删除速度能这么快的原因。

Git的存储原理的更多相关文章

  1. [转帖]Git数据存储的原理浅析

    Git数据存储的原理浅析 https://segmentfault.com/a/1190000016320008   写作背景 进来在闲暇的时间里在看一些关系P2P网络的拓扑发现的内容,重点关注了Ma ...

  2. 深入理解Git的实现原理

      0.导读   本文适合对git有过接触,但知其然不知其所以然的小伙伴,也适合想要学习git的初学者,通过这篇文章,能让大家对git有豁然开朗的感觉.在写作过程中,我力求通俗易懂,深入浅出,不堆砌概 ...

  3. GIT的工作原理和基本命令

    1.GIT的工作原理 工作区:我们写代码的地方. 暂存区:临时存储用的. 历史区:生成历史版本的地方. 提交流程:工作区->暂存区->历史区 图示: 2.GIT的全局配置 3.创建仓库完成 ...

  4. 代码管理工具 --- git的学习笔记二《git的工作原理》

    通过几个问题来学习代码管理工具之git 一.git是什么?为什么要用它?使用它的好处?它与svn的区别,在Mac上,比较好用的git图形界面客户端有 git 是分布式的代码管理工具,使用它是因为,它便 ...

  5. Atitit.git的存储结构and 追踪

    Atitit.git的存储结构and 追踪 1. Add index.js 2 index1 1.1. new1 1.2. Modify1 2. Commit1 1. Add index.js 2 i ...

  6. git对象存储

    之前提到当存储数据内容时,会在objects文件夹下存储一个git对象.我们花些时间来看看 Git 是如何存储对象的.你将看来如何通过 Ruby 脚本语言存储一个 blob 对象 ,有必要了解一下对象 ...

  7. HashMap的存储原理

    HashMap是java中相当重要的数据结构,使用HashMap的场景非常之多,因此,了解HashMap实现的过程和原理,是非常有必要的,在一些面试中也会经常被问到.好了,我们赶紧来研究java内部是 ...

  8. Hadoop(六)之HDFS的存储原理(运行原理)

    前言 其实说到HDFS的存储原理,无非就是读操作和写操作,那接下来我们详细的看一下HDFS是怎么实现读写操作的! 一.HDFS读取过程 1)客户端通过调用FileSystem对象的open()来读取希 ...

  9. HBase底层存储原理

    HBase底层存储原理——我靠,和cassandra本质上没有区别啊!都是kv 列存储,只是一个是p2p另一个是集中式而已! 首先HBase不同于一般的关系数据库, 它是一个适合于非结构化数据存储的数 ...

  10. flash存储原理

    norflash 带有 SRAM接口,有足够的地址引脚来寻址,可以很容易地存取其内容每一字节:nandflash器件使用复杂的IO口串行的存取数据,读写操作采用512字节的块(也就是读/写某个字节,必 ...

随机推荐

  1. Spring Security 初学

    Spring Security 初学 声明:本篇文章无源码解析,属于初学范围,本文采用SpringBoot+thymeleaf的项目. 实现 SpringSecurity 分三步走 继承 WebSec ...

  2. C#笔记 picturebox功能实现(滚动放大,拖动)

    代码链接 1. picturebox上的坐标与原图中坐标的转换 (1) 由于图片的长宽比例和picturebox的长宽比例不同,所以图片不想拉伸的话,左右或者上下会有留白.将picturebox的si ...

  3. 算法金 | Python 中有没有所谓的 main 函数?为什么?

    ​大侠幸会,在下全网同名[算法金] 0 基础转 AI 上岸,多个算法赛 Top [日更万日,让更多人享受智能乐趣] 定义和背景 在讨论Python为何没有像C或Java那样的明确的main函数之前,让 ...

  4. 一周万星的文本转语音开源项目「GitHub 热点速览」

    上周的热门开源项目让我想起了「图灵测试」,测试者在不知道对面是机器还是人类的前提下随意提问,最后根据对方回复的内容,判断与他们交谈的是人还是计算机.如果无法分辨出回答者是机器还是人类,则说明机器已通过 ...

  5. INFINI Labs 产品更新 | Easysearch 新增分词插件、Gateway 支持邮件发送等功能

    INFINI Labs 产品又更新啦~,本次更新概要如下:Easysearch 新增了分词插件.优化了生命周期管理功能等:Gateway 新增 smtp 过滤器来支持邮件的发送,支持自动跳过因为异常关 ...

  6. Ubuntu 更改鼠标滚轮速度

    1.安装imwheel sudo apt-get install imwheel 2.更改配置 sudo gedit ~/.imwheelrc 输入以下内容: ".*"None,  ...

  7. Java连接mySql——简单JDBC连接数据库

    利用JDBC开发数据库 经典应该用框架:      第一步,加载JDBC数据库驱动程序(不同的数据库有不同的数据库驱动,所以在连接数据库之前,需加载驱动)     格式:     String dri ...

  8. 阿里也出手了!Spring CloudAlibaba AI问世了

    写在前面 在之前的文章中我们有介绍过SpringAI这个项目.SpringAI 是Spring 官方社区项目,旨在简化 Java AI 应用程序开发, 让 Java 开发者想使用 Spring 开发普 ...

  9. Woothosting 6$/年 vps测评

    当你看到这个提示的时候,说明当前的文章是由原emlog博客系统搬迁至此的,文章发布时间已过于久远,编排和内容不一定完整,还请谅解 Woothosting 6$/年 vps测评** 日期:2018-7- ...

  10. c++引用(REFERENCES)

    一个例子 void add(int value) { value++; } int main() { int a = 5; LOG(a); add(a); LOG( a); } 在这种情况下,变量a在 ...