在 AI/机器学习项目中,我们经常需要把模型权重、数据集、图片或音频文件纳入版本控制。直接使用 git add 添加一个几 GB 的 .safetensors 文件,很快就会发现仓库越来越大、clone 越来越慢,甚至被托管平台拒绝推送。Git LFS(Large File Storage)正是为了解决这个问题。本文介绍它的工作原理、日常用法、迁移、CI、托管、自托管和替代方案。
1. 为什么需要 Git LFS
1.1 Git 处理大文件的困难
Git 是一种内容寻址的快照系统:每个文件的每个版本都会作为 blob 对象存入 .git/objects,并由内容哈希索引。这种设计适合源代码,但大型二进制文件会带来几个问题:
- 历史会保留旧版本。 文件一旦提交就会留在历史中,之后删除文件也不会从现有 clone 中移除这些对象。一个 2 GB 的模型有十个版本,未压缩时可能占约 20 GB。
- 差异压缩通常效果有限。 Git 会尝试在 packfile 中对相近 blob 做 delta 压缩。文本文件效果很好,但图片、视频和模型权重等压缩二进制格式通常会整体变化,难以有效压缩。
- 普通 clone 会下载历史。 默认的
git clone会获取可达历史及其对象,包括当前可能用不到的旧版本。 - 托管平台有限制。 许多平台限制单个文件大小。例如 GitHub 会阻止普通 Git 文件超过 100 MiB。
1.2 Git LFS 的核心思路
Git LFS 在 Git 仓库中保存一个很小的文本指针文件,把真实文件内容存放在 LFS 服务器上。
LFS 服务器不是 Git 内置的。Git 负责版本控制,另一个实现 Git LFS API 的服务负责保存 LFS 对象。最常见的方式是使用托管平台内置的 LFS 服务,例如 GitHub、GitLab、Gitea/Forgejo、Bitbucket 和 Hugging Face;它们与仓库共用地址和访问控制。客户端通常能根据 Git remote URL 推导出 LFS endpoint(见第 2.3 节)。你也可以选择内置 LFS 的自托管 Git 服务,或另行部署独立 LFS 服务器。
只通过 SSH 访问的裸仓库,例如 ssh://server/srv/repo.git,只提供 Git,没有 LFS 服务器。除非另行提供 LFS endpoint,否则推送 LFS 文件会失败。
- 添加文件时,Git LFS 把真实内容存入本地 LFS 缓存,并向 Git 提供指针;推送时再上传 LFS 对象。
- 检出指针时,Git LFS 获取对应内容并写入工作区。是否立即下载取决于客户端设置;也可以先跳过,再运行
git lfs pull。
因此,Git 历史保存的是小型指针,普通 Git 对象的下载量和仓库大小会减少。LFS 数据仍单独存储,也有自己的传输和存储成本。
2. 工作原理
2.1 指针文件格式
由 LFS 管理的文件,在 Git 对象库中实际存放的是这样的文本文件:
version https://git-lfs.github.com/spec/v1
oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393
size 12345
| 字段 | 含义 |
|---|---|
version | 指针规范版本,目前为 spec/v1。 |
oid | 原始文件内容的 SHA-256 哈希,也是 LFS 对象的唯一标识。 |
size | 原始文件的字节数。 |
由于对象 ID 是内容哈希,完全相同的文件即使出现在不同路径和提交中也只需存一份。文件哪怕只改动一个字节,也会产生一个全新的完整对象;这对配额和替代方案很重要。
可以查看 Git 中保存的指针:
# 查看 HEAD 中该路径在 Git 对象库里的实际内容(即指针)
git cat-file -p HEAD:models/model.safetensors
# 或用 LFS 命令解析指针
git lfs pointer --file=models/model.safetensors
2.2 Clean 与 Smudge Filter
Git LFS 没有修改 Git 本身,而是使用 Git 内置的 filter 机制,在工作区和对象库之间转换文件。filter driver 有两个方向:
| 方向 | 触发时机 | 作用 |
|---|---|---|
| clean | git add:工作区到暂存区/对象库 | 把工作区内容转换为存入 Git 的形式。 |
| smudge | checkout:对象库到工作区 | 把 Git 中保存的内容转换为工作区需要的形式。 |
两个命令都从标准输入读取文件内容,再把转换结果写入标准输出。Git 负责调用它们,但不关心具体转换方式。
设置 filter 需要两部分:
- 在 Git 配置(
.git/config或~/.gitconfig)中定义 filter 命令。 - 在
.gitattributes中指定哪些路径使用该 filter。
下面是一个与 LFS 无关的例子:把提交到 Git 的配置文件中的密码替换掉,但在本地仍保留原文:
# .git/config
[filter "hidepass"]
clean = sed -e 's/^password = .*/password = REDACTED/'
smudge = cat
# .gitattributes
config.ini filter=hidepass
filter 命令不会随仓库分发:.gitattributes 会提交,但 .git/config 不会。如果协作者没有配置对应的 filter,Git 可能会把文件原样加入普通 Git 历史,而不是存成指针。因此需要在使用 LFS 的用户账户上安装 Git LFS 并运行 git lfs install。
Git 比较和存储的是 clean filter 的输出。工作区里的文件内容本身不是 Git 对象库记录的内容。
Git LFS 如何使用 filter
Git LFS 用 clean 把大文件换成指针,用 smudge 把指针换回原文件。运行 git lfs install 后,全局 Git 配置中会有类似设置:
[filter "lfs"]
clean = git-lfs clean -- %f
smudge = git-lfs smudge -- %f
process = git-lfs filter-process
required = true
仓库的 .gitattributes 会选择对应路径:
*.safetensors filter=lfs diff=lfs merge=lfs -text
- clean: 执行
git add时,git-lfs clean计算 SHA-256,将原始文件存入.git/lfs/objects/<oid前两位>/<接下来两位>/<oid>,然后输出供 Git 存为 blob 的指针。 - smudge: checkout 时,
git-lfs smudge读取指针,先检查本地缓存;没有对象时就下载,再把原始内容写进工作区。 process: 保持 filter 进程运行,避免 Git 每处理一个文件就启动一次git-lfs。required = true: 本机已配置的 filter 执行失败时,Git 应让操作失败。它无法替未安装 Git LFS 的协作者配置 filter。diff=lfs: 使用 LFS 的 diff 行为,不尝试对大型二进制内容做普通 diff。merge=lfs: 在适用时使用 LFS merge driver。-text: 关闭换行符转换,避免损坏二进制文件。
git lfs install 还会安装仓库 hook,其中最重要的是 pre-push。Git 更新远端引用前,hook 会上传远端尚未拥有、且这些提交所引用的 LFS 对象。在已有 clone 中运行此命令可以安装或更新对应 hook。
2.3 传输流程与 Batch API
LFS 传输使用独立于 Git 协议的 HTTP API。LFS endpoint 通常从 Git remote URL 推导,例如:
https://git.example.com/user/repo.git → https://git.example.com/user/repo.git/info/lfs
也可以在仓库的 .lfsconfig 中设置 lfs.url,例如让 Git 和 LFS 使用不同的主机。
核心 endpoint 是 Batch API。下载流程大致如下:
Git 客户端 LFS 服务器 对象存储(S3 等)
│ │ │
│ 1. checkout 遇到指针 │ │
│──── POST /objects/batch ────▶│ │
│ {operation: download, │ │
│ objects: [{oid,size}]} │ │
│ │ 2. 验证权限并查找对象 │
│◀──── 200 actions.download ───│ │
│ {href, header, expires_in} │ │
│ │ │
│──────── 3. GET href(可能是预签名 URL)────────────────────▶│
│◀──────────────────────── 4. 文件内容 ─────────────────────│
│ │ │
│ 5. 校验 SHA-256,保存到本地 LFS 缓存和工作区 │
请求大致如下:
POST /user/repo.git/info/lfs/objects/batch
Accept: application/vnd.git-lfs+json
Content-Type: application/vnd.git-lfs+json
{
"operation": "download",
"transfers": ["basic"],
"ref": { "name": "refs/heads/main" },
"objects": [
{ "oid": "4d7a2146...", "size": 12345 }
]
}
服务器会为每个对象返回 action:
- 下载 action 包含
href、需要附带的header和过期时间。 - 上传 action 若对象已存在,可能不会返回;有些服务器还会提供
verifyaction,在上传后要求客户端确认。
这个设计可以批量处理请求,并将控制面与数据面分离:LFS 服务器负责授权和签发 URL,文件字节可以由客户端直接从对象存储或 CDN 传输。
补充说明:
transfers用于协商传输方式。basic使用普通 HTTP PUT/GET;自定义 transfer agent 可以实现分段上传到对象存储等方式。- 使用 SSH remote 时,客户端可以通过 SSH 执行
git-lfs-authenticate获取 HTTP 凭据。Git LFS 3 也支持纯 SSH 传输,但服务器必须实现git-lfs-transfer。 - 排查问题时可运行
GIT_TRACE=1 GIT_CURL_VERBOSE=1 git lfs pull查看请求详情。
3. 日常使用与迁移
3.1 安装并追踪文件
通过平台的软件包管理器安装 Git LFS:
# macOS
brew install git-lfs
# Debian / Ubuntu
sudo apt install git-lfs
# Fedora / RHEL
sudo dnf install git-lfs
# Windows:Git for Windows 已包含 Git LFS
然后初始化 Git 配置:
git lfs install
这个命令会配置 Git 使用 Git LFS,本身不会安装程序。它将 filter 写入用户级 Git 配置;如果在仓库内运行,还会安装或更新仓库 hook。每个用户账户只需运行一次来设置 filter;已有仓库需要安装或修复 hook 时,可在该仓库中再运行一次。
检查全局 filter 配置:
git config --global --get-regexp '^filter\.lfs\.'
常用选项:
| 命令 | 作用范围 |
|---|---|
git lfs install | 当前用户(写入 ~/.gitconfig)。 |
git lfs install --system | 机器上的所有用户(系统级 Git 配置,通常需要管理员/root 权限)。 |
git lfs install --local | 当前仓库(写入 .git/config)。 |
git lfs install --skip-repo | 只写全局配置,不在当前仓库安装 hook。 |
git lfs uninstall | 移除对应配置和 hook。 |
在 CI 中,应在 runner 镜像或工作仓库中明确配置 Git LFS,不要依赖交互式用户的全局配置。
按扩展名或目录追踪文件:
# 给 pattern 加引号,避免 shell 展开 *
git lfs track "*.safetensors"
git lfs track "*.parquet"
# 追踪目录
git lfs track "datasets/**"
# 查看当前规则
git lfs track
git lfs track 会把规则写入 .gitattributes。应提交这个文件,让协作者知道哪些路径使用 LFS:
git add .gitattributes
git add models/model.safetensors
git commit -m "Add model weights via LFS"
git push
常用检查命令:
# 列出当前检出版本中的 LFS 文件(* 表示内容已下载;- 表示只有指针)
git lfs ls-files
# 显示对象大小
git lfs ls-files --size
# 检查暂存区的文件是否作为 LFS 指针存储
git lfs status
# 检查本地 LFS 对象和指针
git lfs fsck
# 显示 endpoint、缓存路径和环境信息
git lfs env
3.2 .gitattributes 常见陷阱
先写规则,再添加文件。 追踪规则只影响之后的 git add。如果文件已作为普通 blob 提交,之后添加规则不会转换旧历史。只想把当前版本转成 LFS 时:
git lfs track "*.bin"
git add --renormalize .
git commit -m "Move *.bin to LFS"
这不会缩小旧历史;要清理历史,请使用第 3.3 节的 git lfs migrate。
pattern 语法与 .gitignore 不完全相同。 .gitattributes 不支持取反(!)。以 / 开头的路径相对于该 .gitattributes 文件。要匹配任意深度的目录,使用 **:
# 只匹配根目录 data/ 下的 CSV
/data/*.csv filter=lfs diff=lfs merge=lfs -text
# 匹配任意目录层级中的 CSV
*.csv filter=lfs diff=lfs merge=lfs -text
# 匹配 assets/ 下的所有文件
assets/** filter=lfs diff=lfs merge=lfs -text
pattern 区分大小写:*.png 不会匹配 IMAGE.PNG。在 macOS 和 Windows 的大小写不敏感文件系统上容易忽略此问题;必要时同时添加两种大小写规则。
不要用 LFS 追踪配置、JSON 或示例 CSV 等小型文本文件。Git 原生处理这些文件更合适,也能保留可读 diff。.gitattributes 本身也不能交给 LFS 追踪;* 这种过宽规则可能匹配到它并破坏配置。
3.3 迁移已有仓库
如果大文件已经作为普通 Git blob 存在,git lfs migrate 可以重写历史并将它们转换为 LFS。
先检查仓库:
# 统计所有 refs 和历史中占空间最大的文件类型
git lfs migrate info --everything --top=10
然后导入选定文件并改写历史:
# 转换所有分支和标签中的这些 pattern
git lfs migrate import --everything --include="*.safetensors,*.bin,*.parquet"
# 或按大小筛选
git lfs migrate import --everything --above=50MB
改写会生成新的提交,因此受影响的 commit ID 都会改变。检查结果后,强制推送被改写的 refs:
git push --force --all
git push --force --tags
改写前务必注意:
- 先备份,例如用
git clone --mirror创建镜像副本。 - 通知协作者。旧分支无法直接与改写后的历史合并;重新 clone 可能更简单。
- 已打开的 PR/MR 可能需要重新创建。
- 服务器上的旧对象可能仍占空间,直到托管平台执行垃圾回收或由客服处理。
不改写已有历史地导入:
# 新建一个提交,将符合已追踪规则的文件转换为 LFS
git lfs migrate import --no-rewrite path/to/large.bin
这种方式保留旧提交,但旧版本仍留在 Git 中。它适合团队中途采用 LFS、又不想打乱现有分支的情况。
从 LFS 导出: 如果停止使用 LFS,可以将匹配的指针转回普通 Git blob:
git lfs migrate export --everything --include="*.png"
4. 进阶技巧
4.1 选择性下载
如果仓库有很多 LFS 对象,而你只需要其中一部分,可以先跳过所有下载,再按需获取:
GIT_LFS_SKIP_SMUDGE=1 git clone https://git.example.com/user/models.git
cd models
# 工作区中是指针;只获取需要的文件
git lfs pull --include="llama-8b/*"
设置长期使用的包含和排除规则后,之后的 pull 和 checkout 也会遵循这些规则:
git config lfs.fetchinclude "configs/*,small-model/*"
git config lfs.fetchexclude "datasets/raw/*"
git lfs fetch --recent 还会获取近期分支和近期提交引用的对象。可用 lfs.fetchrecentrefsdays 和 lfs.fetchrecentcommitsdays 调整时间范围,便于提前缓存可能切换到的分支以供离线使用。
Git 原生 partial clone 也可以减少普通 Git 对象的下载量:
git clone --filter=blob:none https://git.example.com/user/repo.git
4.2 清理本地缓存
.git/lfs/objects 可能保留曾检出过的每个版本,时间久了会比工作区还大。git lfs prune 会删除本地不再需要的对象。它会保留当前检出版本、近期引用、stash、其他 worktree 和未推送的对象;具体行为取决于近期保留设置和 remote。
先预览清理结果,再确认远端确实有可达对象后删除本地副本:
# 预览将清理的内容
git lfs prune --dry-run --verbose
# 删除前向远端确认可达对象存在
git lfs prune --verify-remote
prune 只清理本地缓存,不会减少服务器储存量。服务器对象保留和垃圾回收方式取决于平台。改写历史后,旧对象也可能继续存在,直到平台执行垃圾回收;有些平台需要删除仓库或联系支持人员才能释放空间。
4.3 文件锁定
二进制文件不能像源代码那样合并。两个人同时修改同一个 Photoshop 文件或 Unity 场景时,其中一人的成果可能丢失。Git LFS 文件锁定可以帮助协调编辑:
# 标记匹配路径可锁定
git lfs track "*.psd" --lockable
lockable 属性会让检出的文件变为只读,获取锁后才能编辑:
git lfs lock design/banner.psd # 获取锁;文件变为可写
git lfs locks # 查看锁
git lfs unlock design/banner.psd # 修改并推送后解锁
git lfs unlock --force design/banner.psd # 管理员强制解锁
锁定验证需要服务器支持 Locking API。按 Git LFS 文档配置 lfs.<url>.locksverify。启用后,pre-push hook 会询问服务器,确认即将推送的文件是否被其他人锁定。依赖这套流程前,先确认所用平台支持文件锁定。纯代码或 ML 项目通常用不到;游戏和设计资产则可能受益。
4.4 在 CI 中使用
CI 任务可能反复下载 LFS 对象。只在任务确实需要文件时启用 LFS checkout。GitHub Actions 的 actions/checkout 提供 lfs: true:
steps:
- uses: actions/checkout@v4
with:
lfs: true
如果要缓存 .git/lfs,缓存键应反映任务需要的对象。只按分支或文件名生成的键可能会在文件更新后复用旧内容。确保 checkout 和缓存步骤顺序正确,并用 git lfs fsck 或工作流中的内容哈希检查确认恢复的对象。lint 和文档任务若不需要二进制文件,就跳过 LFS 下载。
其他建议:
- 只下载任务需要的文件,例如
git lfs pull --include="tests/fixtures/*"。 - 不要在不使用大文件的任务中 pull LFS 对象。
- 自托管 runner 可以保留持久缓存,并用
lfs.storage指向它。
5. 托管与自托管
5.1 托管平台
GitHub
GitHub 的单文件限制、储存和带宽额度取决于方案,也可能变化。下载流量计入仓库拥有者的额度;fork 流量也可能由上游仓库承担。请查看 GitHub 当前的 LFS 配额与限制,并计算 CI 重复下载的流量。
GitLab
GitLab 支持 LFS。自托管实例可以配置 LFS 对象储存,包括外部对象储存服务。GitLab.com 的储存和流量规则取决于方案与命名空间设置,请参阅当前的 LFS 对象储存文档。
Hugging Face Hub
Hub 现在使用 Xet 作为大型文件储存后端,同时维持 Git 与 Git LFS 指针的兼容路径。Git LFS 按完整文件识别对象;Xet 支持区块级去重。要使用 Xet 的传输优化,请按照 Hub 文档安装并配置支持 Xet 的客户端。不同客户端和版本的行为可能不同。
5.2 自托管 LFS 服务器
自托管可以避开第三方方案的特定配额,但储存、备份、带宽、可用性和运维仍然有成本。常见选择:
| 方案 | 适用场景 |
|---|---|
| Gitea / Forgejo | 轻量部署,内置 LFS,并可配置对象储存。 |
| GitLab Self-Managed | 需要 GitLab 集成能力,并能够自行运维 LFS 储存。 |
| 独立 LFS 服务器 | Git 主机不提供 LFS,且愿意自行整合认证、储存和备份。 |
请按照实际部署版本查看 LFS 和对象储存文档。配置名称、存储后端和直连下载行为会因产品与版本而异;不要直接复制其他版本的 app.ini 示例。正式上线前测试 clone、checkout、push、访问控制和备份恢复,并确认客户端能够访问服务器生成的下载 URL。
5.3 反向代理注意事项
自托管 LFS 故障经常来自 Git 服务前面的反向代理。大型 HTTP 请求、请求体大小限制、超时、缓冲和上游连接设置都可能影响传输。应按实际服务器配置代理,并使用接近预期最大值的文件进行验证。
Nginx:
server {
listen 443 ssl;
server_name git.example.com;
# 移除请求体大小限制(默认 1 MB)
client_max_body_size 0;
location / {
proxy_pass http://127.0.0.1:3000;
# 直接转发请求,不先缓冲整个请求体
proxy_request_buffering off;
proxy_buffering off;
# 大文件上传可能需要较长时间
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
如果 Caddy 或其他代理配置了请求体大小限制,请确保 LFS 上传路径允许预期大小,也检查超时和缓冲行为。
使用 CDN 或 tunnel 时,确认服务方案对请求大小、连接时间和上传方式的限制。如果代理不适合传输大型对象,可按 Git 服务支持的方式配置独立 LFS endpoint 或对象储存直传。检查生成的 URL、认证和 TLS;不要把私有储存 endpoint 暴露给未授权的客户端。
排查线索:
- 上传返回
413:请求体大小限制。 - 上传中断并返回
504:超时设置。 - 下载 URL 指向内网地址:检查公开 URL 或对象储存 endpoint 配置。
- 认证失败:检查代理是否转发
Authorizationheader,以及X-Forwarded-Proto的协议是否一致。
6. 故障排查与替代方案
6.1 常见问题
clone 后文件内容是指针文本,而不是真实内容
本机可能没有安装或初始化 Git LFS,也可能是有意跳过了 checkout 下载:
git lfs install
git lfs pull
如果 clone 时设置了 GIT_LFS_SKIP_SMUDGE=1,运行 git lfs pull 获取内容。如果 pull 失败,检查凭据、LFS endpoint、对象是否已上传,以及平台提示的配额状态。
smudge filter lfs failed
checkout 下载 LFS 对象失败。依次检查:
- 网络和凭据:用
git lfs env确认 endpoint,并运行GIT_TRACE=1 git lfs pull查看详情。 - 服务器上是否真的存在对象。有人可能提交了指针,却没有成功上传 LFS 文件,例如在未安装 Git LFS 的环境中操作,或绕过
pre-push。 - 是否用尽储存或带宽配额。
可以先跳过 smudge 完成 checkout,之后再重试:
GIT_LFS_SKIP_SMUDGE=1 git checkout <branch>
Encountered N file(s) that should have been pointers, but weren't
.gitattributes 规则匹配的文件以普通 blob 存在,而不是 LFS 指针。常见原因是协作者在未安装 Git LFS 的机器上提交。可以在当前版本中转换而不改写历史:
git add --renormalize .
git commit -m "Fix files that should be LFS pointers"
也可以改写历史,同时转换旧版本:
git lfs migrate import --everything --include="<pattern>"
大文件已作为普通 Git 对象提交并推送
之后再删除文件并不会缩小仓库。使用 git lfs migrate import 改写历史(见第 3.3 节)。如果尚未推送,可运行 git reset --soft HEAD~1,添加 LFS 追踪规则,再重新添加和提交文件。
推送很慢或看起来卡住
- 运行
git lfs push --dry-run origin main检查对象数量和大小。 - 用
git config lfs.concurrenttransfers 8调整并行传输数。 - 自托管部署检查反向代理的缓冲配置(见第 5.3 节)。
常用诊断命令:
| 命令 | 用途 |
|---|---|
git lfs env | 显示版本、endpoint、缓存路径和配置。 |
git lfs status | 显示暂存区和工作区的 LFS 状态。 |
git lfs ls-files --size | 列出 LFS 文件和大小。 |
git lfs fsck | 检查本地对象完整性。 |
git lfs logs last | 查看最近的错误日志。 |
GIT_TRACE=1 GIT_CURL_VERBOSE=1 | 输出 HTTP 请求详情。 |
6.2 何时不该使用 LFS
Git LFS 适合数量和大小适中的二进制文件,并且这些文件需要与代码一起版本化,例如游戏素材、测试样本和小型模型。其他情况可以考虑:
| 方案 | 适用场景 | 特点 |
|---|---|---|
| Git LFS | 需要与代码同步版本化的中等规模二进制文件 | 生态成熟、平台支持广、日常使用透明。 |
| git-annex | 大量文件、多种存储后端、分布式备份 | 通过符号链接管理内容,并追踪文件所在位置;功能强大但学习成本较高。 |
| DVC | ML 数据集和实验管线 | Git 只存 .dvc 元数据,数据放在 S3/GCS 等远端;还提供管线和实验追踪,不依赖 Git 托管平台。 |
| Hugging Face Hub(Xet) | 公开或团队共享模型和数据集 | 区块级去重适合频繁迭代的大文件,可减少储存和流量。 |
| 对象储存加清单文件 | TB 级且无需细粒度版本历史的数据 | 仓库只保存 URL 和哈希,由脚本下载并校验。 |
选择时可参考以下原则:
- 对频繁小幅修改的文件(例如连续训练产生的模型 checkpoint),LFS 每次都会存一个完整新对象。Xet 等区块去重方案或只保留选定版本可能更合适。
- 数据达到数百 GB 时,托管平台的 LFS 费用可能高于直接使用对象储存。可以比较 DVC 或对象储存加清单文件。
- 需要数据来源追踪和实验管理时,DVC 不只是储存工具。
- 对无需版本历史的文件(例如 build 产物),不要用 LFS;应使用 Release 或软件包仓库。
参考资料
- Git LFS 文档与命令手册
- Git LFS Batch API
- Git LFS 文件锁定 API
- Git LFS migrate 手册
- Git LFS prune 手册
- GitHub LFS 储存与带宽限制
- GitHub Actions checkout 的
lfs输入 - GitLab LFS 对象储存
- Gitea Git LFS 配置
- Hugging Face Hub Xet 储存后端
- Git 属性和 filter driver
总结
Git LFS 使用 Git 的 filter 机制把大文件替换为指针,再通过独立的 HTTP API 传输文件内容。理解 clean/smudge filter 和 Batch API 有助于解释大多数使用与部署问题。先添加 .gitattributes 规则再添加文件,在 CI 中限制下载,并留意平台配额。若选择自托管,还要考虑储存、备份、带宽、反向代理和访问控制:自托管改变了管理容量和成本的方式,但不会消除这些成本。