说实话,第一次被 GitHub 拒掉提交时,我还以为是自己操作出了问题。
项目里放了一个训练好的模型权重文件,git add 之后 git push,结果远端直接甩回来一行红字:
text复制remote: error: File model.pth is 312.42 MB; this exceeds GitHub's file size limit of 100 MB
remote: error: GH001: Large files detected. You may want to try Git Large File Storage
紧接着我看了下本地仓库状态,文件已经在本地提交了,但远端一个字节都没收。这就是 GitHub 对大文件上传最经典的拦截方式:不是等你传完再告诉你,而是在推送阶段就把整个传输中止掉。
这不是个例。模型文件、设计稿、视频素材、数据集、安装包,凡是体积超过 100MB 的二进制文件,放进代码仓库的那一刻起,就注定会撞上这道限制。这篇内容就是一次完整的大文件上传失败解决记录,我会把 GitHub 的文件限制规则、Git LFS 的原理和操作、历史仓库迁移、配额报错,以及不走 LFS 的替代方案全部过一遍。适合被"Large files detected"卡住的人,也适合想在团队里建立一套大文件管理规范的人参考。
1. GitHub文件限制规则与"上传失败"的真实成因
1.1 官方限制并非只有一个100MB
很多人以为 GitHub 只有"单文件超过 100MB 不能提交"这一条规则,实际比这复杂一点。
GitHub 对仓库文件的限制分几个层级:
| 限制对象 | 限制数值 | 触发表现 |
|---|---|---|
| 网页端上传文件 | 单文件 25MB | 页面直接报错 |
| 普通 git push 单文件 | 超过 50MB 警告 | 推送时会显示 warning,但可能仍然成功 |
| 普通 git push 单文件 | 超过 100MB 拒绝 | 远端返回 GH001 错误,push 中断 |
| Git LFS 管理的文件 | 免费额度 1GB 存储 + 1GB 带宽/月 | 超出后返回 data quota 错误 |
| Release 附件 | 单文件 2GB | 超过则无法上传 |
也就是说,50MB 时 GitHub 会提醒你"这文件有点大了",100MB 时直接拒绝,而 2GB 是另一套通道(Release)的上限。如果你在网上看到有人说"我 push 了一个 500MB 的文件也没事儿",要么他用了 LFS,要么他走的是 Release,要么他那个仓库根本不是 GitHub 托管的。
另外注意一个容易混淆的点:GitHub 的 100MB 限制针对的是普通代码仓库的 git push,而不是 Release 附件,也不是 LFS 对象。后两者有另一套体积规则。很多人上来就以为是"GitHub 不能传大文件",其实准确说法是"GitHub 不能通过普通 git push 传超过 100MB 的文件"。
1.2 失败的几种典型形态
我在各个项目里实际遇到的大文件上传失败,表现形态并不完全一样,至少有这么几种:
形态一:push 直接被拒
这是最典型的一种,报错长这样:
text复制remote: error: File assets/video/demo.mp4 is 325.00 MB; this exceeds GitHub's file size limit of 100 MB
remote: error: GH001: Large files detected. You may want to try Git Large File Storage
这种情况下,本地 commit 是成功的,但远端分支收不到任何内容。此时 git log 里已经有那个提交了,但 git push 永远失败。
形态二:push 卡在传输阶段后超时
文件没有超过 100MB,但总量很大,比如几千个小文件加起来几个 GB。push 时进度条卡在某个位置,然后报 RPC failed; HTTP 500 curl 22 The requested URL returned error 或者 fatal: the remote end hung up unexpectedly。这类问题不是文件大小限制,而是传输中断或 HTTP buffer 不够,后面我会专门讲。
形态三:LFS 配额超限
如果你已经用 LFS 管理大文件,但仓库的 LFS 存储或带宽超出了免费额度,会报:
text复制batch response: this repository is over its data quota
这个报错非常容易让人误以为是网络问题,实际上是配额问题。
形态四:GUI 工具"假失败"
有些图形化 Git 客户端在 push 大文件时,由于没有把远端错误信息完整展示出来,只显示"failed to push",导致你搞不清是文件超限还是网络故障。我第一次遇到时也排查了很久,最后还是在命令行里重新 push 才看到 GH001 的具体报错。
1.3 先判断"文件超限"还是"传输故障"
我不建议一上来就装 LFS。先花一分钟定位问题类型,能省很多事。
判断方法很简单:在命令行执行 git push,看报错类型。如果返回的是 this exceeds GitHub's file size limit,那就是文件超限,直接走 LFS 方案。如果返回的是 RPC failed、Operation timed out、Connection reset by peer 这类网络层错误,那说明传输链路有问题,大文件本身可能没超限,需要从传输层面解决。
还有一种特殊情况:本地仓库曾经提交过大文件,后来删掉了,但 Git 历史里还留着那个大文件对象。这种情况下 push 一样会被拒,因为你推送的不只是当前版本,而是整个提交历史。这类问题要在 git push 时看报错里提示的 File xxx is xxx MB,如果那个文件是历史遗留,单纯删除当前文件是没用的,必须处理历史。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Git LFS的核心原理:大文件不该和普通文件走同一条管道
2.1 LFS用"指针文件"换掉真正的二进制内容
Git LFS(Large File Storage)是 Git 官方生态里处理大文件的标准扩展,核心思路一句话就能讲明白:仓库里存的不再是二进制本身,而是一个指向二进制内容的文本指针。
我打个比方。普通 Git 仓库就像一家餐厅,每道菜都得在后厨现做,菜太大后厨放不下。LFS 的做法是:后厨不变,但菜单上遇到大盘菜时,只放一个"取餐凭证",真正的菜放在中央厨房,顾客凭凭证去取。仓库负责的是菜单(源码文本),中央厨房负责的是真正的重量级文件(二进制对象)。
具体到技术层面,当你把一个大文件交给 LFS 管理后,Git 仓库里保存的是一个几 KB 的文本文件,内容大致长这样:
text复制version https://git-lfs.github.com/spec/v1
oid sha256:4d7a214f5e1c1d7a3a5f2f2b2e6c3524d9b5e5e5b5fef8e8e8e8e8e8e8e8e8e8e8
size 312423412
真正 312MB 的模型文件被存到了 LFS 存储服务器上,本地和远端仓库里只有这个指针。这样有几个直接好处:
- push 和 pull 时不再传输几百兆的二进制,传输量骤减
- clone 仓库时只拉指针文件,速度飞快
- 仓库本身保持轻量,所有协作者不需要下载全部大文件才能开始工作
2.2 .gitattributes是LFS的"路由表"
LFS 怎么知道哪些文件应该走指针、哪些文件应该正常提交?靠的是仓库根目录下的 .gitattributes 文件。
当你执行 git lfs track "*.mp4" 后,Git 会在 .gitattributes 里写入一条规则:
text复制*.mp4 filter=lfs diff=lfs merge=lfs -text
这行东西看起来简单,但它是 LFS 的"路由表"。它的含义是:所有 .mp4 结尾的文件,在 checkout 时用 LFS filter 把指针替换成真实文件,在 add 时把真实文件替换成指针写进暂存区。
如果你误删了 .gitattributes,或者在没有正确 filter 的情况下 add 大文件,LFS 就可能失效,大文件以原始二进制形式进入 Git 对象库,push 时照样撞 100MB 限制。所以我建议养成一个习惯:在提交代码时,留意 .gitattributes 是否被一起提交,这也是很多"明明配置了 LFS 却仍然报 Large files detected"的原因。
2.3 LFS的适用边界
LFS 不是万能药,它也有自己的适用边界。我见过不少人把什么文件都丢给 LFS 管,结果仓库越来越臃肿,配额很快爆掉。
适合用 LFS 管理的文件:
- 模型权重文件(.pth、.h5、.onnx、.pt)
- 多媒体素材(.mp4、.mov、.psd、.ai、.zip 包)
- 数据集、固件包、安装包等二进制产物
- 体积较大且不频繁变动的文件
不适合用 LFS 管理的文件:
- 文本文件、配置文件、代码文件(这些应该正常走 Git,否则 diff 和版本对比会失效)
- 体积小、改动频繁的二进制(比如每次都重新生成的构建产物)
- 可随时重新生成的中间产物(缓存、临时目录)
判断标准其实很简单:这个文件是"源头资产"还是"产物"? 模型权重、设计原稿是源头资产,值得入库管理;编译产物、临时缓存是垃圾,应该用 .gitignore 拦掉,而不是想办法塞进仓库。
3. 从零配置Git LFS并成功推送大文件:完整操作链路
3.1 安装LFS并在仓库中初始化
首先确保本机装了 Git LFS。在命令行验证一下:
bash复制git lfs version
如果没有输出,需要先安装。macOS 上可以用 Homebrew:
bash复制brew install git-lfs
Ubuntu 或 Debian 类的系统:
bash复制sudo apt install git-lfs
Windows 用户可以直接去 Git LFS 官网下载安装包,或者用 scoop install git-lfs。
安装完成后,执行全局初始化。这一步只需要做一次:
bash复制git lfs install
这个命令会在你的 Git 配置里注册 LFS 的 filter,让 Git 认识 filter=lfs 这种指令。注意,就算你全局初始化了,每个仓库里要不要用 LFS 还是独立的,取决于仓库有没有 .gitattributes 和 LFS 对象。
然后进入你的项目目录,再次执行:
bash复制git lfs install
在仓库内执行这一遍,会确保仓库级别的 LFS 配置也正确。
3.2 track:按后缀还是按具体文件
接下来是选择要管理哪些文件。两种方式:
按后缀批量管理:
bash复制git lfs track "*.pth"
git lfs track "*.mp4"
git lfs track "*.zip"
按具体路径管理:
bash复制git lfs track "models/weights.pth"
按后缀的好处是一劳永逸,以后新增的同类型文件自动走 LFS。但要注意,*.pth 这种模式会匹配仓库里所有层级的 .pth 文件,如果你有某个 .pth 文件其实很小、没必要走 LFS,也一样会被接管,导致不必要的配额消耗。
按具体路径管理更精准,但需要你清楚文件位置。我个人的做法是:项目里有明确的大文件目录(比如 assets/、models/、data/)时,按目录管理,例如:
bash复制git lfs track "assets/**"
git lfs track "models/*.pth"
配置完之后,必须确认 .gitattributes 已经被修改:
bash复制git status
你会看到 .gitattributes 出现在变更列表里。这个文件一定要提交,否则其他协作者 clone 下来后没有路由规则,LFS 文件会被当成普通文件处理。
3.3 push流程与正确顺序
这里有一个非常关键的顺序问题:先 track,再 add,再 commit,再 push。
如果你在 track 之前就 add 了大文件,这个大文件已经以原始二进制形式进入暂存区,此时再 track 已经晚了,必须把暂存区清掉重新来:
bash复制git rm --cached model.pth
git lfs track "*.pth"
git add model.pth
git commit -m "chore: track model files with git lfs"
正确流程走一遍:
bash复制git lfs install
git lfs track "*.pth"
git add .gitattributes model.pth
git commit -m "add model file via git lfs"
git push origin main
push 完成后,验证 LFS 文件是否真的被识别到了:
bash复制git lfs ls-files
输出列表里有 model.pth,说明 LFS 成功接管。在 GitHub 仓库页面上,文件列表里会显示一个 LFS 的小标签,点进文件详情可以看到真实的下载地址,而不是像普通文件那样直接预览。
3.4 协作者 clone 仓库后的 LFS 体验
如果团队其他人 clone 这个仓库,默认行为是:仓库里看到的是 LFS 指针文件,而不是真实的大文件。这是故意的,目的是让 clone 保持轻量。
但问题来了:如果协作者需要真实文件,怎么办?两条路:
bash复制git lfs pull
这个命令会把所有 LFS 文件拉到本地工作区。也可以只拉部分:
bash复制git lfs pull --include="models/*"
有一种场景比较特殊:协作者根本不需要大文件,只想看代码。那么可以在 clone 时跳过 LFS 文件的自动下载:
bash复制GIT_LFS_SKIP_SMUDGE=1 git clone git@github.com:your/repo.git
设置了 GIT_LFS_SKIP_SMUDGE=1 后,clone 出来的仓库里 LFS 文件都是一堆指针文本,工作区能快速就位,等真正需要大文件时再手动 git lfs pull。这在 CI 构建里尤其常用:构建机只需要代码,不需要动辄几百MB的模型文件。
4. 历史仓库大文件迁移:git lfs migrate实战
4.1 为什么直接track旧文件不够
很多人的实际情况是:项目已经跑了一段时间,本地有一堆历史提交,某个大文件早就混在历史里了。此时按照上一章的做法 track 新文件,然后 push,依然会失败。
原因在 Git 的工作机制:push 推送的是整个提交历史,而不是"当前工作区"。只要某个大文件存在于任何一个历史 commit 中,GitHub 在接收时就会扫描到它并拒绝整个 push。你也可以试着用 git rm 删掉当前版本的大文件,但历史里的那个大文件对象仍然在 .git 对象库里躺着,照样触发限制。
这时必须进行历史迁移,把过去所有 commit 里出现过的目标大文件全部改写成 LFS 指针。
4.2 migrate命令的关键参数与操作
Git LFS 从 2.2 版本开始提供 git lfs migrate 命令,专门做这种事。基本用法:
bash复制git lfs migrate import --include="*.zip,*.pth" --everything
关键参数拆解:
import:子命令,表示把文件导入 LFS 管理--include:指定要迁移的文件匹配模式,多个模式用逗号分隔--everything:迁移所有本地分支和 tag 里的引用,不只是当前分支--above:按大小过滤,比如--above=100MB,只迁移超过 100MB 的文件,其他小文件不动
如果只想迁移超过一定大小的文件,可以这样:
bash复制git lfs migrate import --everything --above=100MB
执行过程中,LFS 会重写 Git 历史:每个 commit 里的目标文件被替换成 LFS 指针,真正的文件内容转移到 LFS 存储区。输出大概长这样:
text复制migrate: Sorting commits: ...
migrate: Rewriting commits: 100% (12/12), done.
migrate: Updating refs: ...
迁移结束后,你还需要把远程地址重新关联一下,因为历史重写后本地 refs 已经变了。用 git lfs migrate 后,Git 会把远程 url 也重写掉,所以需要重新设置:
bash复制git remote set-url origin git@github.com:your/repo.git
4.3 migrate之后的收尾动作:清理旧对象并强制推送
历史重写完成只是第一步。旧的大文件对象还残留在 .git 对象库里,如果不清理,本地仓库依然臃肿。执行:
bash复制git reflog expire --expire=now --all
git gc --prune=now --aggressive
这两行命令会清掉 reflog 里对旧提交的引用,然后强制 GC 掉不再被任何引用指向的旧对象。这一步做完,本地仓库会明显瘦身。
接下来要强制推送:
bash复制git push --force origin main
这里的 --force 是因为历史被重写后,本地分支和远端分支已经分叉,普通 push 会被拒绝。如果仓库有多个分支,需要逐个分支 force push,tag 也需要额外处理。
4.4 迁移的副作用与团队协作注意事项
用 git lfs migrate 重写历史有个绕不开的副作用:所有受影响 commit 的 hash 都会改变。
这意味着:
- 已有的 PR(Pull Request)可能会显示为已关闭或需要重新打开
- issue 里引用的 commit 链接会失效
- 其他协作者本地的旧分支、旧提交会与远端脱节
所以团队协作时,必须提前告知所有人迁移的时间点,约定迁移完成后统一重新 clone 或 reset 到远端最新状态。不要在有大量未合并 PR 的时候做这种操作,否则会引发混乱。
另外,绝对不要在迁移前忘了备份。历史重写是不可逆操作,虽然技术上有挽回手段,但实际操作起来代价很高。简单做法是先把整个目录复制一份,或者 git bundle create backup.bundle --all 做全量备份。
5. LFS的配额天花板:data quota报错与应对
5.1 免费额度的计算方式
Git LFS 虽然解决了 100MB 限制问题,但它不是无限容量。GitHub 对 LFS 有明确的配额管理,免费账户的额度是:
- 1GB 存储空间:所有经 LFS 管理的文件,按远端存储的文件总大小计算
- 1GB 带宽/月:每月从 LFS 下载流量的总量限制
存储空间是按"仓库中所有 LFS 对象的去重总大小"计算的。注意,它计算的是所有曾通过 LFS 推送过的文件对象,即使你后来删除了仓库里的文件,如果历史里还留着,存储配额可能不会自动释放。这一点不少人都踩过坑。
查看用量非常方便:打开 GitHub 仓库页面,进入 Settings -> Storage 和 Bandwidth 栏目,可以看到当前配额使用情况以及每日更新曲线。
5.2 遇到 batch response: this repository is over its data quota 怎么办
当 LFS 配额超限时,push 会报:
text复制batch response: this repository is over its data quota
遇到这个报错,第一步先登录 GitHub 看配额使用详情,确认是存储超了还是带宽超了。
如果是带宽超了,通常只需要等。GitHub 的 LFS 带宽是按自然月重置的,下个月初额度恢复。如果项目很急着用,可以考虑让协作者暂时不要频繁 pull LFS 文件,或者把大文件临时挪到外部存储。
如果是存储超了,会比较棘手。因为你不能简单地从仓库里删文件来释放配额——GitHub 对 LFS 存储的计算方式是"仓库中所有 LFS 对象的总大小",包括历史提交里仍然被引用的对象。就算你 git rm 了某个大文件,它在历史 commit 里的对象依然存在,存储占用不会减少。彻底释放存储配额,目前可行的手段是:删除整个仓库(会连代码一起删),或者开启 GitHub 的付费计划获得更多配额。对于大部分个人项目,最实际的方案是把超限的 LFS 文件从迁移方案中排除,改用外部存储(下一章细说)。
5.3 LFS文件的清理与配额回收
有人会问:我用 git lfs prune 能不能清理?这里要区分本地和远端。
git lfs prune 只能清理本地缓存里已经不再被任何 commit 引用的旧 LFS 文件,让本地磁盘瘦身。它不会影响远端存储配额。
要在远端真正释放配额,最可靠的方式是删除仓库后重建。但这对代码仓库来说代价太大。因此我的建议是:把 LFS 当作"有严格容量上限的高速通道",而不是无限网盘。 在项目规划阶段就评估好大文件的体积总量,挑最核心的资产进 LFS,其余放外部存储。
5.4 超过2GB的文件怎么办
LFS 能解决 100MB 限制,但它自己也有单文件体积上限。GitHub LFS 的单个文件上限是 2GB,超过这个值 push 同样会被拒绝。
对于超大文件(比如好几个 GB 的训练数据集、完整版视频素材),我通常建议不要硬塞 LFS。
一种做法是用分卷压缩拆开:
bash复制zip -s 1g large_dataset.zip --out dataset_part.zip
分成多个 1GB 的包,然后再按 LFS 管理。但拆分包有个问题:用户下载后需要合并,体验不好。
更好的做法是直接把这类文件放到对象存储上,仓库里只放下载脚本和校验信息。这就是下一章要说的替代方案。
6. 不走LFS的大文件方案:Release附件与外部存储
6.1 Release附件:适合最终发布物
如果你的大文件不是"项目日常开发中需要频繁访问的资产",而是"最终交付给用户下载的产物",GitHub Release 是比 LFS 更简单的通道。
做法:在仓库的 Releases 页面新建一个 Release,填好版本号、标题和说明,然后把大文件作为附件拖进去。Release 附件单文件上限是 2GB(实际界面可能因网络环境限制略有差异),不占用 LFS 配额,而且下载界面非常友好,用户可以直接在网页上点击下载。
我一般这样分配:开发期需要追踪版本的大文件走 LFS,对外发布的完整安装包、模型 bundle 走 Release。 Release 附件的好处是它不参与 Git 历史,不污染仓库体积,任何协作者 clone 仓库时都不会被迫下载这些大文件。缺点是它只是一个"网盘链接",没有版本控制语义,不能像 LFS 那样和 commit 绑定。
6.2 外部对象存储:OSS/S3这种"放链接"的思路
对于超大文件、数据集类的资源,我现在的标准做法是:对象存储 + 校验脚本 + README 说明。
具体来说:
- 把大文件上传到对象存储服务(S3、OSS、COS 这类)
- 在仓库里放一个下载脚本,比如
scripts/download_data.sh - 在 README 里写明文件的 URL、SHA256 校验值、版本说明
- 需要这些文件的开发者在本地执行脚本拉取
这样的好处非常明显:
- 仓库完全保持轻量,没有 100MB 限制问题
- 单个文件可以轻松超过 2GB,不受 LFS 上限约束
- 费用透明、带宽按量付费,不占用 GitHub 配额
- 大文件的更新不需要改动 Git 历史,只需要改脚本里的版本号
一个简单的下载脚本示例:
bash复制#!/usr/bin/env bash
DATA_URL="https://your-bucket.example.com/datasets/v1/data.zip"
SHA256="a1b2c3d4e5f6..."
curl -L "$DATA_URL" -o data.zip
echo "$SHA256 data.zip" | sha256sum --check
用户跑一下 bash scripts/download_data.sh 就能拿到数据,而且校验和能确保文件没有被篡改或传输损坏。
6.3 选哪种方案:一张实用决策单
我在实际项目里判断用哪种方案时,一般按下面这张表来:
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 单个文件 100MB~2GB,开发中频繁引用 | Git LFS | 有版本关联,checkout 即用 |
| 单个文件 100MB~2GB,最终交付物 | Release 附件 | 不占 LFS 配额,下载方便 |
| 单文件超过 2GB,或总量超过配额 | 对象存储 + 脚本 | 无体积限制,不污染仓库 |
| 可再生的构建产物、缓存 | .gitignore 忽略 | 根本没有入库必要 |
| 偶尔分享的临时文件 | 不放进仓库,用临时文件分享工具 | 保存期短,不占仓库空间 |
这张表不是死的,比如某些项目就是需要把大文件和代码一起受版本控制,那么即使超过 2GB 也要想办法拆分。大部分情况下,按这个决策单走,能避免 90% 的大文件上传问题。
7. 上传大文件前的检查清单和两个容易忽略的坑
7.1 我在实际项目中整理的一份push前检查清单
踩过几次坑之后,我给自己定了一套固定的检查流程,每次要提交大文件前都过一遍:
text复制1. 确认文件有没有必要进仓库:是源头资产,还是可再生的构建产物?
2. 确认文件大小:超过100MB,必须走LFS;超过2GB,考虑外部存储。
3. 是否已经在 .gitattributes 里配置了对应规则?
4. 是否先 git add 再 track?如果是,先 git rm --cached 清掉。
5. 是否提交了 .gitattributes?没提交等于白配置。
6. push 时看远端返回:是GH001还是网络错误?
7. push 后是否验证 git lfs ls-files 有对应文件?
8. 历史里有没有旧的大文件?有就需要 git lfs migrate。
9. LFS 配额是否足够?去 Settings -> Storage 查看。
10. 协作者是否知道大文件的拉取方式?
这十条看着简单,但每一条我都实际踩过。特别是第 5 条:.gitattributes 没提交,导致同事 clone 后直接把整个项目拉爆的情况,发生过不止一次。
7.2 网络波动引发的大文件传输中断
文件超限解决了,不等于万事大吉。还有一种失败不属于"大小限制",而是传输层面的问题。
使用 HTTPS 方式 push 大文件时,如果网络条件波动比较大,经常会出现:
text复制RPC failed; HTTP 400 curl 22 The requested URL returned error
fatal: the remote end hung up unexpectedly
这个错误的本质是 Git push 过程中 HTTP 缓冲区不够,或者单次请求数据量太大导致连接被中断。Git 的 push 过程没有断点续传,一旦中断就得从头再来。
针对这个情况,可以调整本地 Git 配置:
bash复制git config http.postBuffer 524288000
http.postBuffer 默认值是 1MB 左右(旧版本),把它调大可以容纳更大的单次 HTTP 请求体。上面的命令设置成 500MB,能让某些大文件推送更稳定。
另外一个方法是切换传输协议。如果你用的是 HTTPS,可以试试换成 SSH 方式推送:
bash复制git remote set-url origin git@github.com:your/repo.git
SSH 的传输机制和 HTTP 不同,一些 HTTPS 下容易超时的场景会改善。注意,这个操作需要你已经配置好 SSH key。
还有一个小技巧:如果历史提交里累积了大量数据,可以先把提交拆分,分批推送。比如把大改动拆成多个 commit 逐个 push,而不是积攒一堆后一次性推。这样单次传输量小,中断概率会更低。
7.3 团队协作中的大文件管理习惯
大文件管理不只是技术问题,更是协作规范问题。我从自己的团队实践中总结了几条习惯:
第一,目录分区隔离。大文件尽量集中在 assets/、models/、data/ 这类固定目录,而不是散落在代码目录里。这样 .gitattributes 规则更清晰,也方便 git lfs ls-files 审查。
第二,LFS 文件不要频繁变动。LFS 虽然解决了体积限制,但每次改动大文件都会产生新的存储版本,占用配额。一个模型文件反复训练覆盖、反复提交,可能一两天就把 1GB 配额耗光。正确的做法是:确定某个产物基本稳定后再入 LFS,训练中的中间产物用定期导出到外部存储的方式管理。
第三,把 .gitignore 和 .gitattributes 当作项目配置的一部分来维护,而不是建完就忘。新成员入职时,README 里应该写清楚"哪些目录是大文件目录,怎么拉取、怎么更新",避免同事直接用错误方式把超大文件塞进仓库。
第四,定期清理本地 LFS 缓存。跑 git lfs prune 释放本地磁盘空间。远端配额只能通过合理规划控制,本地缓存却可以靠这个命令维持干净。
最后
聊点我自己的体会。这套 LFS 方案前前后后用了很多次之后,我现在处理大文件已经形成了一套固定流程:先问"这个文件该不该进 Git",再问"走 LFS 还是外部存储",最后才动手。发现 100MB 报错时不要慌,花一分钟看清楚报错类型,再决定用 LFS 迁移、历史重写还是干脆换 Release 附件。
如果你只是想让一个带大文件的仓库成功推上 GitHub,最简单的组合拳就是:git lfs install,git lfs track "你要管理的文件",提交 .gitattributes,再 git push。如果 push 前发现文件早就混在历史里了,就补一步 git lfs migrate。这套流程我已经在多个项目里验证过,个人模型文件、设计稿素材、视频 demo 都能稳定落在 GitHub 上,仓库本身还保持得干干净净。
