Git内部原理 - 1

Git 内部

Git是什么呢?不言而喻,官方回答git是分布式软件管理系统, 如果我们往从计算机学科这些想想,
我觉得,git首先是一个本地数据库, 再者,git实现了客户端和远程通信数据交互的功能

数据库能力

想想关系型数据库, 首先提供了对原始数据管理的存储,管理能力,接着通过表,键,链接等等这些关系,
实现了数据直接的联系,从而能较完整描述一个系统。

git实现的是对文件系统的管理,提供了类似快照的功能,通过commit能够保留历史信息

blog对象

咱们从底下往上看,比如对于一个文件file.txt, git里面是blob类型对象
git 底层命令是hash-object, 具体细节可以 git hash-object --help查看

// 计算文件blob 哈希值
content_size = len(file.txt) // file.txt字节数
store = "blob " + content_size + "\u0000" + content(file.txt) //拼接办法
sha1 = sha1(store) // 计算sha1
// zlib压缩文件, 字节流
bytes = zlib.deflate(store)
// 通过底层操作系统, 写入
写入到 .git/objects/' + sha1[0,2] + '/' + sha1[2,38] 文件里面

tree对象

通过这样,文件或者文件夹这些数据信息已经可以存储管理了,但是要解决的下一个问题
文件名,还有文件是怎么组织管理? git提供了 tree对象
tree对象对应UNIX中的目录项
一个tree对象包含了一条或多条tree对象记录(tree entry),每条记录含有一个指向blob对象或者子tree对象的 SHA-1 指针,以及相应的模式、类型、文件名信息
底层命令对应的是write-tree/read-tree命令
类似于

image.png

commit对象

解决了上述问题,我们进一步看,git 提供的快照功能, 依据commit id可以检出指定的一次完整内容
git 用commit对象 来解决, commit对象类似于一个指针,当我们执行git commit命令时候,
生成一个 commit 对象,指向当时tree对象,如图

image.png

底层命令对应的是 commit-tree,通过指定 tree对象 来创建, 也可以附加commit id的父id

屏幕快照 2019-09-27 14.38.33.png

举个例子, 比如master分支 merge feature分支后, 那么, 此时提交后,新生成的commit id(a46163aed00be6700365112ffc5eb4aef2f14dc8)的父id就是master分支最近一次的commit id(397f07151338bff5e7245da35fc41d77f2fe74ff)以及Feature分支的最近一次提交commit id(9424805c3643cf052f0c87221e7a9255bd804ded)
屏幕快照 2019-09-27 14.52.03.png

屏幕快照 2019-09-27 14.54.48.png

引用 - 分支, tag

进行到这里,其实这个数据库已经完全可以使用了,通过指定"id(commit id)", 我们已经可以准确找到一次完成的信息记录,但实际,我们可以再进一步,对人使用更友好一点
比如我们记不住ip但是可以记住域名, 我们记不住commit id, 我们可以记住分支信息
git 里面有一种引用,我们叫做分支, 它指向一次自己分支的最近一次commit 信息.
如图

image.png

显然分支指向的commit是随着 提交实时更新的,这个引用是会改变的,不变的有没有,当然有
那就是tag, tag也是一种引用,不过,这个引用总是执行一个固定的commit.

.git目录分析

到这里, 我们其实把git底层是怎么运转已经弄清楚了, 反应到系统目录上,我们可以看到如下组织:
git判断是不是一个git管理空间,判断的也就是有没有 .git

屏幕快照 2019-09-27 15.13.05.png

  • objects - 所有数据, 没压缩的直接在hash开头目录,处理后的文件在pack
  • refs - 引用, 包括head,tag,origin, 分支和commit id类似于 key-value
  • head - 目前被检出的分支
  • index - 文件保存暂存区信息
  • config - 是项目的配置选项, 比如origin是什么, git便捷命令这些
  • info - 全局排除,不希望被记录在 .gitignore 文件中的忽略模式
  • hoos - 服务端或者客户端钩子脚本

本地和远程的数据交换,其实涉及也挺多,可以放到下一部分来说了

你可能感兴趣的:(Git内部原理 - 1)