目录
- 一、Git LFS 是什么
- 二、安装与初始化
- 三、基本工作流
- 四、
.gitattributes配置 - 五、常用命令速查
- 六、迁移现有仓库
- 七、清理误提交的大文件
- 八、克隆与拉取优化
- 九、自建 LFS 服务器
- 十、第三方平台配额
- 十一、CI/CD 集成
- 十二、安全与权限
- 十三、性能调优
- 十四、常见问题
- 十五、替代方案对比
一、Git LFS 是什么
Git Large File Storage 是 Git 的扩展,用于解决大文件让 Git 仓库膨胀、克隆/推送变慢的问题。
1.1 核心原理
普通 Git: LFS:
┌──────┐ ┌──────┐
│ 仓库 │ ←存大文件本身 │ 仓库 │ ← 存指针文件(约 130 字节)
└──────┘ └──────┘
│ 指针
▼
┌──────────┐
│ LFS 存储 │ ← 真正的大文件
└──────────┘
LFS 把大文件替换成指针文件提交到 Git,真正内容存到独立服务器;checkout 时按需下载。
1.2 指针文件格式
version https://git-lfs.github.com/spec/v1
oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393
size 12345678
1.3 何时使用
| 场景 | 是否用 LFS |
|---|---|
| 二进制资源(图片/音视频/字体) | ✅ |
| 设计文件(PSD/AI/Sketch) | ✅ |
| 数据集、模型权重 | ✅ |
| 编译产物 | ❌(不要入库) |
| 文本文件 | ❌(Git 自带压缩+diff) |
| 几 KB 的小图标 | ❌(提交开销 > 收益) |
经验阈值:单文件 > 5 MB 或仓库内同类大文件总量 > 50 MB 时考虑。
二、安装与初始化
2.1 安装
# macOS
brew install git-lfs
# Ubuntu/Debian
curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
sudo apt install git-lfs
# Windows (winget 或 choco)
winget install GitHub.GitLFS
# 验证
git lfs version
2.2 初始化(每个机器一次)
git lfs install
会写入全局 ~/.gitconfig:
[filter "lfs"]
clean = git-lfs clean -- %f
smudge = git-lfs smudge -- %f
process = git-lfs filter-process
required = true
2.3 仓库初始化
cd my-repo
git lfs install --local # 仅本仓库
git lfs track "*.psd" # 跟踪 .psd
git add .gitattributes
git commit -m "configure LFS"
三、基本工作流
# 1. 声明哪些文件走 LFS
git lfs track "*.psd"
git lfs track "models/*.safetensors"
git lfs track "data/**/*.parquet"
# 2. 提交 .gitattributes(必须)
git add .gitattributes
git commit -m "track binaries with LFS"
# 3. 添加并提交大文件
cp ~/big.psd assets/
git add assets/big.psd
git commit -m "add design"
# 4. 推送(首次会上传到 LFS 服务器)
git push origin main
3.1 验证文件是否走 LFS
git lfs ls-files
# 1234abcd * assets/big.psd
git check-attr -a assets/big.psd
# assets/big.psd: filter: lfs
# assets/big.psd: diff: lfs
# assets/big.psd: merge: lfs
# assets/big.psd: text: unset
3.2 拉取大文件
git pull # 自动下载新增的 LFS 文件
git lfs pull # 显式拉取所有 LFS 文件
git lfs pull --include="data/*.parquet" # 部分
四、.gitattributes 配置
4.1 语法
<pattern> filter=lfs diff=lfs merge=lfs -text
-text 关闭文本规范化,保护二进制完整性。
4.2 常用规则模板
# 图片
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text
# 音视频
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.mov filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
# 字体
*.ttf filter=lfs diff=lfs merge=lfs -text
*.woff2 filter=lfs diff=lfs merge=lfs -text
# 压缩包
*.zip filter=lfs diff=lfs merge=lfs -text
*.tar.gz filter=lfs diff=lfs merge=lfs -text
# 模型/数据
*.safetensors filter=lfs diff=lfs merge=lfs -text
*.bin filter=lfs diff=lfs merge=lfs -text
*.gguf filter=lfs diff=lfs merge=lfs -text
*.parquet filter=lfs diff=lfs merge=lfs -text
*.h5 filter=lfs diff=lfs merge=lfs -text
4.3 路径限定
assets/raw/**/*.png filter=lfs diff=lfs merge=lfs -text
# 仅 assets/raw 下的 PNG 走 LFS,UI 切图等小图不走
4.4 排除特定文件
.gitattributes 不直接支持否定,但可用更细粒度模式覆盖:
*.png filter=lfs diff=lfs merge=lfs -text
icons/*.png !filter !diff !merge text
五、常用命令速查
| 命令 | 作用 |
|---|---|
git lfs install | 安装 LFS 钩子 |
git lfs track <pattern> | 添加跟踪规则 |
git lfs untrack <pattern> | 移除跟踪规则 |
git lfs ls-files | 列出当前 LFS 文件 |
git lfs status | LFS 文件变更状态 |
git lfs pull | 显式拉取 LFS 内容 |
git lfs fetch | 拉取但不 checkout |
git lfs push | 推送 LFS 内容 |
git lfs prune | 清理本地缓存 |
git lfs migrate import | 把历史大文件迁入 LFS |
git lfs migrate export | 从 LFS 迁出 |
git lfs env | 查看 LFS 环境配置 |
git lfs locks | 查看文件锁 |
git lfs lock <file> | 锁定文件(独占编辑) |
git lfs unlock <file> | 解锁 |
git lfs fsck | 校验本地 LFS 完整性 |
git lfs dedup | 去重本地缓存(macOS APFS) |
六、迁移现有仓库
把已存在的大文件迁入 LFS(会重写历史)。
6.1 迁移指定后缀(保留所有分支)
git lfs migrate import \
--include="*.psd,*.zip,*.bin" \
--everything
git push --force --all
git push --force --tags
6.2 仅迁移当前分支
git lfs migrate import --include="*.psd"
6.3 按文件大小迁移
git lfs migrate import \
--include="*" \
--above=10MB \
--everything
⚠️ 重写历史会让所有协作者重新克隆。提前周知团队,迁移完成后告知所有人:
git fetch --all git reset --hard origin/main
6.4 迁移前预览
git lfs migrate info --everything --above=10MB --top=20
会列出最大的文件让你确认。
6.5 反向迁移(从 LFS 迁出)
git lfs migrate export --include="*.txt" --everything
七、清理误提交的大文件
如果未启用 LFS 时误提交了大文件,仓库会持续膨胀。要彻底清除:
7.1 用 git filter-repo(推荐)
pip install git-filter-repo
# 删除路径
git filter-repo --path big-file.bin --invert-paths
# 按大小(删除所有 > 10MB 的 blob)
git filter-repo --strip-blobs-bigger-than 10M
7.2 用 BFG Repo-Cleaner
java -jar bfg.jar --strip-blobs-bigger-than 10M my-repo.git
cd my-repo
git reflog expire --expire=now --all
git gc --prune=now --aggressive
7.3 推送强制覆盖
git push --force --all
git push --force --tags
7.4 GitHub/GitLab 服务端清理
平台不会自动 GC,可能仍能从旧引用访问。GitHub 需联系 support,GitLab 可在管理员后台 prune。
八、克隆与拉取优化
8.1 跳过 LFS 文件克隆
GIT_LFS_SKIP_SMUDGE=1 git clone <url>
# 仓库本身正常克隆,LFS 文件只下指针
适合 CI 只需源代码、不需大文件的场景。
后续按需拉取:
git lfs pull --include="data/important/*"
8.2 浅克隆 + 部分克隆
git clone --depth=1 --filter=blob:limit=10m <url>
--depth=1:只取最新提交--filter=blob:limit=10m:>10MB 的 blob 按需取
8.3 仅 fetch 不 checkout
git lfs fetch --recent # 仅最近的引用
git lfs fetch --all # 全部历史
8.4 部分 checkout
git sparse-checkout init --cone
git sparse-checkout set src/ docs/
# 大文件目录 assets/ 不会 checkout
九、自建 LFS 服务器
适合企业内网、超大配额、隐私敏感场景。
9.1 协议简介
LFS 走标准 HTTP,三类端点:
POST /objects/batch # 询问对象上传/下载 URL(支持 S3 重定向)
PUT <upload_url> # 上传
GET <download_url> # 下载
POST /locks # 文件锁(可选)
支持 basic transfer(直传)或 S3/Azure 转储(推荐)。
9.2 主流方案
| 方案 | 特点 |
|---|---|
| Gitea | 内置 LFS,开源,最简单 |
| GitLab CE | 内置 LFS,企业级 |
| Gogs | 轻量 |
| lfs-test-server | 官方参考实现,仅测试 |
| rudolfs | Rust 实现,S3 后端 |
| giftless | Python 实现,可对接 S3/Azure/GCS |
9.3 Gitea 部署
# docker-compose.yml
services:
gitea:
image: gitea/gitea:latest
ports: ["3000:3000", "2222:22"]
environment:
- GITEA__server__LFS_START_SERVER=true
- GITEA__server__LFS_JWT_SECRET=<random-base64>
- GITEA__lfs__STORAGE_TYPE=minio
- GITEA__lfs__MINIO_ENDPOINT=minio:9000
- GITEA__lfs__MINIO_ACCESS_KEY_ID=...
- GITEA__lfs__MINIO_SECRET_ACCESS_KEY=...
- GITEA__lfs__MINIO_BUCKET=lfs
volumes:
- ./gitea:/data
minio:
image: minio/minio
command: server /data --console-address ':9001'
environment:
MINIO_ROOT_USER: admin
MINIO_ROOT_PASSWORD: changeme
volumes:
- ./minio:/data
9.4 giftless(独立 LFS server)
pip install giftless
# giftless.conf.yaml
TRANSFER_ADAPTERS:
basic:
factory: giftless.transfer.basic_external:factory
options:
storage_class: giftless.storage.amazon_s3:AmazonS3Storage
storage_options:
bucket_name: my-lfs-bucket
endpoint: https://s3.example.com
access_key_id: AKIA...
secret_access_key: ...
AUTH_PROVIDERS:
- jwt:
algorithm: HS256
private_key: ${JWT_SECRET}
giftless --config giftless.conf.yaml --bind 0.0.0.0:5000
客户端配置:
git config -f .lfsconfig lfs.url https://lfs.example.com/myorg/myrepo
git add .lfsconfig
9.5 nginx 反代
server {
listen 443 ssl http2;
server_name lfs.example.com;
client_max_body_size 5g; # 允许大上传
location / {
proxy_pass http://giftless:5000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_request_buffering off; # 流式上传
proxy_read_timeout 600s;
proxy_send_timeout 600s;
}
}
十、第三方平台配额
10.1 GitHub
| 计划 | 存储 | 月带宽 |
|---|---|---|
| Free / Pro | 1 GB | 1 GB |
| Team | 1 GB | 1 GB |
| 数据包 | $5 / 50 GB / 月 | 50 GB |
⚠️ 超出后下载会被禁用,必须购买 data pack。fork 也会消耗源仓库带宽。
10.2 GitLab
| 计划 | 存储 |
|---|---|
| SaaS Free | 10 GB / 项目 |
| Premium | 250 GB / 项目 |
带宽不单独计费,但有总用量限制。
10.3 Bitbucket
每仓库 1 GB(免费)/ 5 GB(Premium)。
10.4 选型建议
- 小团队、几 GB:GitHub LFS 够用
- 数据集 / 模型 100GB+:自建 + S3,或用 Hugging Face Hub
- 企业内网:GitLab Self-hosted / Gitea + MinIO
- 频繁 fork:避开 GitHub LFS(fork 共享配额)
十一、CI/CD 集成
11.1 GitHub Actions
- uses: actions/checkout@v4
with:
lfs: true # 自动拉 LFS
跳过 LFS(仅需源码):
- uses: actions/checkout@v4
with:
lfs: false
按需拉取:
- uses: actions/checkout@v4
with:
lfs: false
- run: |
git lfs install
git lfs pull --include="models/prod/*.safetensors"
11.2 GitLab CI
variables:
GIT_LFS_SKIP_SMUDGE: "1" # 默认不拉
build:
before_script:
- git lfs pull --include="data/required/*"
script:
- make build
11.3 Jenkins
checkout scmGit(
branches: [[name: '*/main']],
extensions: [[$class: 'GitLFSPull']],
userRemoteConfigs: [[url: 'https://...']]
)
11.4 加速 CI 的 LFS 缓存
- name: Cache LFS
uses: actions/cache@v4
with:
path: .git/lfs
key: lfs-${{ hashFiles('**/.gitattributes', 'data/**') }}
restore-keys: lfs-
十二、安全与权限
12.1 鉴权
LFS 复用 Git 的鉴权(HTTPS basic / token / SSH)。如果 Git 用 SSH 但 LFS 走 HTTPS:
git config lfs.url https://lfs.example.com/repo.git/info/lfs
12.2 文件锁(独占编辑)
二进制文件无法 merge,常用锁防冲突:
git lfs lock assets/main.psd
# 编辑...
git push
git lfs unlock assets/main.psd
.gitattributes 标记可锁文件:
*.psd lockable
12.3 Hook:禁止超大文件入库
.husky/pre-commit 或 pre-commit 框架:
#!/usr/bin/env bash
MAX=10485760 # 10MB
files=$(git diff --cached --name-only --diff-filter=AM)
for f in $files; do
if [ -f "$f" ]; then
sz=$(wc -c < "$f")
if [ $sz -gt $MAX ] && ! git check-attr filter "$f" | grep -q lfs; then
echo "❌ $f ($sz bytes) > 10MB 但未走 LFS"
exit 1
fi
fi
done
12.4 敏感文件
LFS 不加密。机密数据用 git-crypt / SOPS / 单独密管系统,不要塞进 LFS。
十三、性能调优
13.1 并发上传
git config lfs.concurrenttransfers 16 # 默认 8
13.2 自定义传输 chunk 大小
git config lfs.tustransfers true # 启用 tus 协议(断点续传)
git config lfs.batch.size 100 # 单 batch 文件数
13.3 本地缓存清理
git lfs prune # 清理 unreachable
git lfs prune --verify-remote # 与远端校验后再清
git lfs prune --recent --recent-refs-days=30 # 保留最近 30 天
13.4 对象去重(macOS APFS)
git lfs dedup
# 用 clonefile() 把多 worktree 间相同 LFS 对象做 CoW,省盘
13.5 加速大仓库克隆
git clone --no-checkout <url>
cd repo
git lfs install --local
git lfs pull --include="path/I/need/*"
git checkout
十四、常见问题
14.1 推送时报 bad object
通常是 .gitattributes 被加进去时已有大文件被普通提交:
# 把历史中的大文件迁入 LFS
git lfs migrate import --include="*.psd" --everything
git push --force --all
14.2 文件没走 LFS
git check-attr -a path/to/file
# 应包含 filter: lfs
如果不是:
.gitattributes模式不匹配 → 修正- 文件在跟踪规则之前就被 add →
git lfs migrate import
14.3 克隆速度慢
GIT_LFS_SKIP_SMUDGE=1 git clone <url>
# 只取必要的:
git lfs pull --include="必要路径"
14.4 GitHub LFS bandwidth quota exceeded
- 自建 LFS 中转
- 把大文件搬到 S3/HF Hub
- 临时购 data pack
14.5 .gitattributes 改了不生效
git rm --cached -r .
git add .
git commit -m "re-apply attributes"
或对单文件:
git add --renormalize <file>
14.6 无法 push 大文件
报 request entity too large:
- 自建 server:调 nginx
client_max_body_size - 公开平台:拆分文件或减包大小
14.7 LFS 对象损坏
git lfs fsck
git lfs fetch --all
14.8 离线/无网环境拷贝
LFS 对象在 .git/lfs/objects/,整个目录拷过去即可,对方 git lfs install 后能直接用。
14.9 与 Git submodule 配合
子模块各自有独立 LFS 配置,需分别 git lfs install。
git submodule update --init --recursive
git submodule foreach --recursive git lfs pull
十五、替代方案对比
| 工具 | 适用 | 与 LFS 区别 |
|---|---|---|
| Git LFS | 二进制资产、零散大文件 | 内嵌 Git 工作流 |
| DVC | 数据科学 / 模型 | 元数据走 Git,数据走对象存储;天然支持版本化数据集 |
| git-annex | 极大文件、跨多存储 | 灵活但学习曲线陡 |
| Hugging Face Hub | 模型、数据集 | 公开/私有 repo,配额慷慨,模型生态完善 |
| S3 + 命名约定 | 简单场景 | 无版本协同 |
15.1 LFS vs DVC
| LFS | DVC | |
|---|---|---|
| 学习成本 | 低 | 中 |
| 数据 pipeline | 无 | 有(dvc.yaml) |
| 实验跟踪 | 无 | 有 |
| 后端 | 自建/平台 | S3/GCS/Azure/SSH/HDFS |
| Git 工作流融合 | 完全融合 | 半融合 |
经验:前端/产品团队 → LFS;数据/算法团队 → DVC 或 HF Hub。
15.2 模型权重的最佳实践
- 训练实验:DVC + S3
- 上架候选:Hugging Face private repo
- 生产部署:单独 model registry(MLflow/SageMaker)+ object storage
- 不要把 GB 级 checkpoints 塞进通用代码仓库的 LFS
附录:速查
A.1 配置一个新仓库(黄金路径)
git lfs install
git lfs track "*.psd" "*.mp4" "*.safetensors"
git add .gitattributes
git commit -m "configure LFS"
# 后续正常 add / commit / push
A.2 检查体积分布
git lfs ls-files --size | sort -k3 -hr | head
A.3 关键环境变量
| 变量 | 作用 |
|---|---|
GIT_LFS_SKIP_SMUDGE=1 | 克隆不下载 LFS |
GIT_LFS_PROGRESS=/path/log | 进度记录 |
GIT_LFS_FORCE_PROGRESS=1 | CI 中也显示进度 |
LFS_DEBUG=1 | 调试日志 |
A.4 资源链接
- 官网:git-lfs.com
- 规范:github.com/git-lfs/git…
- giftless:github.com/datopian/gi…
- BFG:rtyley.github.io/bfg-repo-cl…
- git-filter-repo:github.com/newren/git-…