git LFS 如何比 git 更有效地跟踪和存储二进制数据



我知道 git LFS 导致 git在文本文件中存储一个字符串"指针",然后 git LFS 下载该目标二进制文件。这样,远程 git 服务器上的 git 存储库会更小。但是,git LFS 仍然必须存储二进制文件,所以在我看来,本地存储(git lfs pull后)没有什么不同,远程 git LFS 服务器数据加上远程 git 数据的总和仍然相似。

我错过了什么?git LFS 如何有效地跟踪二进制文件?


更新(在写这个问题后经过额外的学习):不要使用git lfs。我现在建议不要使用git lfs

另请参阅:

  1. 我在我接受的答案下方的评论
  2. 我自己的答案,我刚刚在下面添加

我从这个问题开始,因为我相信 Git LFS 是惊人的和美妙的,我想知道怎么做。相反,我最终意识到 Git LFS 是常工作流程问题的原因,我不应该再使用它或推荐它。

总结:

正如我在这里所说:

对于

个人、免费的 GitHub 帐户来说,它的限制太大了,而对于付费的公司帐户,它使git checkout从几秒钟变成高达 3+小时,尤其是对于远程工作者来说,这完全是浪费他们的时间。我处理了三年,这太可怕了。我写了一个脚本,每晚做一次git lfs fetch来缓解这种情况,但我的雇主拒绝给我买一个更大的 SSD,给我足够的空间让我每晚做一次git lfs fetch --all,所以我仍然经常遇到几个小时结账的问题。除非删除整个 GitHub 存储库并从头开始重新创建它,否则也无法撤消将git lfs集成到存储库中的集成。

详:

我刚刚发现git lfs的免费版本有如此严格的限制,以至于它毫无用处,我现在正在将其从我所有的公共免费存储库中删除。请参阅此答案(GitHub.com 的存储库大小限制)并搜索"git lfs"部分。

在我看来,git lfs的唯一好处是,当您克隆存储库时,它可以避免一次下载大量数据。就是这样!对于任何总内容大小(git repo + 可能的 git lfs 存储库)<2 TB 左右的存储库来说,这似乎是一个非常小的好处,如果不是无用的话。使用git lfs所做的只是

  1. git checkout永远花几个小时(不好)
  2. 使我通常快速和离线的 git 命令,就像现在git checkout变成在线和慢速 git 命令(坏),以及
  3. 充当另一个 GitHub 服务来支付(坏)。

如果您尝试使用git lfs来克服 GitHub 的 100 MB 最大文件大小限制,就像我一样,请不要!您几乎会立即耗尽git lfs空间,特别是如果有人克隆或分叉您的存储库,因为这会影响您的限制,而不是他们的限制!相反,"可以使用诸如tarplussplit之类的工具,或者单独split,将大文件拆分为较小的部分,例如每个 90 MB"(源),以便您可以将这些二进制文件块提交到常规git存储库。

最后,GitHub上停止使用git lfs并再次完全释放该空间的"解决方案"绝对是疯狂的!您必须删除整个存储库!在这里查看此问答:如何删除 git-lfs 跟踪的文件并释放存储配额?

GitHub的官方文档证实了这一点(着重号是加的):

从 Git LFS 中删除文件后,Git LFS对象仍存在于远程存储上,并将继续计入 Git LFS 存储配额。

要从存储库中删除 Git LFS 对象,请删除并重新创建存储库。删除存储库时,任何关联的问题、星号和复刻也会被删除。

我不敢相信这甚至被认为是一个"解决方案"。我真的希望他们正在研究更好的解决方案。

对考虑使用git lfs的雇主和公司的建议:

快速摘要:不要使用git lfs。请改为为您的员工购买更大的 SSD。如果您最终使用了git lfs,请为您的员工购买更大的 SSD,这样他们就可以在睡觉时运行脚本每晚执行一次git lfs fetch --all

详:

假设您是一家科技公司,拥有大小为 50 GB 的庞大单存储库,以及您希望成为存储库一部分的二进制文件和数据,大小为 4 TB。与其给他们不足的 500 GB ~ 2 TB SSD,然后求助于git lfs,这使得git checkout在家庭互联网连接上完成时从几秒钟到几小时,不如让您的员工获得更大的固态硬盘!一个典型的技术员工的成本>1000 美元/天(每周 5 个工作日 x 48 个工作周/年 x 1000 美元/天 = 24 万美元,低于他们的工资 + 福利 + 间接费用)。因此,如果 1000 美元的 8 TB SSD 可以节省他们数小时的等待和麻烦,那么它是完全值得的!购买示例:

  1. 8TB 萨布伦特火箭 M.2 固态硬盘,1100 美元
  2. 8TB 内陆 M.2 固态硬盘,900 美元

现在,他们希望有足够的空间在自动的夜间脚本中运行git lfs fetch --all,以获取所有远程分支的LFS内容,以帮助缓解(但不能解决此问题),或者至少git lfs fetch origin branch1 branch2 branch3获取其最常用分支的哈希值的内容。

参见

  1. 真正有见地的问答也倾向于不使用git lfs[即使是远程存储库]:本地存储库需要Git LFS吗?
  2. git lfs 的优势是什么?
  3. 我的问答:如何在失败git checkout后恢复git lfs post-checkout
  4. 我的答案:如何在 git 存储库中缩小 .git 文件夹
  5. 我的问答:git lfs fetchgit lfs fetch --allgit lfs pull有什么区别?

克隆 Git 存储库时,必须下载其整个历史记录的压缩副本。 您可以访问每个文件的每个版本。

