implementation of git
commit:
tree
parent # parent tree
author / committer
message
tree: list of:
name # basename of current path
mode: kind-mode + unix-mode (e.g. 100755 -> 100 + 755 -> 可执行文件)
oid -> object id = hash("<type> <完整内容长度>\0" + content)
kind-mode:
100: file
040: dir # where oid refers to another tree object
120: symlink
160: submodule # where oid refers to commit id
tree object 的未压缩内容不是 JSON,而是连续排列的目录项:
<mode> SP <name> NUL <raw object id> <mode> SP <name> NUL <raw object id> ...
obj 除了一个版本保留一个 object 以外
.git/objects/
└─ ab/
└─ cdef123456...
也可以把同类型的一系列 loose object 压缩保存为一个 pack:
.git/
packs/{pack-hash}.pack
packs/{pack-hash}.idx
逻辑对象 物理存储
blob A ─────┬────> loose object file
└────> pack entry / delta entry
两种形式保存的是同一个逻辑对象:
变化的只有物理存储位置和压缩方式。
此外,同一对象可以暂时同时存在于 loose object 和 pack 中;Git 按 OID查找,读取其中任意一份都应得到相同对象。