Git 知识整理(三)Git 版本及其物理存储

1.1 校验和

Git 中数据在存储前都计算校验和,Git 用于计算校验和的机制叫做 SHA-1 散列(hash,哈希)。这是一个由 40 个十六进制字符组成的字符串,基于 Git 中文件的内容或目录结构计算出来。它看起来就像这样:

955c6ff0f64eaed91a16be52a65a0daa9c4049d3

Git 数据库中保存的信息都是以这个哈希值来索引,而不是文件名。
使用 hash-object 指令来测试下:
在这里插入图片描述

  1. git hash-object 指令是 git 底层指令,用于计算数据对象的校验和。
  2. 可以看出文件修改前和修改后,两次计算的结果是相同的,但是修改前和修改后的校验和发生了变化。

1.2 Git 存储了那些对象?

测试文件结构

|-- test
	 |-- test1.txt
     |-- dir
          |-- test2.txt

将文件提交到版本库后,在 /test/.git/objects 目录下会新增若干两个字符(十六进制字符)的文件夹,打开可以看到里面会有38个字符命名的文件。

有点巧(38 + 2 = 40),好像是校验和?

使用 git cat-file 指令去查看合在一起的校验和,可以看到是以下 3 类对象:

Git 底层指令 git cat-file 从 Git 库中获取文件信息, -t 参数可以查看对象类型, -p 可以查看文件的内容。

1.2.1 数据对象(Blob Objects)

Git 的数据对象可以是任何内容, 是由 Git 生成的文件快照,但需要注意的是文件名并没有被保存,而是以文件的校验和作为文件快照的文件名。

文件在添加到暂存库后,object 目录中就会创建文件的快照。文件的校验和前两个字符用于命名子目录,余下的 38 个字符则用作文件名。
在这里插入图片描述
上图查看了两个文件在版本库中存储的数据对象

  • 4f 开头的数据对象保存着文件 test1.txt 中的内容 “test 1”
  • 81 开头的数据对象保存着文件 test2.txt 中的内容是 “test 2”

1.2.2 树对象(Tree Objects)

因为数据对象(文件快照)不存储文件名和目录信息,所以 Git 使用树对象来保存文件名和目录结构。通常, Git 会根据某一时刻暂存区所表示的状态创建树对象。

  • 树对象可以包含其他的树对象,这样就可以构成一个树形结构,用来保存目录信息
  • 树对象中可以保存文件对应数据对象的索引(校验和),通过它就可以找到此次提交的文件快照。
    在这里插入图片描述如图所示,当前版本库创建了两个树对象(对应根目录和 dir 目录)
  • 91 开头的树对象中包含了:
    66 开头的树对象索引(校验和)
    指向test1.txt 数据对象的索引(校验和)
  • 66 开头的树对象仅包含:
    指向 test2.txt 数据对象的索引(校验和)

1.2.3 提交对象(Commit Objects)

提交对象用来保存本次提交的信息, 包括本次提交对应的树对象索引、提交人、提交时间、以及提交的备注信息等。

在这里插入图片描述
如上图所示,提交对象中保存了 tree 条目, 指向了 91 开头的树对象(与根目录对应)。文件中还保存了提交时的说明信息 --“init”。

1.2.4 总结

在这里插入图片描述通过对比 Git 存储的对象和工作区文件,可以知道:

  1. Git 通过数据对象(blob)存放工作区文件内容快照,并使用校验和来索引数据对象。
  2. Git 通过树对象(tree)保存提交时的工作区目录结构、文件名和文件快照的索引。
  3. Git 通过提交对象(commit)保存提交人、提交时间、提交注释和提交时的根树对象。

1.3 Git 对象如何存储的?

1.3.1 存储结构

Git 是一个内容寻址文件系统, 它的核心部分是一个键值对数据库(key-value data store)。数据对象、树对象和提交对象作为 Value,它们相应的校验和作为 key 存放到版本库中。这些信息就存放在文件系统中 .git/objects 目录下。

1.3.2 存储的过程

Git 的存储对象的过程可以通过下图简单示意:
在这里插入图片描述

初始化

git init 命令执行完成后, 当前目录出现 .git 文件夹, 其中的 objects 目录中只有 info 和 pack 这两个空目录。

添加到暂存区

git add命令将文件添加到暂存区后,会为每个文件计算校验和,然后会把当前版本的文件快照保存到 Git 仓库中。最终将校验和加入暂存区等待提交

提交

git commit 指令进行提时,Git 为每个子目录计算校验和并在 Git 仓库中保存为树对象。随后, Git 会创建一个提交对象,这个对象中除了保存提交信息外, 还包含指向项目根目录树对象的指针。如此一来,通过提交对象就可以在需要时重现本次保存的快照。

1.4 Git 版本

说到这里, Git 的版本由来也就非常清楚了
GIt 的版本就是每次使用 git commit指令提交时,生成的提交对象。通过 git log查看到 Git 的版本号(1c9d77…),正是提交对象的校验和,可以通过它获取提交对象的信息。
在这里插入图片描述

1.4.1 多次提交

在这里插入图片描述后一次提交产生的提交对象会包含指向上次提交对象的指针(parent)。多次提交形成 Git 的版本链。

1.4.2 HEAD 指针

Git 中有很多指令都使用了 HEAD 做为参数, 那么 Head 到底是什么呢?我们通过以下命令查看下。
在这里插入图片描述可以看出,HEAD 的类型也是 commit,说明它也指向一个提交对象,这个提交对象的内容与6269指向的提交对象其实是同一个。
在这里插入图片描述所以,HEAD 就是一个方便记忆和使用的指针,指向本地仓库当前版本。

1.5 总结

  1. Git 使用数据对象、树对象和提交对象和他们计算出来的校验和来存储文件快照、文件目录结构和版本信息(提交)。
  2. 暂存时生成数据对象(文件快照),提交时生成树对象和提交对象。
  3. 提交对象的校验和就是仓库中的版本号,多次提交形成版本链,后一次提交通过 parent 指向上次提交对象。
  4. HEAD 是一个为了方便记忆和使用的指针,指向本地仓库的当前版本(提交对象

本文参考:

git 官方文档 # 10.2 Git 内部原理 - Git 对象

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值