部分克隆(--filter=blob:none)让你先拿到完整历史的结构、需要某个文件内容时再按需下载。这篇看它省了多少、留下什么记号、缺失的对象是怎么被悄悄取回的,以及哪些操作会触发大量逐个 fetch。
$ git count-objects -vH | grep -E "^(in-pack|size-pack)"; git config --get uploadpack.allowFilter in-pack: 1200 size-pack: 5.83 MiB true
--filter=blob:none 不下载任何 blob,blob:limit=n 只下载小于 n 的,tree:0 连 tree 也不要。服务端需要 uploadpack.allowFilter=true。
克隆方式 本地对象数 对象库大小 耗时 完整 1,200 5932 KB 89ms --filter=blob:none 900 67 KB 44ms --filter=blob:limit=1k 900 67 KB 44ms --filter=tree:0 300 37 KB 48ms
克隆时 git 把远程标成 promisor(remote.origin.promisor=true,记录过滤规则),拿到的 pack 带 .promisor 文件。对象库里缺失的对象因此“有来处”:需要时可以向它要。git rev-list --objects --missing=print 用 ? 列出缺失的对象。
$ git config --get-regexp "promisor|partialclone|extensions"; ls .git/objects/pack | sed -E "s/pack-[0-9a-f]{40}/pack-<hash>/"
remote.origin.promisor true
remote.origin.partialclonefilter blob:none
pack-<hash>.idx
pack-<hash>.pack
pack-<hash>.promisor
pack-<hash>.rev
$ git rev-list --objects --missing=print HEAD | grep -c "^?"; git rev-list --objects HEAD --missing=allow-any | grep -vc "^?" | sed "s/^ */非缺失对象(commit + tree)的个数: /"
300
非缺失对象(commit + tree)的个数: 900任何需要缺失 blob 的操作(cat-file、checkout、diff、log -p)都会在后台启动 git fetch --filter=blob:none --stdin 把需要的对象取回。用户感觉不到,只是第一次访问慢一点。
访问一个缺失的 blob(git cat-file -s)时的子进程:
git.c:502 trace: built-in: git cat-file -s <sha>
run-command.c:672 trace: run_command: git -c fetch.negotiationAlgorithm=noop fetch origin --no-tags --no-write-fetch-head --recurse-submodules=n
git.c:502 trace: built-in: git fetch origin --no-tags --no-write-fetch-head --recurse-submodules=no --filter=blob:none --stdin
run-command.c:672 trace: run_command: unset GIT_CONFIG_PARAMETERS GIT_PREFIX; GIT_PROTOCOL=version=2 'git-upload-pack '\''/work/l60src'\'''
git.c:502 trace: built-in: git upload-pack /work/l60src
对象数 900 → 901(多了 1 个 blob,下载自 origin)checkout 一次知道需要哪些 blob,批量 fetch(本例 39 个);git log -p 沿着历史一个个访问,每个缺失的 blob 触发一次 fetch(本例 260 次)。批量扫描历史的命令在 partial clone 里可能比完整克隆慢得多。
$ git checkout -q main checkout 之后对象数 940(HEAD 的 40 个文件的 blob 一次性下载) git log -p(历史上全部 300 个 blob 的补丁):触发 260 次后台 fetch;完成后对象数 1200 现在还缺失的对象数: 0
仓库里有很多大文件、历史很长,而你只需要最新版本和结构时,partial clone 能把克隆缩小到约 1%。如果需要全部历史内容,还是完整克隆更省事。