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> ...

object storage

obj 除了一个版本保留一个 object 以外

.git/objects/
└─ ab/
   └─ cdef123456...

也可以把同类型的一系列 loose object 压缩保存为一个 pack:

.git/
  packs/{pack-hash}.pack
  packs/{pack-hash}.idx

loose object

pack

Loose 与 pack 的关系

逻辑对象             物理存储

blob A ─────┬────> loose object file
            └────> pack entry / delta entry

两种形式保存的是同一个逻辑对象:

变化的只有物理存储位置和压缩方式。

此外,同一对象可以暂时同时存在于 loose object 和 pack 中;Git 按 OID查找,读取其中任意一份都应得到相同对象。

fetch / pull / push