我使用dulwich做了一些工作,这是 Git 的纯 python 实现。我在这里要说的反映了我对德威 git 实现的经验,而不是规范的 git 源,因此可能存在差异。
Git 非常简单——我的意思是,简单到令人困惑!这个名字真的很适合它的设计,由于它的愚蠢,它非常聪明。
当您提交任何内容时,git 会获取索引(暂存区域)中的内容并创建 SHA 摘要项,因此每个文件都会被 SHAed,每个目录中的文件都会被 SHAed 作为 blob 对象,当然目录结构也会被 SHAed 作为树对象,并且所有这些都绑定到一个也有 SHA 的提交对象中。Git 只是在处理提交时将它们直接触发到 .git/objects 中的文件系统中。如果它成功触发所有这些,它只需将最近提交对象的 SHA 写入 .git/refs/heads/。
有时,提交可能会中途失败。如果某些内容无法写入 .git/objects,则 git 不会在那时进行清理。那是因为通常你会修复问题并重做提交——在这种情况下,git 会从之前停止的地方重新启动,即提交的一半。
这就是 git gc 的用武之地。它只是解析 .git/objects 中的所有对象,标记出所有由 HEAD 或 BRANCH 以某种方式引用的对象。显然剩下的任何东西都是孤立的,与任何“重要”的东西无关,因此可以将其删除。这就是为什么如果您分支,在该分支上做一些工作,但后来放弃该分支并从您的 git 存储库中删除对它的任何引用,运行的定期 git gc 将完全清除您的分支。这可能会让一些老 VCS 用户感到惊讶,例如 CVS 从来没有忘记任何东西,除非它自己崩溃或损坏(这种情况经常发生)。
git repack(实际上是 git-pack-objects)与 git gc 完全不同(例如,一个单独的命令和操作,尽管 git gc 可能会调用 git repack)。正如我之前提到的,git 只是将所有内容都放入它自己的 SHAed 文件中。它会在进入磁盘存储之前对它们进行 gzip 压缩,但从长远来看,这显然不会节省空间。所以 git-pack-objects 所做的是检查一系列 SHA 对象,以查找数据跨修订复制的任何地方。它不关心它是什么类型的 SHA 对象——所有对象都被认为是相同的打包。然后它会生成有意义的二进制增量,并将整个批次作为 .pack 文件存储在 .git/objects/pack 中,从正常目录结构中删除任何打包的对象。
请注意,如果最新的包文件大小小于 1Mb,通常 git-pack-objects 会创建一个新的 .pack 文件而不是替换现有的 .pack 文件。因此,随着时间的推移,您会看到多个 .pack 文件出现在 .git/objects/pack 中。实际上,当您 git fetch 时,您只需要求远程 repo 打包所有未打包的项目并将获取 repo 不需要的 .pack 文件发送到获取 repo。git repack 简单地调用 git-pack-objects 但告诉它合并 .pack 文件,因为它认为合适。这意味着解压缩任何已更改的内容,重新生成二进制增量并重新压缩。
因此,要回答您的问题,总行是指 git repo 中的对象总数。第一个增量数是二进制增量对象的总对象数,即 git 确定有多少对象与其他对象具有很强的相似性并且可以存储为二进制增量。重用的数字表示有多少来自压缩源(即包文件)的对象正在使用而没有被重新压缩以包含最近的更改。当您有多个包文件但更新的 SHA 对象将旧包文件中的项目作为其基础时,会发生这种情况,然后对其应用增量以使其现代化。这让 git 可以利用以前压缩过的旧数据修订版,而无需重新压缩它以包含最近添加的内容。
一般来说,高重用计数表示可以通过完全重新打包(即 git repack -a)回收一些空间,这将始终将重用归零。但是,通常 git 会默默地为您处理所有这些。此外,进行完全重新打包可能会迫使一些 git 提取从头开始重新启动,因为包不同 - 这取决于服务器设置(允许自定义每个客户端包生成在服务器 CPU 上是昂贵的,因此一些主要的 GIT 站点禁用它)。
希望这能回答你的问题。真正使用 git 它是如此简单,您会惊讶于它在开始时完全有效,然后当您将头绕在它周围时,您会被深深地留下深刻印象。只有真正的天才程序员才能写出如此简单却又如此出色的东西,因为他们可以看到大多数程序员只能看到复杂性的简单性。
尼尔