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

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

  1. 手动复制二进制文件。
    • 优势:不肯定。
    • 相反:我强烈反对这一点,由于它在创建新站点/迁移旧站点时增长了出错的可能性。 创建另外一个障碍。
  2. Git管理它们。
    • 专业版:消除了“忘记”复制重要文件的可能性
    • 相反:膨胀存储库并下降管理代码库的灵活性,而检出,克隆等将花费至关长的时间。
  3. 单独的存储库。
    • 优势:签出/克隆源代码比以往任什么时候候都快,而且图像已正确存储在其本身的存储库中。
    • 相反:消除了在项目上拥有惟一的 Git存储库的简单性。 它确定会引入其余我从未想过的东西。

您对此有何经验/想法? git

另外:是否有人在多个Git存储库中进行过管理并在一个项目中进行管理? github

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


#1楼

您也可使用git-fat 。 我喜欢它仅取决于rsync Python和rsync 。 它还经过如下自我说明命令来支持一般的Git工做流程: 服务器

git fat init
git fat push
git fat pull

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

您可使用普通的git add添加二进制文件,后者又会根据您的gitattributes规则调用git fatmaven

最后,它的优势是能够在存储库和用户之间共享实际存储二进制文件的位置,并支持rsync所作的任何事情。 测试

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


#2楼

看看camlistore 。 它并非真正基于Git的,可是我发现它更适合您的工做。 gradle


#3楼

自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


#4楼

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

TL; DR 12-01-2017若是可使用github的LFS或其余第三方,则应采起全部措施。 若是不能,请继续阅读。 请注意,此解决方案是骇客,应这样对待。

OTABS的理想特性

  • 它是一个纯git仅git的解决方案-它无需任何第三方软件(如git-annex)或第三方软件(如github的LFS)便可完成工做。
  • 有效地存储二进制文件,即不会使存储库的历史膨胀。
  • git pullgit fetch ,包括git fetch --all仍然对带宽有效 ,也就是说,默认状况下并不是全部大型二进制文件都是从远程提取的。
  • 它能够在Windows上运行
  • 它将全部内容存储在一个git仓库中
  • 它容许删除过期的二进制文件(与bup不一样)。

OTABS的不良特性

  • 它使git clone可能效率低下(但不必定取决于您的用法)。 若是部署此解决方案,则可能必须建议您的同事使用git clone -b master --single-branch <url>代替git clone 。 这是由于git clone默认会从字面上克隆整个存储库,包括一般不但愿浪费带宽的内容,例如未引用的提交。 取自SO 4811434
  • 它使git fetch <remote> --tags带宽效率低下,但不必定存储效率低下。 您能够随时建议您的同事不要使用它。
  • 您将必须按期使用git gc技巧从不须要的文件中清除存储库。
  • 它不如bupgit-bigfiles有效 。 可是它分别更适合您要尝试的操做和更现成的。 您可能会遇到成千上万个小文件或千兆字节范围内的文件的麻烦,但请继续阅读以获取解决方法。

添加二进制文件

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

  1. 建立一个新的孤立分支。 git checkout --orphan binaryStuff能够解决问题。 这将产生一个与其余分支彻底断开链接的分支,而且您将在该分支中进行的第一次提交将没有父项,这将使其成为根提交。
  2. 使用git rm --cached * .gitignore清理索引。
  3. 深呼吸,使用rm -fr * .gitignore删除整个工做树。 内部.git目录将保持不变,由于*通配符与之不匹配。
  4. 复制到您的VeryBigBinary.exe或VeryHeavyDirectory /中。
  5. 添加并提交。
  6. 如今,它变得棘手-若是将它做为一个分支推送到远程,则全部开发人员在下次调用git fetch阻塞其链接时都将下载它。 您能够经过推送标签而不是分支来避免这种状况。 若是他们习惯键入git fetch <remote> --tags ,这仍然会影响您同事的带宽和文件系统存储,但请继续阅读以寻求解决方法。 继续并git tag 1.0.0bin
  7. 推送您的孤儿标签git push <remote> 1.0.0bin
  8. 如此一来,您就永远不会意外推送二进制分支,能够将其删除git branch -D binaryStuff 。 您的提交不会被标记为垃圾回收,由于指向它的1.0.0bin孤儿标记足以使其存活。

签出二进制文件

  1. 我(或个人同事)如何将VeryBigBinary.exe检出到当前工做树中? 例如,若是您当前的工做分支是master,则能够简单地git checkout 1.0.0bin -- VeryBigBinary.exe
  2. 若是您没有下载孤儿标签1.0.0bin ,这将失败,在这种状况下,您必须事先git fetch <remote> 1.0.0bin
  3. 您能够将VeryBigBinary.exe添加到母版的.gitignore ,这样团队中的任何人都不会偶然用二进制文件污染项目的主要历史记录。

彻底删除二进制文件

若是您决定从本地存储库,远程存储库和同事的存储库中彻底清除VeryBigBinary.exe,则能够:

  1. 删除远程git push <remote> :refs/tags/1.0.0bin上的孤立标签git push <remote> :refs/tags/1.0.0bin
  2. 本地删除孤立标记(删除全部其余未引用的标记) git tag -l | xargs git tag -d && git fetch --tags git tag -l | xargs git tag -d && git fetch --tags 。 取自SO 1841341 ,稍做修改。
  3. 使用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
  4. 若是可能,请在遥控器上重复git gc技巧。 若是您是自托管存储库,则多是这样,而某些git提供程序(例如github)或某些公司环境中可能没法实现。 若是您使用的服务提供商托管的ssh不能使您远程访问ssh,请放手。 您的提供商的基础结构可能会在本身的美好时光中清理未引用的提交。 若是您在公司环境中,则能够建议IT部门执行cron做业垃圾回收,每周大约一次。 只要您建议您的同事始终使用git clone -b master --single-branch <url>而不是git clone不管它们是否在带宽和存储方面都不会对您的团队产生任何影响。
  5. 您全部想摆脱过期的孤儿标签的同事都只需执行步骤2-3。
  6. 而后,您能够重复添加二进制文件以建立新的孤立标记2.0.0bin的步骤1-8。 若是您担忧同事键入git fetch <remote> --tags ,则实际上能够将其从新命名为1.0.0bin 。 这将确保下次他们获取全部标签时,不会引用旧的1.0.0bin并将其标记为后续垃圾回收(使用步骤3)。 当您尝试覆盖远程服务器上的标签时,您必须像这样使用-fgit push -f <remote> <tagname>标签名git 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>应该为您完成。


#5楼

SVN彷佛比Git更有效地处理二进制增量。

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

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

所以,个人选择是对源代码使用Git,对文档等二进制文件使用SVN。

相关文章
相关标签/搜索