使用 Git LFS,文件数据不会存储在存储库中,因此当您克隆存储库时,它不必下载存储在 LFS 中的文件的完整历史记录。 仅从 LFS 服务器下载每个 LFS 文件的"当前"版本。 从技术上讲,LFS 文件是在"签出"而不是"克隆"期间下载的。

因此,Git LFS 与其说是有效地存储大文件,不如说是避免下载所选文件的不需要版本。 无论如何,该历史记录通常不是很有趣,如果您需要旧版本,Git 可以连接到 LFS 服务器并获取它。 这与常规 Git 形成对比,后者允许您离线签出任何提交。

git LFS 如何比 git 更有效地跟踪和存储二进制数据?

git LFS 如何有效地跟踪二进制文件?

总结

其实不然。它跟踪大型二进制文件的效率低下。它只是在单独的服务器上远程完成,以释放一些本地存储空间,并使初始git clone过程最初下载的数据要少得多。这是它的要点:

@John 兹温克:

使用 Git LFS,文件

数据不会存储在存储库中,因此当您克隆存储库时,它不必下载存储在 LFS 中的文件的完整历史记录。仅从 LFS 服务器下载每个 LFS 文件的"当前"版本。从技术上讲,LFS 文件是在"签出"而不是"克隆"期间下载的。

@Schwern:

  1. 它可以大大减少存储库的初始 git 克隆的大小。
  2. 它可以大大减少本地存储库的大小。

@Mark布拉姆尼克:

这个想法是二进制文件从"远程"存储库中懒惰地下载,即在签出过程中而不是在克隆或获取过程中。

常规 Git 存储库

假设你有一个庞大的单存储库,其中包含大约 100 GB 的文本文件(代码,包括所有 git blob 和更改)和 100 GB 的二进制数据。请注意,这是一个现实的、有代表性的例子,我实际上处理了几年。如果 100 GB 的二进制数据已提交一次,则占用 100 GB,而总 git 存储库为 100 GB 的代码 blob + 提交一次的 100 GB 二进制数据 = 200 GB。

但是,如果每个文件的 100 GB 二进制数据已更改 10 次,则它占用 ~100 GB x (1 + 10) = 1.1 TB 的空间,+ 100 GB 代码 -->1.2 TB存储库大小。现在,克隆此存储库:

# this downloads 1.2 TB of data
git clone git@github.com:MyUsername/MyRepo.github.io.git

如果你想做一个git checkout,但它很快!所有二进制数据都存储在本地存储库中,因为您拥有二进制数据的所有 11 个快照(初始文件 + 10 个更改)!

# this downloads 0 bytes of data;
# takes **seconds**; you already have the binary data locally, so no new data is
# downloaded from the remote server
git checkout some_past_commit
# this takes seconds and downloads 0 bytes of new data as well
git checkout another_past_commit

与此形成对比git lfs

使用 Git

LFS 进行所有二进制文件存储的 Git 存储库

您的存储库与上述相同,只是 git 存储库中只有 100 GB 的代码。Git LFS 导致 git 只将指针文本文件存储到 LFS 服务器,因此 git 存储库中的内容只是 100 GB 的代码 + 指针文件的一点点存储。

另一方面,Git LFS 服务器包含所有1.1 TB 的二进制文件。所以,你会得到这个效果:

# this downloads 0.1 TB (100 GB) of code/text data
git clone git@github.com:MyUsername/my_repo.github.io.git
# this downloads 0.1 TB (100 GB) of binary data--just the most-recent snapshot
# of all 100 GB of binary data on Git LFS
cd my_repo
git lfs pull
# this downloads potentially up to another 0.1 TB (100 GB) of data;
# takes **hours**; you do NOT have the binary data for all snapshots stored
# locally, so at **checkout** Git LFS causes your system to download all new
# LFS data!
git checkout some_past_commit
# this downloads up to another 0.1 TB (100 GB) of data, taking **more hours**
git checkout another_past_commit

实际上,常规 Git 存储二进制 blob 的效率高于 Git LFS

请参阅@Alexander Gogl的回答中的表格 这里.添加 28.8 MB 的 Vectorworks (.vwx) 文件需要 26.5 MB 作为 git blob,26.5 MB 作为 Git LFS blob。但是,如果将其存储为 git blob,然后运行git gc来执行"垃圾回收"和 blob 压缩,则常规 git 会将其缩小到 1.8 MB。Git LFS 不会对它做任何事情。另请参阅此表中的其他示例。

如果你看一下这个表,你会发现 git 整体存储比 Git LFS 更有效率:

as git-lfsblob<td style="文本对齐:右;">28,8 MB<td style="文本对齐:右;">16,9 MBstyle="文本对齐:右;">85,8 MB几何<td style="文本对齐:右;">66,3 MB<td style="text-align: right;">25,8 MBtdstyle="文本对齐:右;">13,1 MBstyle="文本对齐:右;">-13,1 MB
typechangefileas git blobAftergit gc
Vectorworks (.vwx)添加了几何
+26,5 MB+1,8 MB+26,5 MB
GeoPackage (.gpkg)添加了几何
+3,7 MB+3,5 MB+16,9 MB
亲和力照片 (.afphoto)切换图层
+85,6 MB+0,8 MB+85,6 MB
FormZ (.fmz)添加了
+66,3 MB+66,3 MB+66,3 MB
Photoshop (.psd)切换图层
+15,8 MB+15,4 MB+25,8 MB
影片 (mp4)修剪<
+13,2 MB+0 MB+13,1 MB
删除文件
+0 MB+0 MB+0 MB