我有意克隆一个特定的存储库,作为自动化系统的一部分来解析提交。我使用的命令是:
git clone https://github.com/google/material-design-icons.git --filter=blob:none --bare --no-tags --single-branch
这对于生成我能实现的最小磁盘克隆以及确保快速克隆非常有效,这两者对我的流程都很重要。
使用以下命令运行 git log
时:
git --no-pager log --max-count=10000 --shortstat -z
git log
似乎在枚举接收对象的提交之间暂停:
remote: Enumerating objects: 8, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 8 (delta 2), reused 8 (delta 2), pack-reused 0
Receiving objects: 100% (8/8), 13.48 MiB | 5.76 MiB/s, done.
Resolving deltas: 100% (2/2), done.
如果我删除 --shortstat
标志,则不会发生这种情况。我试图深入研究文档,但我要么错过了关于为什么 --shortstat
提取对象的内容,要么我缺乏机构知识。上面提到的存储库是我们在处理过程中遇到的少数几个表现出这种行为的存储库之一。我希望能够在拥有精简克隆的同时输出统计信息,而不必在提交之间从远程枚举对象。
最佳答案
您正在通过 --filter=blob:none
参数使用新的(仍在开发中)部分克隆功能。这解释了整个问题。
部分克隆的工作原理是覆盖基本的 Git 假设。 Git 的假设是您始终拥有整个存储库。存储库本身由两个独立的数据库组成:
其中一个保存着 Git 的对象,这些对象是用看似随机(但实际上不是随机)的对象 ID 或 OID 进行编号的。其中一些对象是提交,它们本身非常小,因为它们仅包含提交的元数据。其他对象类型包含实际文件(以及其他在这里不太相关的有用信息)。
另一个数据库保存名称,例如分支和标签名称,将每个名称映射到单个 OID。
在“普通”Git 存储库中,每个名称都映射到对象数据库中实际存在的 OID。该数据库中的提交对象包含附加 OID,用于在对象数据库中定位附加对象。因此,Git 能够提取任何提交的完整快照,而无需借助任何网络访问,因为所有内容都存在于本地数据库中。
然而,在部分克隆中,某些对象丢失了。它们被 Git 所谓的 promise 包 (promisor pack) 所取代。当 Git 需要某些对象并找到这些 promise 包替换之一时,Git 必须调用您最初克隆的存储库并获取丢失的对象。
当使用不带附加参数的 git log 时,Git 只需检查提交元数据。但是,当您添加 --stat
或 --shortstat
或 -p
或许多其他可能的选项之一时,事实证明 Git 将需要当 Git 遍历元数据时,每次提交的(部分或全部)文件。因此 Git 将暂停,如果可能的话收集这些对象,将它们插入到对象数据库中,然后才继续进行下一次提交。
要获取差异信息,包括 --shortstat
样式信息,Git 需要来自两次提交的部分或全部文件。由于树对象的数据格式,Git 实际上只需要那些不同的文件,因此您可以使用比完整克隆所需的更小的 blob 集。但有一个巨大的缺点:Git 一次只能获取几个 blob,并且每次获取都有很大的开销。
您可能会发现,总体而言,克隆整个存储库会更快,这样 git log
就不必再获取任何对象了。考虑使用引用克隆来加速初始克隆过程。 (这可能对磁盘空间没有太大帮助,因为引用克隆将是完整克隆,但如果您避免 --dissociate
,引用克隆本身可以为每个进一步的克隆提供对象,以便您只有一个克隆使用空间,而不是可能有多个克隆。但是,如果没有 --dissociate
,您必须非常小心,确保引用克隆本身保持有效且可访问。)
关于git log pull 对象以获取 Shortstats,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74704938/