git 存储实际提交文件的方式在存储库的生命周期内会有所不同,但让我们从基础开始。
当您将文件提交到存储库时,会生成一个新文件,即该文件的完整副本。 SHA1 是根据其内容计算得出的,这是该文件的“对象 ID”。
你可以在.git\objects\SH\A1-hash下找到这个文件
SH\A1-hash 是我的方式,表示 SHA1 的前两个字符用作文件夹名称,其余 38 个字符用作该目录内的文件名。
然后你修改这个文件,将它添加到索引中,并提交它。
这再次存储为一个全新的文件,索引方式与上述完全相同。
这很容易测试,但请记住,每当您提交更改 1 个文件时,您将获得 3 个 git 对象:
- 文件的新版本
- “树”对象,指示索引中每个文件的哪个版本用于此特定提交
- 提交对象,存储对其父级和树的引用。
所以是的,git 将文件存储为完整的快照。请注意,这些文件是压缩的,因此它们占用的空间不及该文件的两个完整副本,但它们占用的空间与该文件的两个完整压缩副本一样多。
如果要添加的文件不能很好地压缩(想想 jpg、png 或 zip 文件),那么是的,这会占用大量空间。
在某些时候,Git 可能会决定打包您的存储库,并且在这里 Git 可能会决定在此打包文件中使用 delta-compression(压缩并存储文件之间的差异)。然而,Git 的其余部分并没有看到这一点,因为这是对 Git 内部底层文件访问的抽象。各种 Git 命令的实现还是会看到“un-deltified”(如果有这个词的话)文件。
现在,各种命令总是会向您隐藏这一点,因为您使用的大多数 git 命令,如果实施得当,会对您(开发人员)隐藏所有底层抽象和优化,而是专注于你可能想看到什么。
因此,如果您查看这些文件,一些命令将显示差异,其中底层文件没有存储为差异,这仅仅是因为差异对您(开发人员)更有意义。
如果您改为使用管道命令,您将看到更多的 blob。
如果您想了解这一切在实践中的效果,您只需要知道 1 个命令,那就是 git cat-file -p SHA1。
这是一种测试方法:
- 初始化新的存储库
- 添加文件并提交
- 执行
git log并复制提交的SHA1
-
执行git cat-file SHA1-of-commit,你会看到这样的:
tree d7d68c5b2ecc58da225c953e35b0797a4805b844
author Lasse Vågsæther Karlsen <lassevagsaether.karlsen@visma.com> 1491986419 +0200
committer Lasse Vågsæther Karlsen <lassevagsaether.karlsen@visma.com> 1491986419 +0200
First copy
-
现在复制tree之后的SHA1 id,这是树对象的对象id,然后执行git cat-file SHA1-of-tree-object,你会看到这样的:
100644 blob 3b5d02884e6a17f20ed7938bf9e534f1bd0d195e Temp.7z
这告诉您索引包含 1 个文件(1 行),文件名为 Temp.7z,并告诉您它的 SHA1 id。复制此 ID。
- 执行
git cat-file -p SHA1-of-blob,你会看到你添加的文件的内容。
Git 的存储模型一点也不神奇也不复杂,但是里面有很多优化和抽象,避免浪费空间、去重等等。