我正在寻找有关如何处理源代码(Web应用程序)所依赖的大型二进制文件的意见。我们目前正在讨论以下几种替代方法:


手动复制二进制文件。


Pro:不确定。
对比:I我坚决反对这一点,因为它增加了在建立新站点/迁移旧站点时出错的可能性。建立另一个障碍。


使用Git管理它们。


专业版:消除了“忘记”复制重要内容的可能性文件
相反:膨胀存储库并降低管理代码库的灵活性,检出,克隆等将花费相当长的时间。


单独的存储库。


专业版:签出/克隆源代码比以往任何时候都快,并且图像已正确存储在其自己的存储库中。
相反:消除了拥有一个和唯一的Git的简单性项目上的存储库。它肯定会介绍其他我没想到的事情。



您对此有何经验/想法?

还:有人吗?拥有多个Git存储库并在一个项目中进行管理的经验?

文件是一个程序的图像,该程序会在其中生成包含这些文件的PDF。文件不会经常更改(像几年一样),但是它们与程序非常相关。没有文件,该程序将无法运行。

评论

何时需要版本控制二进制文件怎么办?我正在考虑寻找从事资产工作的艺术家团队。

如果有必要,那么您必须权衡可用资源(磁盘,带宽,CPU时间)和所获得的收益。

请注意,如果没有文件锁定,当多个人需要处理同一个二进制文件时,git并不是很好。

另请参见基于git的备份文件bup。
这是bestechvideos.com/tag/gitcasts

#1 楼

如果程序没有这些文件就无法运行,将它们拆分成一个单独的存储库似乎是个坏主意。我们有大型测试套件,可以分解成一个单独的存储库,但它们确实是“辅助”文件。

但是,您也许可以在一个单独的存储库中管理文件,然后使用git-submodule将它们拉出以理智的方式进入您的项目。因此,您仍然拥有所有来源的完整历史记录,但是据我了解,您只会拥有图像子模块的一个相关修订版。 git-submodule工具应该可以帮助您使代码的正确版本与图像的正确版本保持一致。

这是Git Book中子模块的很好介绍。

评论


“据我了解,您只会对图像子模块进行一个相关修订。”我认为这是不正确的。

–罗宾·格林(Robin Green)
2011年11月12日在7:30

确实。子模块是完整的Git存储库,它恰好嵌套在父存储库中。它了解其整个历史。您可以减少在其中的提交频率,但是如果在其中存储的内容与在父级中相同,则它将产生与父级相同的问题。

–卡斯卡贝尔
2012年2月16日在21:03



如果您有大的二进制文件,并且每隔一定的时间间隔进行更改,则这是一个非常差的解决方案。我们的存储库非常膨胀,因为每次构建时都会在其中存储一个新的二进制文件。如下所述,如果您不在Windows上,则Annex是一个很好的解决方案。如果您使用的是Windows,则只需继续寻找即可。

–A.A. Grapsas
2012年7月18日在21:13

存储库中具有大二进制文件的另一个问题是性能。 Git并非旨在处理大型二进制文件,一旦存储库大小达到3G +,性能就会迅速下降。这意味着回购中包含较大的二进制文件会限制您的托管选项。

– zoul
2012年10月12日在7:09

如果您创造性地滥用子模块,则子模块可以减少结帐数据传输的要求:当您要更新子模块的内容时,创建没有父对象的新提交,然后将超级项目(主git repo)指向没有父对象的新创建的提交。从逻辑上讲,这会为子模块创建断开连接的历史记录,但是作为回报,子模块的任何版本都更易于传输,因为该版本没有历史记录。

– Mikko Rantalainen
2013年9月2日在9:42

#2 楼

我最近发现git-annex,发现它很棒。它旨在有效地管理大型文件。我将其用于照片/音乐(等)收藏。 git-annex的开发非常活跃。可以从Git存储库中删除文件的内容,Git只能跟踪树层次结构(通过符号链接)。但是,要获取文件的内容,在拉/推之后需要执行第二步,例如:

