使用gitpipe理大型二进制文件

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

  1. 手动复制二进制文件。
    • 临:不确定。
    • Contra:我强烈反对这一点,因为它增加了在build立一个新站点/迁移旧站点时出现错误的可能性。 build立另一个障碍。
  2. git来pipe理它们。
    • 专业版:删除“忘记”复制重要文件的可能性
    • Contra:扩大版本库并降低pipe理代码库和checkouts / clone / etc的灵活性需要相当长的一段时间。
  3. 分开的存储库。
    • 专业版:检出/克隆源代码的速度一如既往,并且图像被正确存档在自己的存储库中。
    • Contra:删除在项目上拥有唯一的 git仓库的简单性。 当然会介绍一些我没有想过的事情。

你对此有什么经验/想法?

另外:有没有人有多个git仓库的经验,并在一个项目中pipe理他们?

更新 :这些文件是用于生成包含这些文件的PDF的程序的图像。 文件不会经常变化(如年),但与程序非常相关。 该程序不会没有文件工作。

如果程序在没有文件的情况下无法正常工作,似乎将它们分解成单独的回购是一个坏主意。 我们有大的testing套件,我们闯入单独的回购,但这些都是真正的“辅助”文件。

但是,您可能能够在一个单独的回购库中pipe理这些文件,然后使用git-submodule以合理的方式将它们拖到您的项目中。 所以,你仍然有所有的源的完整的历史,但据我了解,你只有一个相关的修改你的图像子模块。 git-submodule设施应该帮助您保持正确版本的代码与图像的正确版本一致。

这里有一个很好的Git Book 子模块介绍 。

我最近发现了git-annex ,我觉得很棒。 它旨在有效地pipe理大型文件。 我把它用于我的照片/音乐(等)collections。 git-annex的开发非常活跃。 文件的内容可以从git repo中删除,只有树层次结构由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上可用。

另一个解决scheme,自2015年4月以来是Git大型文件存储(LFS) (由GitHub)。

它使用git-lfs (请参阅git-lfs.github.com )并使用支持它的服务器进行testing: lfs-test-server
你只能在git仓库中存储元数据,而在其他地方可以存储大型文件。

assets/1319791/7051226/c4570828-ddf4-11e4-87eb-8fc165e5ece4.gif

看看git bup这是一个git扩展,以巧妙地将大型二进制文件存储在git仓库中。

你想把它作为一个子模块,但你不必担心回购难以处理。 他们的示例用例之一是将虚拟机映像存储在git中。

我没有看到更好的压缩率,但我的回购没有真正大的二进制文件。

因人而异

你也可以使用git-fat 。 我喜欢的是它只依赖于股票python和rsync。 它还支持通常的git工作stream程,并带有以下自解释命令:

 git fat init git fat push git fat pull 

另外,你需要将一个.gitfat文件检入你的repo,并修改你的.gitattribute来指定你想要pipe理的文件扩展名。

你使用普通的git add添加一个二进制文件,然后根据你的gitattributes规则调用git fat。

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

更新:如果你使用git-svn桥,不要使用git-fat。 它将最终从您的Subversion存储库中删除二进制文件。 但是,如果您使用的是纯粹的git存储库,那么它的运行效果非常好。

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

几个月前我有一个非常类似的问题:〜21GB的MP3,未分类(坏名字,坏的ID3的,不知道我是否喜欢那个MP3或不…),并在三台电脑复制。

我用一个外部硬盘与主要的仓库回购,我克隆到每台计算机。 然后,我开始习惯性地对它们进行分类(推,拉,合并,删除和重命名多次)。

最后,我在.git目录中只有〜6Gb的mp3和〜83Gb。 我用git-write-tree和git-commit-tree来创build一个新的提交,没有提交祖先,并开始一个新的分支指向提交。 该分支的“git日志”只显示一个提交。

然后,我删除了旧的分支,只保留新的分支,删除ref-logs,并运行“git prune”:之后,我的.git文件夹只加权〜6Gb …

您可以不时用相同的方式“清除”巨大的仓库:您的“git clone”会更快。

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

