当前位置:  开发笔记 > 编程语言 > 正文

使用Git管理大型二进制文件

如何解决《使用Git管理大型二进制文件》经验,为你挑选了9个好方法。

我正在寻找如何处理我的源代码(Web应用程序)所依赖的大型二进制文件的意见.我们目前正在讨论几种选择:

    手动复制二进制文件.

    亲:不确定.

    Contra:我强烈反对这一点,因为它增加了在设置新站点/迁移旧站点时出错的可能性.建立另一个障碍.

    Git管理所有这些.

    专业:删除'忘记'复制重要文件的可能性

    反对:膨胀存储库并降低管理代码库和检出,克隆等的灵活性将需要相当长的时间.

    单独的存储库.

    Pro:检查/克隆源代码的速度很快,图像可以在自己的存储库中正确存档.

    Contra:删除了在项目中拥有唯一的 Git存储库的简单性.它肯定会介绍一些我没有想过的其他事情.

您对此有何体验/想法?

另外:有没有人有多个Git存储库的经验并在一个项目中管理它们?

这些文件是程序的图像,该程序生成包含这些文件的PDF.文件不会经常更改(如年份),但它们与程序非常相关.没有文件,程序将无法运行.



1> rafak..:

我最近发现了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上提供了一个软件包.


但是,Annex不支持Windows.这对游戏开发者来说是个问题.
哇!赞成真棒!这实现了我最近的想法,以及更多.它是用Haskell编写的.顺便说一句,git-media是一个不错的选择.
我听说Steam正在放弃对windows的支持,并添加对Linux的支持...;)但是,认真地说,移植它有多难?我想你的普通游戏开发者可以做到这一点.
@EstebanBrenes真正的交易破坏者是在正常配置中,Windows符号链接需要提升权限才能创建.
我刚刚找到[本页](https://git-annex.branchable.com/install/Windows/).它读到现在`git annex`也可用于******.如果有人曾在Windows中测试过,我想听听他或她的经历!
@ e-satisf Windows有符号链接.但仔细观察后,似乎每个路径可以拥有多少个符号链接.但是Windows中有符号链接:http://msdn.microsoft.com/en-us/library/windows/desktop/aa365680(v = vs.85).aspx
Git-annex本身有一些关于移植到Windows的障碍的文档:http://git-annex.branchable.com/todo/windows_support/

2> Pat Notz..:

如果程序在没有文件的情况下无法工作,似乎将它们分成单独的仓库是一个坏主意.我们有大型测试套件,我们分成一个单独的回购,但那些是真正的"辅助"文件.

但是,您可以在单独的仓库中管理文件,然后用git-submodule它们以理智的方式将它们拉入项目中.所以,你仍然拥有所有来源的完整历史记录,但据我所知,你只有你的图像子模块的一个相关版本.该git-submodule工具应该帮助您保持正确版本的代码符合正确版本的图像.

这是对 Git Book 子模块的一个很好的介绍.


确实.子模块是一个完整的Git存储库,它恰好嵌套在父存储库中.它知道它的整个历史.你可以不那么频繁地提交它,但是如果你在父母中存储相同的东西,那么父母会有同样的问题.
"据我所知,你只有你的图像子模块的一个相关版本." 我不认为这是正确的.
如果您有大量的二进制文件以一定的间隔更改,这是一个非常糟糕的解决方案.我们有一个非常臃肿的存储库,因为每个构建都会存储一个新的二进制文件.如果您不在Windows上,如下所述,附件是一个很好的解决方案.如果你在Windows上......只需继续寻找.
在repo中拥有大型二进制文件的另一个问题是性能.Git不是为了应对大型二进制文件而设计的,一旦回购大小上升到3G +,性能就会迅速下降.这意味着在repo中拥有大型二进制文件会限制您的托管选项.

3> VonC..:

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

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

https://cloud.githubusercontent.com/assets/1319791/7051226/c4570828-ddf4-11e4-87eb-8fc165e5ece4.gif


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

4> sehe..:

看看git bup,这是一个Git扩展,可以在Git存储库中智能地存储大型二进制文件.

您希望将其作为子模块,但您不必担心存储库难以处理.他们的一个示例用例是在Git中存储VM映像.

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

你的旅费可能会改变.


bup提供存储(内部使用奇偶校验存档进行冗余,git用于压缩,重复数据删除和历史记录),但它不会扩展git.git-annex是一个git扩展,提供[bup存储后端](http://git-annex.branchable.com/walkthrough/using_bup/).
bup对于管理大文件肯定很有意思.我想指出UI的不同之处:你在任何存储库上下文之外使用bup命令,而git是一个实现细节.

5> Carl..:

你也可以使用git-fat.我喜欢它只依赖于库存Python和rsync.它还支持通常的Git工作流,具有以下自解释命令:

git fat init
git fat push
git fat pull

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

您可以使用法线添加二进制文件git add,而法线依次git fat根据您的gitattributes规则调用.

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

更新:如果您使用的是Git-SVN网桥,请不要使用git-fat.它最终会从Subversion存储库中删除二进制文件.但是,如果您使用纯Git存储库,它可以很好地工作.



6> Daniel Fanju..:

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

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

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

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

然后,我删除旧分支,只保留新分支,删除引用日志,并运行"git prune":之后,我的.git文件夹仅加权~6 GB ...

你可以用同样的方式"清除"巨大的存储库:你的"git clone"会更快.



7> claf..:

在我看来,如果你经常修改那些大文件,或者你打算做很多git clone或者git checkout,那么你应该认真考虑使用另一个Git存储库(或者可能是另一种方式来访问这些文件).

但是如果你像我们一样工作,并且如果你的二进制文件不经常被修改,那么第一次克隆/结账将会很长,但之后它应该尽可能快(考虑到你的用户继续使用第一个克隆的存储库他们有).


并且,单独的回购不会缩短结账时间,因为您仍然需要检查两个回购!

8> Adam Kurkiew..:

我想提出的解决方案是基于孤立分支和略微滥用标记机制,以下称为*Orphan标记二进制存储(OTABS)

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

OTABS的理想特性

它是纯粹的gitgit解决方案 - 它可以在没有任何第三方软件(如git-annex)或第三方基础设施(如github的LFS)的情况下完成工作.

有效地存储二进制文件,即它不会破坏存储库的历史记录.

git pull并且git fetch,包括git fetch --all仍然带宽有效,即默认情况下并非所有大型二进制文件都从远程提取.

它适用于Windows.

它将所有内容存储在一个git存储库中.

它允许删除过时的二进制文件(与bup不同).

OTABS的不良特性

git clone可能效率低下(但不一定,取决于您的使用情况).如果您部署此解决方案,则可能需要建议您的同事使用git clone -b master --single-branch 而不是git clone.这是因为默认情况下git clone会克隆整个存储库,包括通常不想浪费带宽的事情,例如未引用的提交.取自SO 4811434.

它使git fetch --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 --tags,但请继续阅读以解决此问题.来吧git tag 1.0.0bin

    推送您的孤儿标签git push 1.0.0bin.

    因此,您永远不会意外推送二进制分支,您可以将其删除git branch -D binaryStuff.您的提交不会被标记为垃圾收集,因为指向它的孤立标记1.0.0bin足以使其保持活动状态.

签出二进制文件

    我如何(或我的同事)将VeryBigBinary.exe签出到当前工作树中?如果您当前的工作分支是例如掌握,您可以简单地git checkout 1.0.0bin -- VeryBigBinary.exe.

    如果您没有1.0.0bin下载孤儿标签,这将失败,在这种情况下您必须git fetch 1.0.0bin事先.

    您可以将其添加VeryBigBinary.exe到主服务器中.gitignore,这样您团队中的任何人都不会意外地使用二进制文件污染项目的主历史记录.

完全删除二进制文件

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

    删除遥控器上的孤立标签 git push :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访问遥控器的提供商,那就让它吧.您的提供商的基础架构可能会在自己的甜蜜时间内清理您的未引用提交.如果您在公司环境中,您可以建议您的IT运行cron job垃圾,每周一次收集您的遥控器.无论他们是否做到,都不会对您的团队在带宽和存储方面产生任何影响,只要您建议您的同事始终git clone -b master --single-branch 而不是git clone.

    想要摆脱过时的孤儿标签的所有同事只需要应用步骤2-3.

    然后,您可以重复添加二进制文件的步骤1-8 以创建新的孤立标记2.0.0bin.如果您担心同事打字,git fetch --tags您可以再次命名1.0.0bin.这将确保下次他们获取所有标记时旧的1.0.0bin将被取消引用并标记为随后的垃圾收集(使用步骤3).当您尝试覆盖遥控器上的标签时,您必须使用-f如下:git push -f

后记

OTABS不会触及您的主人或任何其他源代码/开发分支.提交哈希值,所有历史记录以及这些分支的小尺寸不受影响.如果您已经使用二进制文件膨胀了源代码历史记录,则必须将其作为单独的工作进行清理.这个脚本可能很有用.

确认使用git-bash在Windows上工作.

最好应用一组标准trics来提高二进制文件的存储效率.频繁运行git gc(没有任何其他参数)使得git通过使用二进制增量来优化文件的底层存储.但是,如果您的文件在提交提交时不太可能保持相似,则可以完全关闭二进制增量.此外,因为压缩已压缩或加密的文件(如.zip,.jpg或.crypt)没有意义,git允许您关闭底层存储的压缩.不幸的是,这也是影响源代码的全有或全无设置.

您可能希望编写OTABS的部分脚本以便更快地使用.特别是,从完全删除二进制文件updategit钩子的脚本步骤2-3 可以给git fetch("获取并删除过时的所有内容")提供引人注目但可能是危险的语义.

您可能希望跳过完全删除二进制文件的步骤4 ,以中央存储库膨胀为代价保留远程上所有二进制更改的完整历史记录.随着时间的推移,本地存储库将保持精益.

在Java世界中,可以将此解决方案与maven --offline创建完全存储在您的版本控制中的可重现的离线构建相结合(使用maven比使用gradle更容易).在Golang世界中,建立这个解决方案来管理你的GOPATH是可行的go get.在python世界中,可以将它与virtualenv结合起来,以生成一个独立的开发环境,而无需从头开始依赖PyPi服务器进行每个构建.

如果您的二进制文件经常改变,像构建工件,这可能是一个好主意,脚本存储5个最近期孤儿标签的文物版本的解决方案monday_bin,tuesday_bin...,friday_bin和也是一个孤儿每一个版本的标签1.7.8bin 2.0.0bin等.您可以weekday_bin每天旋转和删除旧的二进制文件.通过这种方式,您可以获得两个世界中最好的:保留源代码的整个历史记录,但只保留二进制依赖项的相关历史记录.获取给定标记的二进制文件也很容易,而不会获得包含其所有历史记录的完整源代码:git init && git remote add && git fetch 应该为您完成.



9> 小智..:

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

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

所以看起来SVN对二进制文件的效率要高得多.

所以我的选择是Git的源代码和SVN的二进制文件,如文档.


添加这4个文件后,您只需要运行"git gc"(重新打包和垃圾收集).Git不会立即压缩所有添加的内容,因此您将拥有一组文件压缩(在大小方面更有效),并且不会减慢单独压缩每个添加的对象.但即使没有"git gc",git也会最终为你完成压缩,无论如何(在注意到之后,已经积累了足够的解压缩对象).
@jpierson我创建了一个空的git存储库并添加(并提交了)一个大小为41MB的完全白色的bmp映像,这导致了一个总大小为328KB的git存储库.在`git gc`之后,总git存储库大小减少到184KB.然后我将单个像素从白色更改为黑色并提交此更改,总git存储库大小增加到388KB,并且在`git gc`之后,总git存储库的大小减少到184KB.这表明git非常适合压缩和查找二进制文件的增量.
@JanDvorak - 没有人提到它,因为它完全是不真实的.Subversion副本很便宜 - http://svnbook.red-bean.com/en/1.7/svn.branchmerge.using.html - 关于页面的中间部分.
@Tader:你的考试不好.你所谓的二进制文件实际上(从git的角度来看)更像是一个文本文件 - 比特流是字节对齐的,并且有一些有意义的本地化差异; 毕竟,更改一个像素基本上相当于更改文本文件中的一个字符(现在谁使用未压缩的位图?)尝试使用小视频,压缩图像,虚拟机,zipfile或其他任何相同的实验 - 你会发现那个git没有有效地处理delta; 事实上,不可压缩的数据根本不可能.
@jpierson旁注:我刚评论了二进制增量.如果它管理具有大(GB大小)文件的存储库,Git将占用你所有的内存和交换.为此,请使用[git-annex](http://git-annex.branchable.com/)(已在其他答案中提及)......
@jpierson推送仅传输差异.因此,第一次推送将传输所有数据(压缩).后续推送仅传输更改.
@jpierson你在混淆"推"和"提交"吗?在SVN中,没有区别,但是git"commit"是本地操作.立即计算增量只会增加开销.
推荐阅读
李桂平2402851397
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有