$ git annex add mybigfile
$ git commit -m'add mybigfile'
$ git push myremote
$ git annex copy --to myremote mybigfile ## This command copies the actual content to myremote
$ git annex drop mybigfile ## Remove content from local repo
...
$ git annex get mybigfile ## Retrieve the content
## or to specify the remote from which to get:
$ git annex copy --from myremote mybigfile


有很多可用的命令,并且有很多功能。网站上的文档。 Debian上有可用的软件包。

评论


哇!支持真棒!这实现了我最近的想法,还有更多。它是用Haskell编写的。顺便说一下,git-media是一个很好的选择。

– cdunn2001
11年7月20日在17:13

但是,附件不支持Windows。这对于游戏开发者来说是有问题的。

–A.A. Grapsas
2012年7月18日在21:12

我听说Steam放弃了对Windows的支持,并增加了对Linux的支持...;)虽然如此,移植它有多困难?我想您的普通游戏开发人员可以做到。

–山姆·沃特金斯(Sam Watkins)
2012年7月28日15:04



@EstebanBrenes真正的麻烦之处在于,在常规配置中,Windows符号链接需要提升的特权才能创建。

–劳伦斯·霍尔斯特(Laurens Holst)
13年2月12日在15:06

我刚刚找到此页面。它显示,现在git annex也可以在Windows上使用。如果有人曾经在Windows中对其进行过测试,我想听听他或她的经验!

–中村圭一
2015年3月5日在3:47



#3 楼

自2015年4月以来的另一种解决方案是Git大文件存储(LFS)(由GitHub提供)。

它使用git-lfs(请参阅git-lfs.github.com)并在支持该服务器的服务器上进行了测试: lfs-test-server:
您只能将元数据存储在git repo中,并将大文件存储在其他位置。



评论


声明lfs-test-server不用于生产。实际上,我正在生产LFS服务器(github.com/artemkin/git-lfs-server)。它正在进行中,但已经可以使用,我们正在内部对其进行测试。

–状态
15年4月26日在22:30

您可以使用git lfs签出此类二进制文件的先前版本吗?

–穆卡霍
16 Mar 23 '16 at 2:59

@mucaho您应该:git checkout的语法不变,并且应该仍然调用lfs smudge脚本。

–VonC
16 Mar 23 '16 at 7:41

#4 楼

看看git bup,它是一个Git扩展,可以将大型二进制文件聪明地存储在Git存储库中。

您希望将其作为子模块,但是您不必担心仓库变得越来越难处理。他们的示例用例之一是将VM映像存储在Git中。

我实际上没有看到更好的压缩率,但是我的存储库中没有太大的二进制文件。

您的里程可能会有所不同。

评论


bup提供存储(内部使用奇偶校验存档来实现冗余,并使用git来进行压缩,去重复和历史记录),但它不扩展git。 git-annex是一个git扩展,提供了bup存储后端。

–东武
2012年2月21日上午11:55

@Tobu当我发布此内容时,git附件尚不存在(在主流版本中)

–sehe
2012年2月21日12:00



bup对于管理大文件绝对是有趣的。我想指出UI的不同之处:您可以在任何存储库上下文之外使用bup命令,而git是实现细节。

–东武
2012年2月21日在12:07

#5 楼

您也可以使用git-fat。我喜欢它仅取决于库存的Python和rsync。它还使用以下自我说明命令来支持通常的Git工作流程:

git fat init
git fat push
git fat pull


此外,您需要将.gitfat文件检入到存储库中并修改您的.gitattributes指定要git fat管理的文件扩展名。

使用常规git add添加二进制文件,该二进制文件又根据gitattributes规则调用git fat

最后,它的优点是可以在存储库和用户之间共享实际存储二进制文件的位置,并支持rsync所做的任何事情。

更新:如果您使用的是Git,请不要使用git-fat -SVN桥。最终将从Subversion存储库中删除二进制文件。但是,如果您使用的是纯Git存储库,它的运行效果就很好。

#6 楼

