Git LFS 完整指南

2 阅读10分钟

目录


一、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 statusLFS 文件变更状态
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官方参考实现,仅测试
rudolfsRust 实现,S3 后端
giftlessPython 实现,可对接 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 / Pro1 GB1 GB
Team1 GB1 GB
数据包$5 / 50 GB / 月50 GB

⚠️ 超出后下载会被禁用,必须购买 data pack。fork 也会消耗源仓库带宽。

10.2 GitLab

计划存储
SaaS Free10 GB / 项目
Premium250 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-commitpre-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

LFSDVC
学习成本
数据 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=1CI 中也显示进度
LFS_DEBUG=1调试日志

A.4 资源链接