【YOU DON'T KNOW GIT】2.Git内部原理-Git对象

225 阅读4分钟

Git对象

Git 最核心、最底层 的部分则是其所实现的一套 对象数据库,其本质是一个基于 Key-Value 的内容寻址文件系统(Content-addressable File System)。但这是什么意思呢? 这意味着,Git 的核心部分是一个简单的键值对数据库。 你可以向该数据库中插入任意类型的内容,它会返回一个唯一的键,通过该键可以在任意时刻再次取回该内容。Git 文件系统中存储了所有文件的所有历史快照,通过索引不同的历史快照,Git 才能够实现版本控制。

可以通过底层命令 git hash-object 来演示上述效果——该命令可将任意数据保存于 .git/objects 目录(即 对象数据库),并返回指向该数据对象的唯一的键值。

首先,我们进入一个新初始化的Git版本库,并确定它的objects目录。 image.png 可以发现,Git 对 objects 目录进行了初始化,并创建了 pack 和 info 子目录,但均为空。

  • 向数据库写入内容,并返回对应键值

接着,我们用 git hash-object 创建一个新的数据对象并将它手动存入你的新 Git 数据库中。 image.png 上图 git hash-object -w --stdin 命令中,-w 选项的意思是将数据对象存储于数据库中,若不指示该选项,则 git hash-object 命令仅仅只会返回所对应的键值,并不会进行存储。 --stdin 选项则指示该命令从标准输入读取内容,若不指定此选项,则须在命令尾部给出待存储文件的路径。

此命令输出一个长度为 40 个字符的校验和。 这是一个 SHA-1 哈希值,根据你文件内容的不同,所返回的都是各不相同的唯一值

由此,我们接触到了第一个Git对象,他的就是刚刚所返回的SHA-1哈希值,他的就是我们的文件内容

  • 查看Git是如何存储数据的

现在,如果你回头再次查看 objects 目录,那么可以在其中找到一个与新内容对应的文件。 image.png 这就是开始时 Git 存储内容的方式:一个文件对应一条内容。校验和的前两个字符用于命名子目录,余下的 38 个字符则用作文件名

  • 根据键值拉取数据

一旦你将内容存储在了对象数据库中,那么可以通过 cat-file 命令从 Git 那里取回数据,为此你需要指定你想查看的数据对象的SHA-1值。 image.png 为 cat-file 指定 -p 选项可指示该命令自动判断内容的类型,并示格式友好的内容。

对一个文件进行简单的版本控制

首先准备一个干净的Git仓库

  • 创建一个新文件并将其内容存入数据库

image.png 查看一下文件内容

image.png

  • 向文件里写入新内容,并再次将其存入数据库

image.png

image.pngdiana.txt文件中写入新内容后,返回的SHA-1哈希值便与之前不同了

  • 再次查看数据库内容

image.png 可以看到,对象数据库记录下了该文件的两个不同版本,并且可以看出Git进行版本控制并不是存放文件之间的差异,而是进行完整存储。

存在的问题

然而,记住文件的每一个版本所对应的 SHA-1 值并不现实;另一个问题是,在这个(简单的版本控制)系统中,文件名并没有被保存——我们仅保存了文件的内容。 上述类型的对象我们称之为Git对象 或 数据对象(blob object) 。 利用 git cat-file -t 命令,可以让 Git 告诉我们其内部存储的任何对象类型,只要给定该对象的 SHA-1 值:

image.png

  • 解决方案:树对象
  • 注意:当前的操作都是在对本地数据库进行操作 不涉及暂存区

【YOU DON'T KNOW GIT】系列

  1. 开始探索Git内部原理
  2. Git内部原理-Git对象(本文)
  3. Git内部原理-树对象
  4. Git内部原理-提交对象

参考资料

1.Pro Git