我将使用子模块(如Pat Notz)或两个不同的存储库。如果您经常修改二进制文件,那么我将尽量减少清理历史记录的巨大存储库的影响:

几个月前我遇到了一个非常类似的问题:大约21 GB的MP3文件,未分类(错误的名称,错误的id3,不知道我是否喜欢该MP3文件...),并在三台计算机上复制。

我使用了带有主Git的外部硬盘驱动器存储库,然后将其克隆到每台计算机。然后,我开始按习惯方式对它们进行分类(推,拉,合并...删除和重命名多次)。

最后,我只有〜6 GB的MP3文件和〜 .git目录中的83 GB。我使用git-write-treegit-commit-tree创建了一个没有提交祖先的新提交,并启动了一个指向该提交的新分支。该分支的“ git log”仅显示一次提交。

然后,我删除了旧分支,仅保留了新分支,删除了引用日志,然后运行“ git prune”:之后,我的.git文件夹的权重仅为〜6 GB ...

您可以不时以相同的方式“清除”巨大的存储库:您的“ git clone”将更快。 br />

评论


我曾经做过类似的事情,当时我不得不将一个存储库拆分成一个偶然的合并成两个不同的存储库。有趣的用法模式。 :)

– Pi。
09年2月12日在15:04

这是否与rm -f .git;相同? git init; git添加; git commit -m“破坏历史记录。”

– Pat Notz
09年2月12日在22:21

是的,仅在我的mp3盒中是一样的。但是有时候您不想触碰分支和标签(公共存储库中不减少空间),而是想加快仅分支的“ git clone / fetch / pull”(用于专用于该分支的空间减少)分支存储库)。

–丹尼尔(Daniel Fanjul)
09年2月13日在12:50

#7 楼

我想提出的解决方案基于孤立的分支和对标记机制的轻微滥用,因此被称为*孤立的标记二进制存储(OTABS)

TL; DR 12-01-2017如果可以使用github的LFS或其他第三方,则应该使用。如果不能,请继续阅读。请注意,此解决方案是骇客,应这样对待。

OTABS的理想属性


它是纯git和git only解决方案-它无需使用任何第三方软件(如git-annex)或第三方软件(如github的LFS)即可完成工作。
它可以高效地存储二进制文件,即不会使存储库的历史膨胀。 br />
git pullgit fetch(包括git fetch --all)仍然具有带宽效率,即默认情况下并非所有大型二进制文件都从远程拉出。
在Windows上工作。
将所有内容存储在单个文件中git repository。
它允许删除过时的二进制文件(与bup不同)。

OTABS的不良属性


它使git clone可能效率低下(但不一定,这取决于您的用法)。如果部署此解决方案,则可能必须建议您的同事使用git clone -b master --single-branch <url>而不是git clone。这是因为git clone默认会从字面上克隆整个存储库,包括通常不希望浪费带宽的内容,例如未引用的提交。取自SO4811434。
使git fetch <remote> --tags带宽效率低下,但不一定会使存储效率低下。您可以随时建议您的同事不要使用它。
您必须定期使用git gc技巧从不需要的文件中清除存储库。
它不如bup或git-bigfiles有效。但这分别更适合您想要做的事情和更多现成的东西。您可能会遇到成千上万个小文件或千兆字节范围内的文件的麻烦,但请继续阅读以获取解决方法。

添加二进制文件

开始时,请确保已提交所有更改,工作树是最新的,并且索引中不包含任何未提交的更改。最好将所有本地分支推送到远程(github等),以防万一发生灾难。


创建一个新的孤立分支。 git checkout --orphan binaryStuff可以解决问题。这将产生一个与其他分支完全断开连接的分支,并且您将在该分支中进行的第一次提交将没有父提交,这将使其成为根提交。
使用git rm --cached * .gitignore清理索引。
深呼吸,并使用rm -fr * .gitignore删除整个工作树。内部.git目录将保持不变,因为*通配符与之不匹配。
复制到VeryBigBinary.exe或VeryHeavyDirectory /中。
添加并提交并提交。
现在它变成棘手的问题-如果您将它作为一个分支推送到远程服务器,则所有开发人员在下次调用git fetch阻塞其连接时都将下载它。您可以通过推送标签而不是分支来避免这种情况。如果他们习惯键入git fetch <remote> --tags,这仍然会影响您同事的带宽和文件系统存储,但请继续阅读以寻求解决方法。继续并继续git tag 1.0.0bin

