如何使用 Git 管理二进制大对象

5 位读者喜欢这篇文章。
Databases as a service

Jason Baker。CC BY-SA 4.0。

阅读

在本系列的前六篇文章中,我们学习了如何使用 Git 管理文本文件的版本控制。但是二进制文件呢?Git 具有处理二进制大对象(如多媒体文件)的扩展,因此今天我们将学习如何使用 Git 管理二进制资产。

每个人似乎都同意一件事,那就是 Git 不太适合大型二进制大对象。请记住,二进制大对象与大型文本文件不同;您可以在大型文本文件上使用 Git 而不会出现问题,但 Git 对不可渗透的二进制文件无能为力,只能将其视为一个巨大的黑色盒子并按原样提交。

假设您有一个复杂的第一人称益智游戏的 3D 模型,您将其保存为二进制格式,生成一个 1 GB 的文件。您 git commit 提交一次,为您的仓库历史记录增加了一个 GB。稍后,您为模型设计了不同的发型并提交了更新;Git 无法区分头发与头部或模型的其余部分,因此您又提交了一个 GB。然后您更改了模型的眼睛颜色并提交了这个小改动:又是一个 GB。对于一个模型进行了一些微小的随意更改,就产生了 3 GB 的数据。将此规模扩展到游戏中的所有资产,您就会遇到严重的问题。

将其与 .obj 格式的文本文件进行对比。一次提交存储所有内容,就像其他模型一样,但 .obj 文件是一系列描述模型顶点的纯文本行。如果您修改模型并将其保存回 .obj,Git 可以逐行读取这两个文件,创建更改差异,并处理相当小的提交。模型越精细,提交就越小,这是一个标准的 Git 用例。这是一个大文件,但它使用一种覆盖或稀疏存储方法来构建数据当前状态的完整图像。

但是,并非所有内容都以纯文本形式工作,而且现在每个人都想使用 Git。因此需要一种解决方案,并且已经出现了几种解决方案。

Git Large File Storage (LFS) 是来自 GitHub 的一个开源项目,最初是 git-media 的一个分支。Git-media 和 git-annex 是 Git 的扩展,旨在管理大型文件。它们是解决同一问题的两种不同方法,并且各有优势。这些不是项目本身的官方声明,但以我的经验来看,它们的独特之处在于:

  • Git-annex 倾向于分布式模型;您和您的用户创建仓库,并且每个仓库都有一个本地 .git/annex 目录,用于存储大型文件。附件定期同步,以便所有用户根据需要访问所有资产。除非使用 annex-cost 另行配置,否则 git-annex 优先考虑本地存储而不是异地存储。

  • Git-portal 也是分布式的,并且像 Git-annex 一样可以选择同步到中央位置。它使用您可能已经安装的常用实用程序(特别是 Bash、Git、rsync)。

  • Git-LFS 是一种集中式模型,用于存储常用资产的仓库。您告诉 Git-LFS 大型文件的存储位置,无论是硬盘驱动器、服务器还是云存储服务,并且您项目中的每个用户都将该位置视为大型资产的中央主位置。

git-portal

Git-portal 使用标准的 UNIX 工具(如 Bash、Git 本身以及可选的 rsync)为 Git 提供简化的 blob 管理。它将大型二进制文件复制到本地或远程存储,并将其替换为符号链接,您可以将符号链接与项目的其余文件一起提交。

Git-portal 的简单性是以有时需要更多手动操作为代价的(例如,它没有自动垃圾回收)。它非常适合需要管理通常不适合 Git 管理的大型文件,但又不想学习全新系统的用户。Git-portal 模仿 Git 本身,因此学习曲线非常小。

您可以从其在 Gitlab 上的项目页面安装 Git-portal。

所有 Git-portal 命令都镜像 Git 本身。要在项目中使用 Git-portal,请执行以下操作:

$ git-portal init

要添加文件:

$ git-portal add bigfile.png

一旦文件“通过门户发送”(在项目的术语中),您与 Git 的交互与往常完全相同。您可以像往常一样添加文件,相对地忽略了其中一些文件实际上是指向 _portal 目录的符号链接。

_portal 目录中的所有内容(Git 完全忽略)都可以单独备份到您喜欢的任何类型的存储中,无论是 USB 驱动器还是远程服务器。由于 Git-portal 提供了一些 Git 钩子(由特定 Git 操作触发的自动化脚本,例如推送或拉取),您甚至可以设置一个特殊的 Git 远程条目,以便您的 _portal 目录与远程位置自动同步。

$ git remote add _portal alice@myserver.com:/home/alice/umbrella.git/_portal

Git-portal 的优势在于它是一个简单且 Linux 原生的系统。凭借相当少的常用实用程序堆栈和只需记住的几个额外命令,您可以管理大型项目依赖项,甚至可以在协作者之间共享它们。Git-portal 已用于媒体项目、独立视频游戏和游戏博客,以管理从小型启动画面图像到大型 PDF 甚至更大的 3D 模型的所有内容。

git-annex

git-annex 具有稍微不同的工作流程,默认使用本地仓库,但基本思想是相同的。您应该能够从您的发行版仓库安装 git-annex,或者您可以根据需要从网站获取它。与 git-media 一样,任何使用 git-annex 的用户都必须在其机器上安装它。

初始设置比 git-media 更简单。要在您的服务器上创建裸仓库,请运行以下命令,替换为您自己的路径:

