Git大项目实践:Monorepo管理、LFS使用、稀疏检出、浅克隆

说实话,很多团队一开始用Git都挺开心的。代码量不大,仓库清爽,分支切换丝滑。但项目一膨胀,问题就来了——克隆慢得像下载电影,.git目录比源码还大,随便一个git status都要等好几秒。

我经历过一个项目,前端、后端、移动端、文档全塞在一个仓库里。第一次克隆花了40分钟,同事直接崩溃。后来我们不得不拆分仓库,但拆分后又带来了版本对齐的噩梦。嗯,这就是我们今天要聊的话题——大项目怎么用Git管好。

Monorepo:一个大仓库还是多个小仓库?

Monorepo,说白了就是把多个项目放在同一个Git仓库里。Google、微软、Uber都在用。我刚开始觉得这反人类,后来真香了。

Monorepo的好处很明显:

  • 代码共享方便,不用发npm包
  • 原子提交,一个改动跨多个模块
  • 统一构建和CI流程
  • 重构时跨项目改代码很轻松

但坑也不少:

  • 仓库体积爆炸
  • 克隆时间感人
  • 权限控制困难
  • Git操作变慢

我建议中小团队用Monorepo,但要做好配套。比如用pnpm workspacesturborepo来管理依赖,用changesets来管理版本。Git本身只是载体,真正的管理工具在Git之上。

核心原则:Monorepo不是把代码堆在一起就完事了。你需要工具链来支撑。没有工具链的Monorepo,就是给自己挖坑。

Git LFS:大文件别往Git里塞

Git设计出来是管文本的。二进制文件?它真的不擅长。你想想看,一个100MB的PSD文件,每次改一点点,Git都会存一份完整副本。仓库不爆炸才怪。

Git LFS(Large File Storage)就是干这个的。它把大文件替换成指针文件,真正的文件内容存到远程服务器上。

安装和使用:

# 安装LFS
git lfs install

# 指定哪些文件用LFS管理
git lfs track "*.psd"
git lfs track "*.zip"
git lfs track "*.mp4"

# 提交.trackattributes文件
git add .gitattributes
git commit -m "配置LFS跟踪规则"

# 正常使用,LFS自动处理
git add design.psd
git commit -m "添加设计稿"
git push

我在项目中遇到过最坑的事:有人把node_modules提交到了LFS。嗯,你没看错。LFS是按流量收费的,node_modules动不动几百MB,一次push就烧掉几块钱。后来我们加了CI检查,禁止LFS跟踪node_modules目录。

避坑指南:我曾经因为忘记配置.gitignore,把编译产物也推到了LFS。结果团队成员每次拉取都要下载几百MB的二进制文件。记住:LFS只适合管理不常变但体积大的文件,比如设计稿、音视频、数据集。频繁变动的文件不要用LFS。

稀疏检出:我只想要一部分代码

Monorepo里可能有几十个模块,但你只负责其中一个。每次克隆整个仓库?太浪费了。稀疏检出(Sparse Checkout)就是解决这个问题的。

操作步骤:

# 方式一:克隆时直接稀疏
git clone --filter=blob:none --sparse https://github.com/example/monorepo.git
cd monorepo

# 设置要检出的目录
git sparse-checkout set packages/frontend packages/shared

# 方式二:已有仓库启用稀疏
git sparse-checkout init --cone
git sparse-checkout set packages/frontend

# 添加更多目录
git sparse-checkout add packages/docs

# 查看当前稀疏配置
git sparse-checkout list

我个人习惯用--cone模式。它只检出顶层文件和指定目录,性能最好。如果你需要更细粒度的控制,可以用非cone模式,但说实话,大部分场景cone模式就够了。

小技巧:稀疏检出配合--filter=blob:none使用效果更佳。前者控制工作目录,后者控制Git对象下载。两者结合,克隆一个大型Monorepo可以从40分钟降到2分钟。

浅克隆:只要最近的历史

有时候你根本不需要完整的历史。比如CI环境,只需要最新代码来跑测试。或者你只是想看看项目长什么样。这时候浅克隆(Shallow Clone)就派上用场了。

常用方式:

# 只克隆最近1次提交
git clone --depth 1 https://github.com/example/big-project.git

# 克隆最近5次提交
git clone --depth 5 https://github.com/example/big-project.git

# 克隆某个分支的最近提交
git clone --depth 1 --branch main https://github.com/example/big-project.git

# 浅克隆后拉取更多历史
git fetch --depth 50

我记得有一次线上问题排查,需要看某个文件的修改历史。结果发现CI环境用的是--depth 1克隆的,根本没法git blame。后来我们改了策略:开发环境用完整克隆,CI用浅克隆,但保留最近50次提交。

注意:浅克隆有一些限制。你不能从浅克隆仓库再推送(push)到远程,除非你git fetch --unshallow拉取完整历史。另外,git merge在某些情况下也会失败。所以浅克隆适合只读场景,不适合开发环境。

组合使用:大项目的最佳实践

这些技术不是孤立的。在实际项目中,我通常会组合使用:

# 终极组合:浅克隆 + 稀疏检出 + 无blob
git clone --depth 1 --filter=blob:none --sparse \
  https://github.com/example/monorepo.git

cd monorepo
git sparse-checkout set packages/frontend

这个命令做了什么?

  • --depth 1:只拉取最新提交,不要历史
  • --filter=blob:none:不下载文件内容,只下载目录结构
  • --sparse:启用稀疏检出模式
  • sparse-checkout set:只检出frontend目录

效果?一个原本5GB的仓库,克隆下来只有200MB。时间从30分钟降到1分钟。我团队里有个新人第一次用这个命令,直接惊呼"原来Git可以这么快"。

知识体系总览

下面这张图总结了本章的核心内容,方便你对照理解:

Git大项目实践知识体系 大项目Git管理 Monorepo管理 Git LFS 稀疏检出 浅克隆 组合使用(最佳实践) 代码共享 · 原子提交 统一CI · 权限控制 大文件指针替换 远程存储 · 按流量计费 只检出部分目录 cone模式 · 性能优先 --depth 1 · 只读场景 CI环境 · 快速克隆 浅克隆+稀疏+无blob 5GB→200MB · 30min→1min 四种技术独立使用,但组合效果最佳

总结一下

大项目用Git,说白了就是三个字:减负。减少克隆的数据量,减少工作目录的文件数,减少历史记录的深度。

  • Monorepo:适合多项目协作,但需要工具链支撑
  • Git LFS:大文件的救星,但别滥用
  • 稀疏检出:只拿你需要的代码
  • 浅克隆:只要最新,不要历史

我见过太多团队被Git大项目折磨得死去活来。其实解决方案就在眼前,只是很多人不知道这些功能的存在。希望这篇文章能帮你少走一些弯路。

最后一句:如果你现在正被大仓库折磨,试试git clone --depth 1 --filter=blob:none --sparse。相信我,你会回来感谢我的。


公众号:蓝海资料掘金营,微信deep3321