将您的孤儿标签git push <remote> 1.0.0bin按下。
因此,您绝不会偶然推入您的二进制分支,可以将其删除git branch -D binaryStuff。您的提交不会被标记为垃圾回收,因为指向它的孤立标记1.0.0bin足以保持它的生命。

检出二进制文件


我(或我的同事)如何将VeryBigBinary.exe检出到当前工作树中?例如,如果您当前的工作分支是master,则只需git checkout 1.0.0bin -- VeryBigBinary.exe即可。
如果没有下载孤岛标签1.0.0bin,则此操作将失败,在这种情况下,您必须事先进行git fetch <remote> 1.0.0bin
您可以将VeryBigBinary.exe添加到主人的.gitignore中,以便团队中的任何人都不会偶然用二进制文件污染项目的主要历史记录。

完全删除二进制文件

如果您决定完全从本地存储库,远程存储库和同事的存储库中清除VeryBigBinary.exe,则可以:


删除远程git push <remote> :refs/tags/1.0.0bin上的孤立标记

在本地删除该孤立标记(删除所有其他未引用的标记)git tag -l | xargs git tag -d && git fetch --tags。取自SO 1841341,稍作修改。
使用git gc技巧在本地删除您现在未引用的提交。 git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 -c gc.rerereresolved=0 -c gc.rerereunresolved=0 -c gc.pruneExpire=now gc "$@"。它还将删除所有其他未引用的提交。取自SO 1904860

如果可能,请在遥控器上重复git gc技巧。如果您是自托管存储库,则可能会出现这种情况,而某些git提供程序(例如github)或某些公司环境中可能无法实现。如果您使用的服务提供商托管的ssh不能使您通过ssh访问遥控器,那就顺其自然了。您的提供商的基础结构可能会在自己的美好时光中清理未引用的提交。如果您在公司环境中,则可以建议IT部门执行cron作业垃圾,每周大约收集一次遥控器。只要您建议您的同事始终使用git clone -b master --single-branch <url>而不是git clone,无论他们是否做对带宽和存储都不会对您的团队产生任何影响。
所有希望摆脱过时的同事孤儿标签仅需要应用第2-3步。
然后,您可以重复添加二进制文件中的步骤1-8,以创建新的孤立标记2.0.0bin。如果您担心同事输入git fetch <remote> --tags,则可以重新命名为1.0.0bin。这将确保下次他们获取所有标签时,不会引用旧的1.0.0bin并将其标记为后续垃圾回收(使用步骤3)。当您尝试覆盖遥控器上的标签时,必须像这样使用-fgit push -f <remote> <tagname>


后缀


