搜索 K
主题
Git 原生设计不适合管理大文件——每次 clone 都要下载完整历史中的每个版本。Git LFS(Large File Storage)通过将大文件存储在独立服务器来解决这个问题。sparse-checkout 和 partial clone 则从另一个角度优化——只下载需要的部分。
LFS 解决「大文件」问题,sparse-checkout 解决「大仓库(文件多)」问题,partial clone 解决「历史太深」问题。
# LFS 的工作原理:
# 1. 大文件不直接存在 Git 对象中
# 2. Git 仓库中只存一个「指针文件」(~130 字节)
# 3. 实际文件存储在 LFS 服务器上
# 4. checkout 时自动下载需要的文件
# 指针文件的内容:
# version https://git-lfs.github.com/spec/v1
# oid sha256:abc1234def5678...
# size 52428800# 安装
# Windows (Scoop)
scoop install git-lfs
# Windows (Git for Windows 2.x+ 自带)
# 无需额外安装
# macOS
brew install git-lfs
# Linux (Ubuntu/Debian)
sudo apt install git-lfs
# 初始化(每台机器只需运行一次)
git lfs install
# Updated git hooks.
# Git LFS initialized.# 跟踪特定扩展名
git lfs track "*.psd"
git lfs track "*.mp4"
git lfs track "*.zip"
# 跟踪特定目录下的文件
git lfs track "assets/videos/**"
git lfs track "models/*.bin"
# 跟踪特定文件
git lfs track "data/large-dataset.csv"
# 查看当前跟踪规则
git lfs track
# Listing tracked patterns
# *.psd (.gitattributes)
# *.mp4 (.gitattributes)
# assets/videos/** (.gitattributes)
# 取消跟踪
git lfs untrack "*.psd"
# ⚠️ 必须提交 .gitattributes
git add .gitattributes
git commit -m "chore: 配置 Git LFS 跟踪规则"# LFS 文件的日常操作和普通文件完全一样
git add assets/design.psd
git commit -m "feat: 添加设计稿"
git push origin main
# Git 会自动将 LFS 文件上传到 LFS 服务器
# 查看 LFS 文件状态
git lfs status
# Objects to be pushed to origin/main:
# assets/design.psd (LFS: abc1234)
# 查看 LFS 管理的文件列表
git lfs ls-files
# abc1234 * assets/design.psd
# def5678 * assets/video.mp4
# 查看 LFS 文件信息
git lfs pointer --file=assets/design.psd# 正常克隆(自动下载 LFS 文件)
git clone https://github.com/team/project.git
# 跳过 LFS 文件(只下载指针文件)
GIT_LFS_SKIP_SMUDGE=1 git clone https://github.com/team/project.git
# 之后按需拉取
git lfs pull
# 或只拉取特定文件
git lfs pull --include="assets/needed-file.psd"
git lfs pull --include="*.mp4" --exclude="archive/*"
# 获取但不替换工作区文件(预下载)
git lfs fetch
git lfs fetch --recent # 只获取最近引用的文件
git lfs fetch --all # 获取所有版本的 LFS 文件# LFS 支持文件锁定(防止二进制文件的合并冲突)
# 二进制文件无法 merge,所以需要锁定机制
# 锁定文件(其他人无法修改)
git lfs lock assets/design.psd
# Locked assets/design.psd
# 查看已锁定的文件
git lfs locks
# ID Path Owner Locked At
# 1 assets/design.psd Alice 2026-03-08T10:00:00Z
# 解锁文件
git lfs unlock assets/design.psd
# 强制解锁(管理员,释放他人的锁)
git lfs unlock assets/design.psd --force
# 在 .gitattributes 中标记需要锁定的文件类型
# *.psd filter=lfs diff=lfs merge=lfs -text lockable
# 设置 lockable 后,checkout 出的文件默认只读
# 必须先 lock 才能编辑# 默认使用 Git 托管平台的 LFS 服务(GitHub、GitLab 等)
# 为特定仓库指定 LFS 服务器
git config lfs.url https://lfs.company.com/team/repo
# 或在 .lfsconfig 中配置(提交到仓库,团队共享)
cat > .lfsconfig << 'EOF'
[lfs]
url = https://lfs.company.com/team/repo
EOF
git add .lfsconfig
git commit -m "chore: 配置自定义 LFS 服务器"# 将已经在 Git 历史中的大文件迁移到 LFS
# 1. 查看哪些文件应该用 LFS
git lfs migrate info
# migrate: Fetching remote refs: ..., done.
# migrate: Sorting commits: ..., done.
# migrate: Examining commits: 100% (500/500), done.
# *.psd 50 MB 5 files
# *.mp4 200 MB 10 files
# 指定文件大小阈值
git lfs migrate info --above=5mb
# 2. 执行迁移(会重写历史!)
git lfs migrate import --include="*.psd,*.mp4"
# migrate: Fetching remote refs: ..., done.
# migrate: Sorting commits: ..., done.
# migrate: Rewriting commits: 100% (500/500), done.
# main abc1234 -> def5678
# migrate: Updating refs: ..., done.
# 只迁移特定分支
git lfs migrate import --include="*.psd" --include-ref=main
# 3. 强制推送(历史已重写)
git push --force --all
git push --force --tags
# 4. 通知团队重新克隆# 查看 LFS 存储使用量
git lfs env
# Endpoint=https://github.com/team/repo.git/info/lfs (auth=basic)
# LocalMediaDir=/path/to/.git/lfs/objects
# ...
# 清理本地 LFS 缓存
git lfs prune
# prune: 42 local objects, 30 retained, done.
# prune: Deleting objects: 100% (12/12), done.
# 干跑模式
git lfs prune --dry-run
# 验证 LFS 文件完整性
git lfs fsck
# 查看 LFS 对象的本地缓存
ls .git/lfs/objects/| 平台 | 免费存储 | 免费带宽 | 付费方案 |
|---|---|---|---|
| GitHub | 1 GB | 1 GB/月 | $5/50GB 存储+带宽 |
| GitLab | 5 GB | 无限 | 按套餐 |
| Bitbucket | 1 GB | 5 GB/月 | 按套餐 |
| Azure DevOps | 无限 | 无限 | 免费 |
# GitHub 上查看 LFS 使用量
# Settings → Billing → Git LFS Data
# 优化 LFS 带宽
# 1. CI 中跳过 LFS
GIT_LFS_SKIP_SMUDGE=1 git clone <url>
# 2. 只获取需要的文件
git lfs fetch --include="src/assets/icons/*"
# 3. 浅克隆减少历史版本下载
git clone --depth 1 <url># 问题:monorepo 有 10 万个文件,但你只需要 frontend/ 目录
# 解决:sparse-checkout 只检出你需要的目录
# 没有 sparse-checkout:
# clone → 下载所有文件 → 工作区 10 万个文件 → IDE 卡死
# 使用 sparse-checkout:
# clone → 下载所有 Git 对象(历史)→ 只检出指定目录 → 工作区 500 个文件# 初始化 sparse-checkout
git sparse-checkout init
# 设置要检出的目录(cone 模式,推荐)
git sparse-checkout init --cone
git sparse-checkout set frontend/ shared/ docs/
# 查看当前配置
git sparse-checkout list
# frontend/
# shared/
# docs/
# 添加更多目录
git sparse-checkout add backend/api/
# 取消 sparse-checkout(检出所有文件)
git sparse-checkout disable# 1. 克隆时不检出文件
git clone --no-checkout https://github.com/team/monorepo.git
cd monorepo
# 2. 初始化 sparse-checkout
git sparse-checkout init --cone
# 3. 设置要检出的目录
git sparse-checkout set packages/frontend packages/shared
# 4. 检出文件
git checkout main
# 现在工作区只有 packages/frontend/ 和 packages/shared/# 终极优化:partial clone + sparse-checkout
# 不下载不需要的 blob 对象 + 不检出不需要的文件
git clone \
--filter=blob:none \
--sparse \
https://github.com/team/monorepo.git
cd monorepo
git sparse-checkout set packages/frontend packages/shared
# 效果:
# - 克隆速度极快(只下载树对象和提交对象)
# - 工作区只有需要的文件
# - 访问其他文件时按需下载# Cone 模式:基于目录的包含/排除
git sparse-checkout init --cone
# 只能指定目录(不能指定单个文件的模式)
git sparse-checkout set src/ docs/
# 根目录的文件 + src/ + docs/ 会被检出
# 优势:
# - 性能更好(O(1) 匹配而非 O(n))
# - 规则更直观
# - Git 2.37+ 默认模式# Non-cone 模式:支持 gitignore 风格的模式
git sparse-checkout init --no-cone
# 可以使用通配符
git sparse-checkout set \
"/*" \
"!/packages/*" \
"/packages/frontend/" \
"/packages/shared/"
# 或编辑配置文件
# .git/info/sparse-checkout# 1. 无 blob 克隆(最常用)
git clone --filter=blob:none <url>
# 不下载任何文件内容,只下载提交和树对象
# 访问文件时按需下载
# 适合:大型仓库的快速克隆
# 2. 按大小过滤
git clone --filter=blob:limit=1m <url>
# 不下载超过 1MB 的文件
# 适合:仓库中有少量大文件
# 3. 无树克隆(实验性)
git clone --filter=tree:0 <url>
# 不下载任何树对象
# 适合:只需要最新快照
# 4. 浅克隆
git clone --depth 1 <url>
# 只下载最近 1 个提交
# 适合:CI/CD 环境
# 5. 单分支克隆
git clone --single-branch --branch main <url>
# 只克隆指定分支# CI/CD 最优克隆策略
git clone \
--depth 1 \
--single-branch \
--branch main \
--filter=blob:none \
<url>
# 开发者日常使用
git clone \
--filter=blob:none \
--sparse \
<url>
git sparse-checkout set <my-package>
# 浅克隆后获取更多历史
git fetch --unshallow
# 或获取指定深度
git fetch --depth 100# 部分克隆使用 promisor remote
# Git 知道某些对象虽然本地没有,但可以从远程获取
# 查看本地缺失的对象
git rev-list --objects --all --missing=print | grep "^?"
# 手动获取缺失的对象
git fetch origin --filter=blob:none# 文件系统监视器(显著加速 status/diff)
git config core.fsmonitor true # Git 2.37+
git config core.untrackedcache true
# 提交图缓存(加速 log/merge-base/rebase)
git config fetch.writeCommitGraph true
git commit-graph write --reachable
# 多线程操作
git config pack.threads 0 # 自动使用所有核心
git config checkout.workers 0 # 并行检出
git config index.threads true # 并行索引
# 后台维护
git maintenance start
# 打包优化
git config pack.windowMemory 256m # 限制内存使用
git config pack.packSizeLimit 2g # 限制单个 packfile 大小
# 预取(后台提前获取远程数据)
git config fetch.negotiationAlgorithm skipping # 更快的协商算法| 场景 | 推荐方案 |
|---|---|
| 设计资源(PSD/AI/视频) | Git LFS |
| ML 模型/数据集 | Git LFS 或 DVC |
| Monorepo(前端+后端+...) | sparse-checkout + partial clone |
| CI/CD 构建 | --depth 1 --single-branch |
| 历史中有废弃的大文件 | git filter-repo --strip-blobs-bigger-than 10M |
| 仓库已经很大了 | 迁移大文件到 LFS + filter-repo 清理历史 |
| 游戏开发(大量二进制) | Git LFS + 文件锁定 |
# .gitattributes — 游戏项目
# 3D 模型
*.fbx filter=lfs diff=lfs merge=lfs -text lockable
*.obj filter=lfs diff=lfs merge=lfs -text
*.blend filter=lfs diff=lfs merge=lfs -text lockable
# 贴图
*.png filter=lfs diff=lfs merge=lfs -text
*.tga filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text lockable
# 音频
*.wav filter=lfs diff=lfs merge=lfs -text
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
# 视频
*.mp4 filter=lfs diff=lfs merge=lfs -text
# 编译产物
*.dll filter=lfs diff=lfs merge=lfs -text
*.so filter=lfs diff=lfs merge=lfs -text
# 场景/关卡文件
*.unity filter=lfs diff=lfs merge=lfs -text lockable
*.umap filter=lfs diff=lfs merge=lfs -text lockable# 团队有一个大型 monorepo,每个开发者只负责部分代码
# 前端开发者
git clone --filter=blob:none --sparse https://github.com/team/monorepo.git
cd monorepo
git sparse-checkout set packages/web packages/shared configs/
# 后端开发者
git clone --filter=blob:none --sparse https://github.com/team/monorepo.git
cd monorepo
git sparse-checkout set packages/api packages/shared configs/
# 需要看其他包时临时添加
git sparse-checkout add packages/mobile
# 不需要了再移除
git sparse-checkout set packages/api packages/shared configs/# GitHub Actions — 优化 LFS 使用
# 方案 1:跳过 LFS(如果构建不需要大文件)
- uses: actions/checkout@v4
with:
lfs: false
# 方案 2:缓存 LFS 文件
- uses: actions/checkout@v4
with:
lfs: true
- name: Cache LFS objects
uses: actions/cache@v4
with:
path: .git/lfs
key: lfs-${{ hashFiles('.gitattributes') }}
# 方案 3:只获取需要的 LFS 文件
- uses: actions/checkout@v4
with:
lfs: false
- name: Fetch specific LFS files
run: |
git lfs fetch --include="assets/icons/*"
git lfs checkout#!/bin/bash
# migrate-to-lfs.sh — 将现有仓库迁移到 LFS
echo "🔍 分析仓库中的大文件..."
git lfs migrate info --above=5mb --top=20
echo ""
read -p "确认迁移?这会重写历史!(y/N): " CONFIRM
if [ "$CONFIRM" != "y" ]; then
echo "取消迁移"
exit 0
fi
echo ""
echo "📦 执行迁移..."
git lfs migrate import \
--include="*.psd,*.ai,*.sketch" \
--include="*.mp4,*.mov,*.avi" \
--include="*.zip,*.tar.gz" \
--include="*.bin,*.dat,*.model"
echo ""
echo "🧹 清理..."
git reflog expire --expire=now --all
git gc --prune=now --aggressive
echo ""
echo "📊 迁移后仓库大小:"
git count-objects -vH
echo ""
echo "⚠️ 下一步操作:"
echo " 1. git push --force --all"
echo " 2. git push --force --tags"
echo " 3. 通知团队重新克隆"
echo " 4. 在 GitHub/GitLab 上清理服务端缓存"# ❌ track 了 LFS 但没有提交 .gitattributes
git lfs track "*.psd"
git add assets/design.psd
git commit -m "add design"
# 文件被当作普通文件提交了!
# ✅ 先提交 .gitattributes
git lfs track "*.psd"
git add .gitattributes
git commit -m "chore: 配置 LFS"
git add assets/design.psd
git commit -m "feat: 添加设计稿"# GitHub 免费只有 1GB 存储 + 1GB/月带宽
# 频繁 CI clone 会快速消耗带宽
# ✅ 解决方案:
# 1. CI 中跳过 LFS
GIT_LFS_SKIP_SMUDGE=1 git clone <url>
# 2. 缓存 LFS 对象
# 3. 使用自建 LFS 服务器
# 4. 定期清理旧版本 LFS 文件# sparse-checkout 隐藏的文件不在工作区中
# 但 Git 仍然跟踪它们!
# ❌ 以为文件不存在就创建同名文件
# 可能导致冲突
# ✅ 查看完整的文件列表
git ls-tree -r HEAD --name-only# 二进制文件(PSD、MP4)无法 diff
# 两个人同时修改同一个 PSD 会冲突且无法自动合并
# ✅ 使用文件锁定
git lfs lock assets/design.psd
# 编辑...
git add assets/design.psd
git commit -m "update design"
git lfs unlock assets/design.psd# 浅克隆不能:
# - git log(只能看到有限的历史)
# - git blame(可能不完整)
# - git bisect(范围受限)
# - push 到新仓库(可能被拒绝)
# ✅ 需要完整历史时
git fetch --unshallowgit lfs track 命令实际上是在 .gitattributes 中添加规则。LFS 通过 Git 的 filter 属性实现——clean 过滤器在 add 时将文件替换为指针,smudge 过滤器在 checkout 时将指针替换为实际文件。
| 特性 | 浅克隆 --depth | 部分克隆 --filter |
|---|---|---|
| 限制内容 | 历史深度 | 对象类型/大小 |
| 按需获取 | 需要 --unshallow | 自动按需获取 |
| 适用场景 | CI/CD、快速查看 | 日常开发 |
| Git 版本 | 一直支持 | Git 2.22+ |
不会。git status 只显示已检出的文件的状态。未检出的文件既不会显示为已修改也不会显示为已删除。
# 本地 LFS 缓存大小
du -sh .git/lfs/
# GitHub 上查看
# Settings → Billing → Git LFS Data
# 清理本地缓存
git lfs prune# Windows 上 LFS 可能较慢,优化方法:
git config lfs.concurrenttransfers 8 # 增加并行下载数
git config lfs.transfer.maxretries 5 # 增加重试次数
git config core.longpaths true # 支持长路径| 目标 | 命令 |
|---|---|
| 安装 LFS | git lfs install |
| 跟踪文件类型 | git lfs track "*.psd" |
| 查看跟踪规则 | git lfs track |
| 取消跟踪 | git lfs untrack "*.psd" |
| 查看 LFS 文件列表 | git lfs ls-files |
| 查看 LFS 状态 | git lfs status |
| 拉取 LFS 文件 | git lfs pull |
| 按需拉取 | git lfs pull --include="*.psd" |
| 跳过 LFS 克隆 | GIT_LFS_SKIP_SMUDGE=1 git clone <url> |
| 锁定文件 | git lfs lock <file> |
| 解锁文件 | git lfs unlock <file> |
| 迁移到 LFS | git lfs migrate import --include="*.psd" |
| 清理本地缓存 | git lfs prune |
| 验证完整性 | git lfs fsck |
| 目标 | 命令 |
|---|---|
| 初始化 | git sparse-checkout init --cone |
| 设置检出目录 | git sparse-checkout set dir1/ dir2/ |
| 添加目录 | git sparse-checkout add dir3/ |
| 查看配置 | git sparse-checkout list |
| 禁用 | git sparse-checkout disable |
| 目标 | 命令 |
|---|---|
| 无 blob 克隆 | git clone --filter=blob:none <url> |
| 按大小过滤 | git clone --filter=blob:limit=1m <url> |
| 浅克隆 | git clone --depth 1 <url> |
| 单分支克隆 | git clone --single-branch -b main <url> |
| 组合优化 | git clone --filter=blob:none --sparse <url> |
| 获取完整历史 | git fetch --unshallow |