但是,如果你像我们一样工作,而且如果你的二进制文件不经常修改,那么第一个克隆/检出将会很长,但是之后它应该尽可能快(考虑到你的用户继续使用第一个克隆的回购有)。

我想提出的解决scheme是基于孤儿分支和轻微的滥用标签机制,从此以后被称为孤儿标签二进制存储(OTABS)

TL; DR 12-01-2017如果您可以使用github的LFS或其他第三方,请尽一切办法。 如果不行的话,请继续阅读。 被警告,这个解决scheme是一个黑客,应该这样对待。

OTABS的理想属性

  • 它是一个纯粹的gitgit唯一的解决scheme – 它没有任何第三方软件(如git-annex)或第三方基础设施(如github的LFS)完成工作。
  • 有效地存储二进制文件,即它不会膨胀你的仓库的历史。
  • git pullgit fetch ,包括git fetch --all都仍然具有带宽效率 ,即并不是所有的大型二进制文件都被默认从远程机器中取出。
  • 它在Windows上工作
  • 它将所有东西都存储在一个git仓库中
  • 它允许删除过时的二进制文件(不像bup)。

OTABS的不良性质

  • 它使git clone可能效率低下(但不一定,取决于您的使用情况)。 如果你部署这个解决scheme,你可能不得不build议你的同事使用git clone -b master --single-branch <url>而不是git clone 。 这是因为git clone默认情况下会克隆整个存储库,包括通常不想浪费带宽的东西,比如未提交的提交。 从SO 4811434采取。
  • 它使得git fetch <remote> --tags带宽效率低下,但是不一定存储效率低下。 你总是可以build议你的同事不要使用它。
  • 您将不得不定期使用git gc技巧来清除您不需要的任何文件的存储库。
  • 它不像bup或git-bigfiles那样高效。 但它分别更适合你想要做的和更多的现成的。 您可能会遇到数十万个小文件或千兆字节范围内的文件,但请继续阅读以了解解决方法。

添加二进制文件

在开始之前,请确保您已经提交了所有更改,工作树是最新的,并且您的索引不包含任何未提交的更改。 将所有本地分支机构推送到远程(github等)可能是一个好主意,以防发生任何灾难。

  1. 创build一个新的孤立分支。 git checkout --orphan binaryStuff会做的。 这会产生一个完全与任何其他分支断开的分支,而你在这个分支中做的第一个提交将没有父节点,这将使它成为一个根提交。
  2. 使用git rm --cached * .gitignore清理索引。
  3. 深吸一口气,使用rm -fr * .gitignore删除整个工作树。 内部.git目录将保持不变,因为*通配符不匹配它。
  4. 复制到VeryBigBinary.exe或VeryHeavyDirectory /中。
  5. 添加它&&提交它。
  6. 现在变得棘手 – 如果你把它作为一个分支推送到远程,所有你的开发人员将在下一次调用git fetch堵塞它们的连接时下载它。 您可以通过推送标签而不是分支来避免这种情况。 如果他们习惯于inputgit 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签出到当前工作树中? 如果你目前的工作分支是例如主人,你可以简单地git checkout 1.0.0bin -- VeryBigBinary.exe
  2. 如果你没有下载孤立标签1.0.0bin ,这将失败,在这种情况下,你必须提前git fetch <remote> 1.0.0bin
  3. 您可以将VeryBigBinary.exe添加到您的主控的.gitignore ,这样您团队中的任何人都不会意外地用二进制文件污染项目的主要历史logging。

完全删除二进制文件

如果您决定从本地存储库,远程存储库和同事的存储库中彻底清除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技巧。 如果您自行托pipe您的存储库,并且可能无法使用某些git提供程序(如github或某些企业环境),则可能是这样。 如果你正在与一个提供商托pipe,不让你ssh访问远程只是让它。 您提供商的基础架构可能会在自己的甜蜜时间内清理您的未提交的提交。 如果您处于企业环境中,您可以build议您的IT部门每周运行一次cron作业垃圾收集您的遥控器。 只要你build议你的同事总是git clone -b master --single-branch <url>而不是git clone他们是否会对你的团队在带宽和存储方面没有任何影响。
  5. 你想摆脱过时的孤儿标签的所有同事只需要应用步骤2-3。
  6. 然后,您可以重复添加二进制文件的步骤1-8以创build新的孤立标记2.0.0bin 。 如果你担心你的同事inputgit fetch <remote> --tags你可以再次命名为1.0.0bin 。 这将确保下一次他们获取所有的标签时,旧的1.0.0bin将被重新引用并标记为后续的垃圾收集(使用步骤3)。 当你试图覆盖远程的标签,你必须使用-f像这样: git push -f <remote> <tagname>