$ git init --bare --shared /opt/jupiter.git

然后将其克隆到您的本地计算机上,并将其标记为 git-annex 位置:

$ git clone seth@example.com:/opt/jupiter.clone 
Cloning into 'jupiter.clone'... warning: You appear to have cloned
an empty repository. Checking connectivity... done. 
$ git annex init "seth workstation" init seth workstation ok 

您不是使用过滤器来识别媒体资产或大型文件,而是通过使用 git annex 命令来配置将哪些内容归类为大型文件:

$ git annex add bigblobfile.flac
add bigblobfile.flac (checksum) ok
(Recording state in Git...) 

提交操作照常完成:

$ git commit -m 'added flac source for sound fx'

但推送操作有所不同,因为 git annex 使用自己的分支来跟踪资产。您进行的第一次推送可能需要 -u 选项,具体取决于您管理仓库的方式:

$ git push -u origin master git-annex 
To seth@example.com:/opt/jupiter.git 
* [new branch] master -> master 
* [new branch] git-annex -> git-annex 

git-media 一样,正常的 git push *不会* 将您的资产复制到服务器,它只会发送有关媒体的信息。当您准备好与团队的其他成员共享您的资产时,请运行同步命令:

$ git annex sync --content

如果其他人已将资产共享到服务器,并且您需要拉取它们,则 git annex sync 将提示您的本地检出拉取您的计算机上不存在但在服务器上存在的资产。

Git annex 是一种经过微调的解决方案,灵活且用户友好。它功能强大且经过充分测试。

git-lfs

git-lfs 使用 Go 编写,您可以从源代码或作为可下载的二进制文件安装它。说明位于 网站 上。每个想要使用 git-lfs 的用户都需要安装它,但它是跨平台的,因此通常不会造成问题。

安装 git-lfs 后,您可以设置您希望 Git 忽略并由 Git-LFS 管理的文件类型。例如,要让 Git-LFS 跟踪所有 .png 文件:

$ git lfs track "*.png"

每当您为 Git-LFS 跟踪添加文件类型时,您都必须添加然后提交文件 .gitattributes

$ git add .gitattributes
$ git commit -m "LFS track *.png"

当您暂存这些类型的文件时,该文件将被复制到 .git/lfs

Git-LFS 是 Github 的一个项目,并且与 Github 的基础设施紧密结合。如果您想运行允许 Git-LFS 集成的 Git 服务器,您可以研究 Git-LFS 服务器规范(也用 Go 编写)并实现 API。

git-portalgit-annex 都很灵活,可以使用本地仓库而不是服务器,因此它们对于管理私有本地项目也同样有用。

大型文件和 Git

虽然 Git 旨在用于文本文件,但这并不意味着仅仅因为您有二进制资产就不能使用它。有很多很好的解决方案可以帮助您管理大型文件。如果您想使用 Git,那么真的没有太多借口不使用它,所以今天就试试看吧!

标签
Seth Kenlon
Seth Kenlon 是一位 UNIX 极客、自由文化倡导者、独立多媒体艺术家和 D&D 爱好者。他曾在电影和计算行业工作,而且经常同时进行。

8 条评论

我对任何大型文件支持方案的疑问是(据我所知),您实际上并没有对任何资产进行版本控制。当然,您有大型文件,并且有您所做更改的日志,但除非我误解了一些基本的东西,否则没有机制可以将这些大型二进制文件回滚到以前的版本。这对我来说是不可接受的,因为分支和回滚能力是我使用版本控制的两个主要原因。

简而言之,请告诉我我错了。Git LFS、git-media 或 git-annex 是否支持分支和回滚大型二进制文件,只是文档真的很难理解?还是我可悲地正确阅读了文档?

做了一些研究,但事实证明我错了。大型文件*确实*被版本化了……修订版只是单独存储。我现在明白了。当您进行检出时,您只会获得该修订版/分支所需的文件。但是,如果您在没有中央服务器的情况下进行临时版本控制(即,就地版本控制项目,而不一定与任何人共享/协作),那么设置起来可能会有点麻烦……也许吧。我想只有一种方法可以确定。 :)

回复 ,作者:Alexander Teterkin

是时候变得迂腐了:版本控制和版本控制是不同的。对于我管理的大对象,当其他所有内容都处于 33md6465b3 状态时,让 git “知道”昨天发生了一些变化对我没什么好处。我不需要我的图形或视频的版本与昨天的提交相匹配。我不需要能够逐步浏览我的项目并查看视觉效果的不同阶段。我想要备份,以防我完全毁坏图形,但除此之外,我不需要版本。然而,git-lfs 确实对大型文件进行版本控制,这很酷,但这并不是我需要的。事实上,当 git-media 和 git-annex 过度时,我实际上推出了自己的 BASH 解决方案来简化流程。

回复 ,作者:Jason van Gumster

您知道吗?“blob” 代表 “binary large object”(二进制大对象)。

“Binary blobs”(二进制大对象)因此是 binary binary large objects(二进制二进制大对象)

对我来说,这是一个决定性的缺点,因为分支和回滚能力是我使用版本控制的两个主要原因。对于我管理的 blobs,当其他所有内容都在 33md6465b3 版本时,让 git “知道” 昨天发生了更改对我没什么用处

Creative Commons License本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
© . All rights reserved.