OTABS不会碰到您的母版或任何其他源代码/开发分支。提交哈希,所有历史记录以及这些分支的较小大小均不受影响。如果您已经用二进制文件充实了源代码历史记录,则必须将其清理为单独的工作。该脚本可能有用。
确认可以在Windows上使用git-bash。
应用一组标准度量标准来提高二进制文件的存储效率是一个好主意。 git gc的频繁运行(不带任何其他参数)使git通过使用二进制增量来优化文件的基础存储。但是,如果从提交到提交的文件不太可能保持相似,则可以完全关闭二进制增量。此外,由于压缩无用的压缩或加密文件(如.zip,.jpg或.crypt)是没有意义的,因此git允许您关闭基础存储的压缩。不幸的是,这是一个全有或全无的设置,也会影响您的源代码。
您可能希望编写OTABS的一部分脚本,以便更快地使用。特别是,从完全删除二进制文件到update git钩子中的脚本步骤2-3可以为git fetch(“获取和删除所有过时的内容”)提供引人注目的但可能是危险的语义。
您可能要跳过“完全删除二进制文件”的第4步,以将所有二进制更改的完整历史记录保留在远程服务器上,而这要花中央存储库的费用。本地存储库将随着时间的推移保持精简。
在Java世界中,可以将此解决方案与maven --offline结合使用,以创建完全可复制的离线版本,该版本完全存储在您的版本控制中(使用maven比使用gradle容易)。在Golang世界中,可以使用此解决方案来管理您的GOPATH而不是go get。在python世界中,可以将其与virtualenv结合使用以生成一个自包含的开发环境,而无需从头开始的每个构建都依赖PyPi服务器。
如果您的二进制文件经常更改,例如构建工件,则可能是编写一个解决方案的好主意,该解决方案将5个最新版本的工件存储在孤立标签monday_bintuesday_bin,...,friday_bin中,并且还为每个发行版1.7.8bin 2.0.0bin等提供一个孤立标签。您可以旋转weekday_bin并删除旧的每日二进制文件。这样,您可以充分利用两个世界:保留源代码的整个历史记录,但仅保留二进制依赖项的相关历史记录。获取给定标签的二进制文件也很容易,而无需获取所有带有其全部历史记录的源代码:git init && git remote add <name> <url> && git fetch <name> <tag>应该为您完成。


评论


“您必须定期使用git gc”-停止在那里阅读。为什么有人放弃自己的最后一条安全带来支持某些黑客行为?

–user1643723
16-09-16在10:23

@ user1643723 git gc并非不安全运行。默认情况下,所有悬空的提交都会安全地保存在硬盘上至少30天:git-scm.com/docs/git-gc

–亚当·库基维奇(Adam Kurkiewicz)
16-09-22在8:46

感谢您的详细撰写。我想尝试这种方法,以将某些二进制依赖项存储在我的GitHub存储库中,以便在有人克隆该存储库时默认情况下不下载它们,但可以手动下载并更新本地存储库。但是,我在这一步遇到了一个错误:git push 1.0.0bin-remote:错误:GH001:检测到大文件。您可能要尝试使用Git大文件存储。看起来GitHub不再支持此功能?该二进制文件的大小为100MB。

–user5359531
17年1月12日,19:16



老实说,如果允许您使用github进行工作,是什么使您无法使用LFS? github的家伙们一直在努力创建这个产品,他们甚至为您托管它,并且围绕其使用对他们的基础结构进行了优化。此hack的目的是当您确实不能使用LFS或其他第三方并且您正在寻求纯git解决方案时。

–亚当·库基维奇(Adam Kurkiewicz)
17年1月12日在19:23

我还更新了答案,以更清楚地了解此解决方案的实际漏洞。

–亚当·库基维奇(Adam Kurkiewicz)
17年1月12日在19:27

#8 楼

我认为,如果您可能经常修改那些大文件,或者打算制作很多git clonegit checkout,那么您应该认真考虑使用另一个Git存储库(或者也许是另一种访问那些文件的方式)。 br />
但是,如果您像我们一样工作,并且您的二进制文件不经常被修改,那么第一个克隆/检出将很长,但是在那之后它应该尽可能快(考虑您的用户)继续使用他们拥有的第一个克隆存储库。

评论


而且,单独的存储库不会使结帐时间变短,因为您仍然必须检出两个存储库!

– Emil Sit
09年2月12日在14:34

如果您不断清理“二进制存储库”的历史记录,则@EmilSit单独的存储库会使结帐时间大大缩短。此外,开发人员不会被迫每次都检出两个存储库。

–FabienAndre
13-10-16在17:01

为什么不让主模块的构建脚本从第二个存储库中提取二进制文件,并一一提取它们(如此处:stackoverflow.com/questions/1125476/…)。

–akauppi
2014年2月6日在8:54

即使您的二进制文件不经常更改,如果您出于协作目的而经常将分支推送到存储库中,大文件仍然会杀死您的工作流程。

– Timo Reimann
2014年9月12日上午9:17

#9 楼

SVN似乎比Git更有效地处理二进制增量。

