当我在我的 Git 存储库上运行 git gc
或 git repack
时,一旦完成,它会输出一个"总计"行。这些数字意味着什么?
来自一个相当小的存储库的几个示例:
$ git gc
...
Total 576 (delta 315), reused 576 (delta 315)
$ git repack -afd --depth=250 --window=250
...
Total 576 (delta 334), reused 242 (delta 0)
还有一个来自更大的存储库:
$ git gc
...
Total 347629 (delta 289610), reused 342219 (delta 285060)
...
我可以猜到第一个"总数"数字是多少:存储库中 Git 对象(如此提交、树和文件(的数量。所有其他实际上是什么意思?
我已经查看了git-gc(1)
和git-repack(1)
手册页,并仔细阅读了它们的"另请参阅",我在谷歌搜索上的尝试只产生了无关紧要的结果。
我用dulwich做了一些工作,这是一个Git的纯python实现。我在这里要说的反映了我对德威git实现的经验,而不是规范的git源代码,因此可能存在差异。
Git 非常简单 - 我的意思是,如此简单以至于令人困惑!这个名字真的很适合它的设计,因为它的愚蠢而非常聪明。
当你提交任何东西时,git 会获取索引(暂存区(中的内容并创建 SHA 摘要项,因此每个文件都会被 SHAed 并且每个目录中的文件被 SHAed 为 blob 对象,当然目录结构被 SHA 化为树对象,所有这些都被绑定到一个也具有 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 文件中。在进入光盘存储之前,它确实会压缩它们,但从长远来看,这显然不节省空间。因此,git-pack-objects所做的是检查一系列SHA对象,以查找数据跨修订复制的任何位置。它不在乎它是哪种 SHA 对象 - 所有对象都被认为对打包是平等的。然后,它会生成有意义的二进制增量,并将整个批次作为 .pack 文件存储在 .git/objects/pack 中,从正常目录结构中删除任何打包对象。
请注意,如果最新的包文件的大小小于 1Mb,则通常 git-pack-objects 会创建一个新的 .pack 文件,而不是替换现有的 .pack 文件。因此,随着时间的推移,你会看到多个.pack文件出现在.git/objects/pack中。事实上,当你 git fetch 时,你只需要求远程存储库打包所有解压缩的项目,并将获取存储库不需要的 .pack 文件发送到获取存储库。Git repack 只是调用 git-pack-objects,但告诉它按照它认为合适的方式合并 .pack 文件。这意味着解压缩任何已更改的内容,重新生成二进制增量并重新压缩。
因此,为了回答您的问题,总行是指 git 存储库中的对象总数。第一个增量数是二进制增量对象总数的数量,即 git 决定与其他对象有很强相似性并且可以存储为二进制增量的对象数量。重用数字表示有多少来自压缩源(即包文件(的对象正在使用,而没有重新压缩以包含最近的更改。当您有多个包文件,但较新的 SHA 对象引用旧包文件中的项作为其基础,然后对其应用增量以使其现代时,就会发生这种情况。这让 git 可以使用以前压缩的旧数据修订版,而无需重新压缩它以包含更新的添加内容。请注意,git 可能会附加到现有包文件,而无需重写整个包文件。
一般来说,高重用计数表示可以通过完全重新打包(即 git repack -a(来回收一些空间,该重新打包将始终将重用返回为零。但是,通常 git 会默默地为您处理所有这些。此外,执行完全重新打包可能会强制某些 git 获取从头开始,因为包不同 - 这取决于服务器设置(允许自定义每个客户端包生成在服务器 CPU 上很昂贵,因此一些主要的 GIT 站点禁用它(。
希望这能回答您的问题。真的有了 git,它是如此简单,你会惊讶于它在开始时完全有效,然后当你把头缠绕在它周围时,你会留下深刻的印象。只有真正天才的程序员才能写出如此简单但工作如此出色的东西,因为他们可以看到简单性,而大多数程序员只能看到复杂性。
尼尔