Git 大文件的未来,依然是 Git
原文由 Tyler Cipriani 于 发布,订阅该博客
如果说 Git 有什么天敌,那一定是大文件。
大文件会撑爆 Git 的存储,拖慢 git clone 的速度,还会让 Git 托管平台不堪重负。
2015 年,GitHub 发布了 Git LFS——一个用来绕过大文件问题的 Git 扩展。但 Git LFS 也带来了新的复杂性和存储成本。
与此同时,Git 项目一直在悄悄攻关大文件问题。虽然 LFS 还没死,但最新版 Git 已经指明了一条道路——在不远的将来,LFS 终将被淘汰。
今天你就能做的事:用 Git 部分克隆替代 Git LFS
Git LFS 的原理是将大文件存储在仓库之外。
通过 LFS 克隆项目时,你会拿到仓库的历史记录和小文件,但会跳过大文件。取而代之,Git LFS 只会下载你当前工作区所需的大文件。
2017 年,Git 项目引入了部分克隆,它能提供与 Git LFS 相同的好处:
部分克隆让我们可以在 clone 和 fetch 期间避免预先下载[大型二进制资源],从而缩短下载时间、减少磁盘占用。
—— 部分克隆设计说明,git-scm.com
Git 的部分克隆和 LFS 都能带来:
- 更小的检出——克隆时,你拿到的是大文件的最新一份拷贝,而不是每一份历史拷贝。
- 更快的克隆——由于无需下载大文件,每次克隆都很快。
- 快速就绪——与浅克隆不同,你仍然拥有项目的完整历史,可以马上投入工作。
什么是部分克隆?
Git 部分克隆就是带 --filter 参数的克隆。
例如,要避免下载大于 100KB 的文件,可以这样操作:
git clone --filter='blobs:size=100k' <repo>之后,Git 会在你检出需要时,再按需惰性下载超过 100KB 的文件。
默认情况下,如果我用 git clone 克隆一个包含某个烦人的 25MB PNG 文件众多版本的仓库,克隆会很慢,检出的体积也会大得离谱:
$ time git clone https://github.com/thcipriani/noise-over-git
Cloning into '/tmp/noise-over-git'...
...
Receiving objects: 100% (153/153), 1.19 GiB
real 3m49.052s检出单个 25MB 文件竟然要将近四分钟!
$ du --max-depth=0 --human-readable noise-over-git/.
1.3G noise-over-git/.
$ ^ 🤬而这一个 25MB 文件的 50 个版本就占掉了 1.3GB 空间。
但部分克隆可以绕开这些问题:
$ git config --global alias.pclone 'clone --filter=blob:limit=100k'
$ time git pclone https://github.com/thcipriani/noise-over-git
Cloning into '/tmp/noise-over-git'...
...
Receiving objects: 100% (1/1), 24.03 MiB
real 0m6.132s
$ du --max-depth=0 --human-readable noise-over-git/.
49M noise-over-git/
$ ^ 😻 (the same size as a git lfs checkout)我的过滤条件让克隆速度提升了 97%(3m 49s → 6s),检出体积也缩小了 96%(1.3GB → 49M)!
不过,这里还是有一些注意事项。
如果你运行的命令需要用到被过滤掉的数据,Git 就得去服务器上拉取。因此,像 git diff、git blame 和 git checkout 这类命令,执行时都需要向 Git 托管平台请求数据。
但对于大文件来说,这和 Git LFS 的行为是一样的。
再说了,我可不记得自己上次对 PNG 文件跑 git blame 是什么时候了 🙃。
何必这么折腾?Git LFS 有什么问题?
Git LFS 把 Git 处理大文件的问题转嫁给了用户。
而且问题还不小:
- 🖕 高度的厂商锁定——GitHub 编写 Git LFS 时,其他大文件系统——Git Fat、Git Annex 和 Git Media——在服务端上都是中立的。但 GitHub 却把用户锁定在了自家的私有服务端实现上,还要为此收费。1
- 💸 成本高昂——GitHub 能胜出,是因为它让用户可以免费托管仓库。但 Git LFS 一开始就是付费产品。如今虽然有了免费额度,定价却完全取决于 GitHub 的心情。如今在 GitHub 上存放一个 50GB 的仓库,存储费就要 40 美元/年,而在 Amazon S3 标准存储上存 50GB 只要 13 美元/年。
- 😰 难以撤销——一旦迁移到 Git LFS,不重写历史就无法撤销。
- 🌀 持续的配置成本——所有协作者都得安装 Git LFS。没装的话,他们拿到的就不是预期的大文件,而是让人一头雾水的、塞满元数据的文本文件。
未来:Git 大对象承诺者
大文件也会给 Git 托管平台带来麻烦。
GitHub 和 GitLab 都对文件大小做了限制2,因为大文件的托管成本更高。Git LFS 通过把大文件卸载到 CDN 来降低服务端的成本。
但 Git 项目已经有了新的解决方案。
今年早些时候,Git 合并了一项新功能:大对象承诺者。大对象承诺者旨在提供与 LFS 相同的服务端收益,同时免去给用户带来的麻烦。
这项工作尤其旨在改善服务端的情况,特别是针对那些已经以二进制格式压缩过的大型 blob。
这项工作旨在提供 Git LFS 的替代方案
—— 大对象承诺者,git-scm.com
什么是大对象承诺者?
大对象承诺者是只存放大文件的特殊 Git 远端。
在那个光明美好的未来,大对象承诺者将这样工作:
- 你把大文件推送到 Git 托管平台。
- 后台,Git 托管平台会把这个大文件卸载到大对象承诺者上。
- 当你克隆时,Git 托管平台会把承诺者的信息告诉你的 Git 客户端。
- 你的客户端会从 Git 托管平台克隆,并自动魔法般地从承诺者远端获取大文件。
但距离那个光明美好的未来,我们还有一段路要走。
Git 大对象承诺者仍在开发中。相关代码已在2025 年 3 月合并到 Git 中。但还有更多工作要做,也有不少悬而未决的问题有待解答。
所以就目前而言,处理超大文件你还是得靠 Git LFS。但一旦大对象承诺者得到广泛采用,也许 GitHub 就会允许你推送大于 100MB 的文件了。
Git 中大文件的未来,依然是 Git。
Git 项目正在为大文件问题绞尽脑汁,这样你就不用操心了。
今天,我们还得靠 Git LFS。
但很快,在 Git 里存放大文件的唯一阻碍,就只剩下你那隐隐约约、不祥的直觉——把整个 MP3 曲库塞进 Git 似乎不是什么好主意。
由 Refactoring English 编辑
后来,其他 Git 托管平台也做了自己的 LFS 服务端。如今,你可以推送到多个 Git 托管平台或使用 LFS 传输代理,但这些都会让协作者的配置变得更复杂。除非你额外下功夫去解锁,否则基本还是被锁定的状态。↩︎
文件大小限制:GitHub 100MB,GitLab.com 100MB↩︎
随机一篇博客
评论
登录后参与讨论