我必须决定用于文档(JPEG文件,PDF文件和.odt文件)的版本控制系统。我刚刚测试了添加JPEG文件并将其旋转90度四次(以检查二进制增量的有效性)。 Git的存储库增长了400%。 SVN的存储库仅增长了11%。

因此,看起来SVN与二进制文件相比效率更高。

所以我的选择是对源代码使用Git,对二进制文件使用SVN像文档。

评论


添加这4个文件后,您只需要运行“ git gc”(重新打包和垃圾回收)。 Git不会立即压缩所有添加的内容,因此您将具有文件组压缩(在大小方面更高效),并且不会单独压缩每个添加的对象。但是即使没有“ git gc”,git最终还是会为您完成压缩(无论如何,它会注意到已经积累了足够的未打包对象)。

–夜莺
10-10-4在8:13

@jpierson我创建了一个空的git存储库,并添加(并提交了)一个大小为41MB的全白bmp图像,这导致了一个总git存储库的大小为328KB。 git gc之后,总git存储库大小减小到184KB。然后,我将一个像素从白色更改为黑色,并进行了此更改,整个git存储库的大小增加到388KB,并且在git gc之后,整个git存储库的大小减小到184KB。这表明git在压缩和查找二进制文件增量方面相当出色。

–塔德
2011年8月1日12:22



@jpierson旁注:我只是评论了二进制增量。如果Git管理具有大(GB大小)文件的存储库,它将消耗掉所有内存并进行交换。为此,请使用git-annex(已在其他答案中提及)...

–塔德
11年8月18日在18:27

@JanDvorak-没有人提到它,因为它是完全不真实的。 Subversion副本很便宜-svnbook.red-bean.com/en/1.7/svn.branchmerge.using.html-在页面中间。

–乔里斯·蒂默曼斯(Joris Timmermans)
13年2月11日在15:23

@Tader:您的考试很糟糕。实际上,从git的角度来看,您所说的二进制文件更像是一个文本文件-比特流是按字节对齐的,并且要进行有意义的本地化比较。毕竟,更改一个像素基本上等同于更改文本文件中的一个字符(如今,谁在使用未压缩的位图?)尝试对小型视频,压缩图像,虚拟机,zip文件或其他内容进行相同的实验-您会发现git无法有效地处理增量;确实,使用不可压缩的数据根本不可能。

–Eamon Nerbonne
2013年12月5日23:45

#10 楼

来自Git 2.19 +浅层克隆的git clone --filter

如果Git和GitHub开发人员并使它足够用户友好(他们可能还没有做到这一点),那么这个新选项最终可能成为二进制文件问题的最终解决方案

它实际上仅允许获取服务器所需的文件和目录,并且是与远程协议扩展一起引入的。

为此,我们可以先进行浅层克隆,然后使用每种构建类型的构建系统自动提取要提取的斑点。

甚至已经有了一个--filter=blob:limit<size>,它可以限制要提取的最大斑点大小。

我提供了该功能外观的最小详细示例:如何仅克隆Git存储库的子目录?

#11 楼


我正在寻找有关如何处理源代码(Web应用程序)所依赖的大型二进制文件的意见。您对此有何经验/想法?



我的Web应用程序二进制数据突破3 GB标记后,我个人就与Git与某些云主机发生了同步故障。当时我考虑过BFT Repo Cleaner,但感觉就像是黑客。从那时起,我就开始将文件保留在Git权限之外,而利用诸如Amazon S3之类的专用工具来管理文件,版本控制和备份。


是否有人拥有多个Git存储库并在一个项目中进行管理的经验?


是的。雨果主题主要通过这种方式进行管理。这有点笨拙,但可以完成工作。


我的建议是为工作选择合适的工具。如果是针对公司的,并且您要在GitHub上管理代码行,则需要付款并使用Gi​​t-LFS。否则,您可以探索更多创造性的选择,例如使用区块链的分散式加密文件存储。

要考虑的其他选项包括Minio和s3cmd。

#12 楼

看看camlistore。它并不是真正基于Git的,但是我发现它更适合您的工作。