后记

  • OTABS不会触及您的主人或任何其他源代码/开发分支。 提交哈希,所有的历史,这些分支小尺寸不受影响。 如果您已经使用二进制文件臃肿了源代码历史logging,则必须将其作为单独的一部分工作来清理。 这个脚本可能是有用的。

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

  • 应用一套标准trics来更有效地存储二进制文件是个好主意。 频繁运行git gc (没有任何额外的参数)可以使git通过使用二进制增量来优化文件的底层存储。 但是,如果您的文件不太可能保持类似于提交提交,则可以完全closures二进制增量。 此外,因为压缩已压缩或encryption的文件(如.zip,.jpg或.crypt)是没有意义的,所以git允许您closures底层存储的压缩。 不幸的是,这是一个全有或全无的设置,也会影响你的源代码。

  • 您可能需要编写部分OTABS脚本,以便更快速地使用。 特别是,从完全删除二进制文件update git钩子的脚本步骤2-3可能会给git fetch一个引人注目的,但也许是危险的语义(“获取和删除所有过时的东西”)。

  • 您可能想要跳过完全删除二进制文件的步骤4,以便以中央资料库膨胀为代价,保留远程计算机上所有二进制文件更改的完整历史logging。 随着时间的推移,本地存储库将保持精简。

  • 在Java世界中,可以将这个解决scheme与maven --offline结合起来,创build一个完全存储在你的版本控制中的可重复的离线版本(maven比gradle更容易)。 在Golang世界里,build立这个解决scheme来pipe理你的GOPATH是可行的,而不是go get 。 在python世界中,可以将这个与virtualenv结合起来,从而生成一个独立的开发环境,而不必依赖PyPi服务器从头开始构build每个版本。

  • 如果您的二进制文件经常更改,比如构build工件,那么将脚本存储5个最新版本的工件的解决scheme脚本monday_bin tuesday_bin标签monday_bintuesday_bin ,…, friday_bin ,以及一个孤立标签中为每个版本1.7.8bin 2.0.0bin ,等等。您可以旋转weekday_bin和每天删除旧的二进制文件。 这样你就可以得到两个最好的世界:你保留你的源代码的整个历史,但只有你的二进制依赖关系的相关历史。 获取给定标签的二进制文件也很容易, 而不需要获取完整的源代码及其所有的历史logging: git init && git remote add <name> <url> && git fetch <name> <tag>应该为你做。

SVN似乎比git更有效地处理二进制三angular形

必须决定版本系统的文件(jpgs,pdfs,odts)。 只是testing添加一个JPEG并旋转90度4次(以检查二进制三angular洲的有效性)。 git的仓库增长了400%。 SVN的存储库只增长了11%

所以看起来SVN在二进制文件上效率更高

所以我的select是git的二进制文件,如文档的源代码和SVN。

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

一旦我的Web应用程序二进制数据超过了3GB的标记,我个人已经与git与我的一些云主机同步失败 。 当时被认为是BFT Repo Cleaner ,但感觉像是黑客。 从那以后,我开始只保留git权限以外的文件,而不是使用 S3等专用工具来pipe理文件,版本和备份。

有没有人有多个Git仓库的经验,并在一个项目中pipe理他们?

是。 雨果的主题主要是这样pipe理的。 这有点古德,但完成了工作。


我的build议是select合适的工具 。 如果是为了一个公司而且你在GitHub上pipe理你的代码行,那就付钱,然后使用Git-LFS。 否则,您可以使用区块链探索更多的创造性选项,例如分散的encryption文件存储 。

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

你看了camlistore这不是真正的git基础,但我觉得它更适合你所要做的。