内容寻址存储 · content-addressable store
很多人以为 Git 像 SVN 一样存"每次改了什么"(diff)。其实 Git 存的是每次提交的完整快照。
每次 commit,Git 把当时的每个文件存成一个 blob(按内容算 SHA),目录结构存成 tree,再包一层 commit 指向根 tree。没改的文件,新 commit 的 tree 直接指向旧 blob——靠 SHA 复用,不靠 diff 存储。所以 Git 切分支是 O(1)(只加一个指针),合并能自动找共同祖先。
下面是一个小仓库的对象树(commit → tree → blob/tree)。点任意对象,看它的类型、SHA 和内容。
每个对象单独存一个文件,小仓库没问题,大仓库几百万对象就慢了。Git 的解法是 packfile:
这就是为什么 git gc 后仓库变小、clone 变快——它把松散对象压成 packfile。理解对象模型 + packfile,你就懂了 Git 的存储层:日常是松散对象(快),gc 后是 packfile(小),两者自动转换。