Concepts

Git LFS 深入

深入理解 Git LFS 的架构原理、性能调优、服务端配置与大规模迁移策略。

适合谁看
  • 想先理解历史图再看命令的人
前置知识
  • 知道提交不是文件快照列表那么简单
常见风险
  • 把概念页当命令说明页使用

架构原理

Git LFS(Large File Storage)通过指针文件替换大文件,将实际内容存储在独立的对象存储中。指针文件仅有几十字节,而大文件按需下载。

指针文件结构

version https://git-lfs.github.com/spec/v1
oid sha256:4a7c7f... (64 位十六进制哈希)
size 471859200

只有 LFS 客户端能识别和解析指针文件。没有安装 LFS 的 Git 客户端只能看到指针文本。

工作流程

flowchart LR
  A[git add bigfile.psd] --> B[LFS 拦截文件]
  B --> C[将原内容存到 .git/lfs/objects/]
  B --> D[将指针文件写入 index]
  D --> E[git commit]
  E --> F[git push]
  F --> G[LFS 内容推送到 LFS 服务器]
  F --> H[指针文件推送到 Git 服务器]

服务端配置

GitHub

# 每个仓库最多 2GB LFS 存储(免费)
# 支持 S3 兼容对象存储

GitLab

# /etc/gitlab/gitlab.rb
gitlab_rails['lfs_enabled'] = true
gitlab_rails['lfs_storage_path'] = "/var/opt/gitlab/lfs-objects"

# 使用对象存储
gitlab_rails['object_store']['enabled'] = true
gitlab_rails['object_store']['remote_directory'] = 'gitlab-lfs'
gitlab_rails['object_store']['connection'] = {
  'provider' => 'AWS',
  'region' => 'us-east-1',
  'aws_access_key_id' => 'AWS_ACCESS_KEY',
  'aws_secret_access_key' => 'AWS_SECRET_ACCESS_KEY'
}

Gitea

[server]
LFS_START_SERVER = true
LFS_JWT_SECRET = your-secret-key
LFS_CONTENT_PATH = /data/git/lfs

性能调优

按需下载(Smudge 策略)

# 默认:检出时下载 LFS 文件
git config --global lfs.fetchinclude "*.psd,*.bin"
git config --global lfs.fetchexclude "*.zip,*.tar.gz"

# Skipping smudge:检出时不下载,按需获取
GIT_LFS_SKIP_SMUDGE=1 git clone https://github.com/user/repo.git
cd repo
git lfs pull --include="*.psd"

缓存与并行

# 启用并行上传/下载
git config --global lfs.concurrenttransfers 8

# 设置传输缓存
git config --global lfs.cache-url https://lfs-cache.example.com

文件清理

# 查看 LFS 使用情况
git lfs ls-files --size
git lfs ls-files --all

# 清理旧的 LFS 对象(根据指针引用的 prune)
git lfs prune
git lfs prune --dry-run  # 预览

迁移策略

将已有大文件迁移到 LFS

# 迁移特定文件类型
git lfs migrate import --include="*.psd,*.bin" --everything

# 迁移指定大小的文件
git lfs migrate import --above=10MB --everything

迁移后检查

# 验证迁移成功
git lfs fsck --pointers
git lfs ls-files --all | wc -l

# 清理原始大文件引用
git reflog expire --expire-unreachable=now --all
git gc --prune=now

批量迁移脚本

#!/bin/bash
# 批量迁移多个仓库
for repo in repo-a repo-b repo-c; do
  cd $repo
  git lfs migrate import --include="*.psd,*.bin" --everything
  git push --force origin main
  cd ..
done

最佳实践

  1. 尽早引入 LFS:仓库越小迁移成本越低
  2. 精确的文件匹配:用 --include 明确文件类型,避免误匹配
  3. 定期清理:运行 git lfs prune 移除本地不需要的对象
  4. CI 优化:在 CI 中使用 GIT_LFS_SKIP_SMUDGE=1 避免不必要的下载
  5. 备份 LFS 存储:LFS 对象存储需要独立备份策略

继续学习

  1. concepts/git-lfs — Git LFS 基础概念
  2. concepts/git-hooks-deep — Git Hooks 深入
  3. performance/large-repo-optimization — 大型仓库优化