Git LFS 大文件优化说明
本文档用于说明本项目如何使用 Git LFS 管理 MP3 等大文件,并给出常见场景下的操作流程、验证方法和风险提醒。
当前项目是 MP3 音频库,mp3/ 目录下的音频文件不适合直接作为普通 Git 对象长期提交。仓库已配置:
gitattributes
*.mp3 filter=lfs diff=lfs merge=lfs -text
这表示所有 .mp3 文件都会由 Git LFS 管理。
1. 为什么需要 Git LFS
Git 适合管理源码、配置文件、Markdown 文档等文本类文件,不适合直接管理大量二进制大文件,例如:
- MP3 音频
- 视频
- 图片资源
- 模型文件
- 压缩包
如果直接把大文件提交到普通 Git 历史中,会产生几个问题:
- Git 会保存完整二进制内容
- 文件每次修改都会产生新的对象
- 仓库历史会快速膨胀
clone、pull、push速度下降- GitHub 单次接收的 pack 文件有大小限制
可以用下面的命令检查仓库对象大小:
bash
git count-objects -vH
如果出现类似结果:
text
size-pack: 2.36 GiB
推送时可能遇到:
text
remote: fatal: pack exceeds maximum allowed size (2.00 GiB)
error: remote unpack failed: index-pack failed
原因是 GitHub 单次接收的 pack 文件超过 2GB 限制。
2. Git LFS 是什么
Git LFS(Large File Storage)是 Git 官方提供的大文件存储扩展。
核心思想:
Git 仓库中保存大文件指针,真正的大文件存储在 Git LFS 服务端。
普通 Git 保存大文件时:
text
Git Repository
.git/objects
├── source.js
└── xxx.mp3 (100MB)
使用 Git LFS 后:
text
Git Repository
.git/objects
├── source.js
└── xxx.mp3 pointer
Git LFS Storage
└── xxx.mp3 (100MB)
Git 中实际保存的是类似这样的指针文件:
text
version https://git-lfs.github.com/spec/v1
oid sha256:xxxxxx
size 104857600
真正的 MP3 文件存储在 LFS 服务端。
3. 安装 Git LFS
macOS:
bash
brew install git-lfs
git lfs install
git lfs version
Ubuntu / Debian:
bash
sudo apt update
sudo apt install git-lfs
git lfs install
git lfs version
git lfs install 会安装本机 Git LFS hooks。每台开发机器通常只需要执行一次。
4. 本项目的大文件配置
本项目根目录的 .gitattributes 已包含:
gitattributes
*.mp3 filter=lfs diff=lfs merge=lfs -text
这会让所有 .mp3 文件进入 Git LFS。
如果在新仓库中首次配置,可以执行:
bash
git lfs track "*.mp3"
git add .gitattributes
生成或更新的 .gitattributes 内容应类似:
gitattributes
*.mp3 filter=lfs diff=lfs merge=lfs -text
建议同时提交 .gitattributes,否则其他人 clone 仓库后无法自动得到相同的 LFS 规则。
5. 验证 Git LFS 配置
查看规则:
bash
cat .gitattributes
检查某个 MP3 文件是否命中 LFS 规则:
bash
git check-attr filter -- mp3/test.mp3
正确结果:
text
mp3/test.mp3: filter: lfs
错误结果:
text
mp3/test.mp3: filter: unspecified
如果显示 unspecified,表示该文件没有进入 LFS 规则,需要检查 .gitattributes 是否存在、路径是否正确、文件扩展名是否匹配。
查看已经由 LFS 跟踪的文件:
bash
git lfs ls-files
查看当前 LFS 状态:
bash
git lfs status
6. 新项目使用 Git LFS 的推荐流程
新项目建议先配置 LFS,再添加 MP3 文件:
bash
git init
git lfs install
git lfs track "*.mp3"
git add .gitattributes
git add .
git commit -m "initial commit with git-lfs"
git remote add origin git@github.com:xxx/repo.git
git push -u origin main
重点是:先 git lfs track "*.mp3",再 git add 大文件。
如果先把 MP3 加入普通 Git,再配置 LFS,旧历史里仍然会保留普通 Git 对象。
7. 已提交大文件迁移到 Git LFS
如果 MP3 已经提交到普通 Git 历史中,例如:
text
commit 1:
add genesis.mp3
commit 2:
modify genesis.mp3
可以用 Git LFS 迁移历史:
bash
git lfs migrate import \
--include="*.mp3" \
--everything
迁移后检查:
bash
git lfs ls-files
git count-objects -vH
然后推送:
bash
git push origin main --force
注意:git lfs migrate import --everything 会重写 Git 历史,--force 推送会覆盖远端分支历史。执行前必须确认:
- 所有人都已停止向旧分支提交
- 已备份重要分支或 tag
- 团队成员知道需要重新 clone 或重置本地分支
- GitHub Actions、部署环境、镜像仓库都能接受历史重写
如果仓库已经公开发布或多人协作,优先选择新建迁移分支、测试通过后再统一切换。
8. 未发布项目删除 Git 历史重新初始化
如果项目尚未发布、没有其他人基于当前 Git 历史协作,可以选择删除 Git 历史后重新初始化。
危险操作,执行前请确认当前目录正确,并做好备份:
bash
rm -rf .git
重新初始化:
bash
git init
git branch -M main
git lfs install
git lfs track "*.mp3"
提交:
bash
git add .
git commit -m "initial commit with git-lfs"
推送:
bash
git remote add origin git@github.com:xxx/repo.git
git push -u origin main --force
优点:
- 清除旧历史
- 仓库大小立即下降
- 操作简单
限制:
- 会丢失旧提交历史
- 不适合已经发布或多人协作的仓库
- 需要重新设置远端和分支保护策略
9. Clone 后是否能获得完整 MP3
可以,前提是本机安装并启用了 Git LFS。
正常 clone:
bash
git clone git@github.com:xxx/repo.git
Git LFS 会自动下载真实文件,目录中看到的是完整 MP3:
text
project/
├── src/
├── README.md
└── mp3/
├── genesis.mp3
└── matthew.mp3
如果没有安装 Git LFS,可能看到的是指针文件:
text
version https://git-lfs.github.com/spec/v1
oid sha256:xxxx
size xxxx
这不是音频文件本体。安装并拉取 LFS 内容:
bash
git lfs install
git lfs pull
10. CI/CD 中使用 Git LFS
GitHub Actions 使用 actions/checkout 时,需要开启 LFS:
yaml
- uses: actions/checkout@v4
with:
lfs: true
否则 CI 拉取到的可能只是 LFS pointer,而不是完整 MP3 文件。
如果 CI 中只需要代码、不需要音频,可以不拉取 LFS,以减少构建时间和流量。
11. 常用排查命令
检查仓库对象大小:
bash
git count-objects -vH
查看 LFS 跟踪规则:
bash
git lfs track
cat .gitattributes
检查文件属性:
bash
git check-attr filter -- mp3/test.mp3
列出 LFS 文件:
bash
git lfs ls-files
下载 LFS 文件:
bash
git lfs pull
检查 LFS 环境:
bash
git lfs env
12. 本项目推荐示例
针对当前 xxx-mp3-cn 仓库,推荐把普通文件和 MP3 文件分开提交。一次性把所有文件放进同一个 commit,容易在 LFS 规则未生效、缓存未清理或误 add 的情况下,把 MP3 作为普通 Git 对象写进历史。
推荐流程如下。
先初始化 Git LFS 并配置 MP3 跟踪规则:
bash
git lfs install
git lfs track "*.mp3"
git add .gitattributes
先提交非 MP3 文件,例如源码、脚本、文档、转写文本等:
bash
git add README.md scripts books .transcripts
git commit -m "add project files"
查看此时 Git pack 大小:
bash
git count-objects -vH
这一步的 pack 应该比较小,因为还没有提交 MP3 本体。
然后再单独添加 MP3 文件:
bash
git add mp3
git status --short
git lfs ls-files
确认 git lfs ls-files 能看到 MP3 文件后,再提交音频:
bash
git commit -m "add mp3 files with git-lfs"
再次查看 Git pack 大小:
bash
git count-objects -vH
如果 LFS 生效,Git pack 不应该因为 MP3 文件大幅膨胀;MP3 的真实内容会进入 LFS 存储,Git 历史中只保存 pointer。
最后推送:
bash
git push -u origin main
这个"两次 commit"的方式更容易排查问题:
- 第一次 commit 只验证普通项目文件是否正常
- 第二次 commit 专门验证 MP3 是否进入 Git LFS
- 如果 pack 在添加 MP3 后突然变大,说明 LFS 可能没有生效,应先停止推送并检查
.gitattributes、git lfs ls-files和git check-attr - 避免一次 commit 把普通文件和大文件混在一起,导致问题发生后很难判断是哪一步引入了大对象
CI 如需读取真实音频,actions/checkout 仍需配置:
yaml
- uses: actions/checkout@v4
with:
lfs: true