Git 本质是一套内容寻址 (content-addressable) 文件系统, 但由于其将内容哈希成一个 sha 作为索引, 故也称对象存储或键值存储(key-value-store). 原文
现在很多产品都带有历史回退功能, 笔记产品尤为常见, 这也是非常重要的, 特别对于一些文字工作相关的, 经常会写一些东西然后改来改去, 最后发现还是之前的写的好, 这时想回退旧版本, 就必须记录历史.
git 有三类对象 blob, tree, commit, 这三类会以文件形式存储在 git 根目录下 objects 目录中, 每个对象都会有个对应的索引哈希值(sha), 哈希值(sha) 几乎等同于其文件名(前两位为目录, 后面部分为文件名).
文件回退流程:
详细原理分析可读此篇文章: GIT 原理分析
以根 tree 为起点是可以递归获取整个仓库的文件索引信息的, 但每个 tree 都是一个文件, 通过 tree 去获取会不停的读文件, 性能很差. 为此 git 会将整个仓库的文件索引信息单独记录在一个 index 文件中, 每次通过读取 index 文件内容来获取整个仓库的文件记录.
由于 git 通过 index 文件记录仓库的文件信息. 因此当仓库的文件数越多, index 文件大小就越大, git 服务程序越占内存. 同时由于要保证 index 文件正确性, git 服务是没法支持并发写同一个仓库的多个文件. 当并发写多个仓库的文件时, 程序会同时加载多个仓库的 index 文件到内存. 而硬件内容是有限的, 因此 index 文件大小也直接影响到并发写多个仓库的数量. 由此可见仓库文件数过多确实会影响 git 服务的性能.
git 本职功能是代码管理, 若 git 服务仅用于代码管的话, 其性能问题其实还好, 因为没有并发写同一仓库的问题存在. 但是将 git 服务 作为普通的存储服务, 那么并发写同一仓库的可能性会很高(仓库内容越多, 可能性也越高). 也许有人会说 git 不适合此种场景, 本文暂不讨论此说法, 是建立 git 做存储服务上讨论. 解决 git 性能最好的办法便是降低单仓库的文件数, 而作为普通的存储服务关心的是单文件的历史, 并不关心整个仓库的整体的历史. 所以降低单仓库的思路是可行的. 而降低单仓库的文件数又便于管理直接办法便是: 目录即仓库, 将所有目录都初始化为仓库, 同时限制单目录(仓库)的文件数.