Git的存储原理

打印 上一主题 下一主题

主题 850|帖子 850|积分 2550

目录

Git 设计原理

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

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

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

直觉上讲,似乎基于增量的方式要更好些?
毕竟针对被修改的文件,Git 生成的是完全的快照,而其他体系只是生成增量文件。没错,但是当必要回滚版本或者比对多个版本间的差异时,Git 只必要取出对应版本的快照文件进行对比即可,而基于增量的体系则必要从头开始一步步应用增量文件来回溯,Git 的速度优势就很明显了。
Git 存储模型

.git 目录结构

当用git init 或者 git clone 获取一个 git 仓库时,可以发现目录下有一个隐藏目录。git,它的基本结构类似如下:
  1. ├── COMMIT_EDITMSG 仓库最后一次commit的message
  2. ├── FETCH_HEAD  每个分支的最后一次commit的SHA1值
  3. ├── HEAD 记录了HEAD指针的指向位置
  4. ├── ORIG_HEAD 针对某些危险操作,该指针记录了上一次安全版本的HEAD指针的位置,方便回退
  5. ├── config git的相关配置
  6. ├── index 暂存区,索引文件
  7. ├── packed-refs 已经压缩的分支,记录了每个分支的最后一次commit的SHA1
  8. ├── logs/ 操作日志,包括本地远程的
  9. ├── objects/ 对象存储文件夹
  10. |   ├── ... 文件夹名称根据object的SHA1值的前2个字符确定
  11. |   ├── ...
  12. |   ├── info/
  13. |   ├── pack/ 压缩后的数据
  14. └── refs/ 记录本地和远程的最后一次commit的SHA1值
  15.     ├── heads/ 分支引用
  16.     ├── remotes/ 远程地址
  17.     └── tags/ 标签引用
复制代码
这个目录下包罗了 Git 所有信息,且都是用文件的情势存储,所以说 Git 是一个文件体系。
Git 基本数据对象


  • blob(二进制大对象):也就是前面说的基于快照存储的文件
  • tree:目录,代表了 blob 对象的聚集
  • commit:提交,包罗了 blob、tree 的聚集
  • tag:标签对象(指 annotation 标签),还有一种轻量标签不记录创建标签人等额外信息,不必要再单独创建标签对象
上述 4 种数据对象均存储在。git/object/目录下,git 会对每一种数据对象计算哈希值来确定具体的存储路径,下面来举个例子。
  1. > echo 'test content' | git hash-object -w --stdin
  2. d670460b4b4aece5915caf5c68d12f560a9fe3e4
  3. //40位的SHA-1哈希值,前2位位目录名,其他38位为文件名,存储路径即.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
  4. > git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4
  5. test content
  6. > git cat-file -p master^{tree} // 输出master最新提交包含内容
  7. 100644 blob a906cb2a4a904a152e80877d4088654daad0c859      README  
  8. 100644 blob 8f94139338f9404f26296befa88755fc2598c289      Rakefile  
  9. 040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0      lib
  10. // 包含了2个文件的修改和1个目录的修改
  11. > git cat-file -p 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0
  12. 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 哈希值的文件,非常的轻量,这也是为什么分支/标签的创建、删除速度能这么快的原因。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

忿忿的泥巴坨

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表