GIT 数据结构

时间:2024-07-30 19:37:26

GIT 数据结构

Git doesn’t think of or store its data this way. Instead, Git thinks of its data more like a series of snapshots of a miniature filesystem. With Git, every time you commit, or save the state of your project, Git basically takes a picture of what all your files look like at that moment and stores a reference to that snapshot. To be efficient, if files have not changed, Git doesn’t store the file again, just a link to the previous identical file it has already stored. Git thinks about its data more like a stream of snapshots.

Git 更像是把数据看作是对小型文件系统的一组快照。 每次你提交更新,或在 Git 中保存项目状态时,它主要对当时的全部文件制作一个快照并保存这个快照的索引。 为了高效,如果文件没有修改,Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件。 Git 对待数据更像是一个 快照流

git内部commit, tree, blob 三者的关系如下

GIT 数据结构

需要用到的命令:

  • 查看“blob”对象:git show + 对象名(SHA1哈希值)
  • 查看“tree”对象:git show + 对象名 / git ls-tree + 对象名
  • 查看“commit”对象:git show / git log + -s + --pretty=raw +对象名
  • 查看“tag”对象:git cat-file tag v1.5.0

实例:

$ cd D:\playspace\git\git-study
$ git init

在该文件夹下新建三个txt,分别是a.txt ,b.txt, c.txt ,然后文件的内容分别写上 a, b, c

$ git add *

"暂存操作会为每一个文件计算校验和(使用我们在 起步 中提到的 SHA-1 哈希算法),然后会把当前版本的文件快照保存到 Git 仓库中(Git 使用 blob 对象来保存它们),最终将校验和加入到暂存区域等待提交"

引用自 https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%AE%80%E4%BB%8B

$ git commit -m "first commit"

"当使用 git commit 进行提交操作时,Git 会先计算每一个子目录(本例中只有项目根目录)的校验和,然后在 Git 仓库中这些校验和保存为树对象。 随后,Git 便会创建一个提交对象,它除了包含上面提到的那些信息外,还包含指向这个树对象(项目根目录)的指针。如此一来,Git 就可以在需要的时候重现此次保存的快照。"

引用自 https://git-scm.com/book/zh/v2/Git-%E5%88%86%E6%94%AF-%E5%88%86%E6%94%AF%E7%AE%80%E4%BB%8B

$ git log
commit 33c92d3c005e1697725d5b91687a9ce6fa2f93dc
Author: <@qq.com>
Date: Tue May :: +
$ git ls-tree HEAD
blob 2e65efe2a145dda7ee51d1741299f848e5bf752e a.txt
blob 63d8dbd40c23542e740659a7168a0ce3138ea748 b.txt
blob 3410062ba67c5ed59b854387a8bc0ec012479368 c.txt

$ git ls-tree 33c92
blob 2e65efe2a145dda7ee51d1741299f848e5bf752e a.txt
blob 63d8dbd40c23542e740659a7168a0ce3138ea748 b.txt
blob 3410062ba67c5ed59b854387a8bc0ec012479368 c.txt

可见上面git ls-tree 这个命令,是将哈希值为33c92d的这个commit对象对应的tree对象显示了出来,而这个tree对象含有3个blob

假设增加一个文件d.txt,对将其add后提交,然后再来看看git ls-tree HEAD的情况

$ git log
commit ff2151f2f05f0f5fd3d136705ef0112f8520ba43
Author: <@qq.com>
Date: Tue May :: + add d.txt commit 33c92d3c005e1697725d5b91687a9ce6fa2f93dc
Author: <@qq.com>
Date: Tue May :: + first commit $ git ls-tree HEAD
blob 2e65efe2a145dda7ee51d1741299f848e5bf752e a.txt
blob 63d8dbd40c23542e740659a7168a0ce3138ea748 b.txt
blob 3410062ba67c5ed59b854387a8bc0ec012479368 c.txt
blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 d.txt

可见 a.txt, b.txt 和 c.txt 的哈希值在新的tree对象里面并没有发生改变,新的commit对应的tree对象里对于没有修改过的文件,只保存了指针

也可以看出,每个commit对应的版本,也就是快照,是包含了全部的文件的

但是有个疑问,现在一个文件是对应一个blob,如果是一个文件夹呢,是一个blob呢,还是文件夹里每个文件一个blob呢,来试一下,根目录下增加一个文件夹folder1,里面增加两个文件a.txt和b.txt然后提交,然后再看看git ls-tree的结果

$ git ls-tree HEAD
blob 2e65efe2a145dda7ee51d1741299f848e5bf752e a.txt
blob 63d8dbd40c23542e740659a7168a0ce3138ea748 b.txt
blob 3410062ba67c5ed59b854387a8bc0ec012479368 c.txt
blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 d.txt
tree 4e2fd0b481a785eb99cab80ec1c582e1caf6cb44 folder1

看来是一个文件夹对应一个blob

使用git show,可以看到这个文件夹blob包含的内容

git show 4e2fd0b
tree 4e2fd0b a.txt
b.txt

使用git ls-tree来看这个blob,发现这个blob包含了两个blob...

git ls-tree 4e2fd0b
blob 2e65efe2a145dda7ee51d1741299f848e5bf752e a.txt
blob 63d8dbd40c23542e740659a7168a0ce3138ea748 b.txt

看来blob是可以包含blob的,blob既可以是文件夹,也可以是文件