Git仓库太大clone太慢怎么办?12GB仓库优化到4分12秒,顺便对比SVN/Mercurial/Perforce

🔑 关键词:Git仓库优化,git clone太慢,版本控制工具对比,git sparse checkout,git maintenance

📖 摘要:一个12.4GB游戏前端仓库的真实优化记录:从38分17秒clone降到4分12秒,包含git-sizer、partial clone、sparse checkout、Git LFS、filter-repo、Gitaly参数,以及Git/SVN/Mercurial/Perforce的选型对比。

先交代背景:12.4GB 的 .git,clone 38 分 17 秒

图片

我不是 Git 专家,最多算被仓库折磨过的客户端开发。2023 年 11 月接手一个 UE5 + 4K 贴图项目,.git 目录 12.4GB,内网 git clone 要 38 分 17 秒,CI 冷启动 11 分钟。最开始我以为换台 M2 Pro 就能解决,结果本机只快了两分半,问题不在 CPU,在 packfile、index 和那堆没人清理的二进制历史。 后来我把优化过程拆成 7 步,最后普通开发 clone 4 分 12 秒,CI 冷启动 3 分 08 秒。先别急着争论 monorepo 还是 submodule,先量你的仓库。

第 1 步:先量,别猜

git count-objects -vH
git-sizer --verbose
git rev-list --objects --all | wc -l
du -sh .git/index

我们当时输出:size-pack 9.8 GiB,in-pack 1,237,842 objects,index 312MB。最大 blob 是 Assets/Raw/forest_v3.psd,4.7GB,只在 2019 年提交过一次,后面再没用过。git-sizer 的 maximum blob size 直接把这个文件标红了,max tree entries 也有 8,742。 如果 max blob 超过 100MB,先处理历史,再谈分支模型。这个顺序反了,后面全是白干。

图片

第 2 步:commit-graph、multi-pack-index、maintenance

git commit-graph write --reachable --changed-paths
git multi-pack-index write --bitmap
git config --global core.fsmonitor true
git config --global fetch.parallel 8
git maintenance start

这组命令让 git log -- 某目录从 9.4 秒降到 1.1 秒,git blame 也不至于卡死。changed-paths 很有用,但第一次写 commit-graph 在 1.2M 对象仓库里跑了 6 分 20 秒。别在周五下班前跑。

第 3 步:partial clone + sparse checkout

新同事 clone 改成:

图片

git clone --filter=blob:none --no-checkout git@gitlab.com:team/repo.git
cd repo
git sparse-checkout init --cone
git sparse-checkout set Client/Config Client/Source Docs
git checkout main

只拉需要的 blobs,clone 从 38 分钟到 6 分 40 秒。注意 CI 如果跑全量打包,不能这么干,我们给 CI 单独留了 full clone 的 runner,标签叫 heavy-build。

第 4 步:Git LFS 和大文件

把所有大于 5MB 的 png、psd、uasset 迁到 LFS:

图片

git lfs migrate import --include='*.psd,*.png,*.uasset' --above=5MB
git config --global lfs.concurrenttransfers 8
git config --global lfs.fetchrecentrefsdays 7

LFS 服务器配额 50GB,月流量 300GB,不便宜。迁移要所有人重新 clone,我们停机了 3 小时,还收到 4 个美术的投诉。但 .git 从 12.4GB 降到 8.9GB,clone 时间又少了一截。

第 5 步:清历史,别用 git gc --aggressive 硬刚

我们用了 git filter-repo:

图片

git filter-repo --path Assets/Deprecated --invert-paths --force

这个动作把 .git 从 8.9GB 降到 7.1GB。BFG 也行,但 filter-repo 对多分支更稳。改完历史后所有 commit hash 都变了,旧 PR 链接全废,我们在 Wiki 留了映射表。还有,git gc --aggressive 在 12GB 仓库跑了一夜,packfile 只小了 800MB,CPU 吃了 6 小时。别乱跑,git maintenance 更稳。

第 6 步:服务端和分支策略

GitLab 16.7 的 Gitaly 上我们开了 pack_objects_cache.enabled=true,post_upload_pack 超时 180s,housekeeping 每天 2:30。CI 拉取失败率从 6% 降到 0.8%。客户端再加 pack.threads=8,fetch.parallel=8。 分支从 214 个远程分支砍到 release/、hotfix/、feature/* 三类,feature 合并后自动删。合并窗口改成每天 11:30 和 17:30 两次,冲突从每周 14 个降到 4 个。我的观点:分支模型不是关键,合并频率才是。你就算用 Git Flow,三个月合一次,照样炸。

对比:Git、SVN、Mercurial、Perforce 怎么选

图片

SVN 1.14 我们 2020 年用过,checkout 12GB 要 25 分钟,分支是目录复制,合并没有 Git 灵活,但美术锁 PSD 很舒服。Mercurial 在 Facebook 那种 monorepo 里很强,但国内插件生态和招聘都少。Perforce Helix Core 大文件、文件锁、二进制强,游戏公司大量用,2024 年官网报价大约 240 美元/人/年起,20 人约 4800 美元/年起,具体看 Helix Core 版本和 socket 数。Git 赢在生态,但大文件是硬伤。 全新观点:版本控制选型不是「谁先进」,而是「你的冲突预算是多少」。如果团队每天花 40 分钟在拉取、合入、冲突、LFS 超时上,一年 240 个工作日就是 160 小时,按 150 元/小时算 2.4 万元。这比买工具贵。

最后给一套能抄的排查顺序

git count-objects -vH
git-sizer --verbose
git rev-list --objects --all | wc -l
git commit-graph write --reachable --changed-paths
git multi-pack-index write --bitmap
git config --global core.fsmonitor true
git config --global fetch.parallel 8
git maintenance start

我现在最后悔的是没第一天跑 git-sizer。那个 4.7GB 的 forest_v3.psd 让我们多付了三年 clone 时间。你如果也在被 10GB 以上仓库折磨,先跑上面 4 条体检命令,把数字贴出来,再决定要不要上 LFS、filter-repo 或者换工具。别一上来就重做仓库,很多问题只是 packfile 和 index 太久没维护。

🏷️ 标签: