首页 文章

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

提问于
浏览
508

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

  • 手动复制二进制文件 .

  • 亲:不确定 .

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

  • 用Git管理所有这些 .

  • Pro:删除'forget'复制重要文件的可能性

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

  • 单独的存储库 .

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

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

您对此有何体验?

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

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

12 回答

  • 11

    自2015年4月以来的另一个解决方案是Git Large File Storage (LFS)(由GitHub提供) .

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

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

  • 42

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

    git fat init
    git fat push
    git fat pull
    

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

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

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

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

  • 307

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

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

  • 29

    git clone --filter from Git 2.19 + shallow clones

    这个新选项可能最终成为二进制文件问题的最终解决方案,如果Git和GitHub开发并使其具有足够的用户友好性(例如,他们可以说是still haven't achieved for submodules) .

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

    有了这个,我们可以先做一个浅层克隆,然后自动化使用构建系统为每种类型的构建获取哪些blob .

    甚至已经有一个 --filter=blob:limit<size> 允许限制最大blob大小来获取 .

    我已经提供了该功能的最小详细示例:How do I clone a subdirectory only of a Git repository?

  • 26

    我会使用子模块(如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”会更快 .

  • 21

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

    TL;DR 12-01-2017 如果你可以使用github 's LFS or some other 3rd party, by all means you should. If you can' t,然后继续阅读 . 请注意,这个解决方案是一个黑客,应该这样对待 .

    Desirable properties of OTABS

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

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

    • git pullgit fetch ,包括 git fetch --all 仍然是 bandwidth efficient ,即默认情况下不会从遥控器中提取所有大型二进制文件 .

    • 适用于 Windows .

    • 它将所有内容存储在 single git repository 中 .

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

    Undesirable properties of OTABS

    • 它使 git clone 可能效率低下(但不一定,取决于您的使用情况) . 如果部署此解决方案,您可能需要建议您的同事使用 git clone -b master --single-branch <url> 而不是 git clone . 这是因为默认情况下git clone实际上克隆了 entire 存储库,包括你通常不想浪费带宽的东西,比如未引用的提交 . 取自SO 4811434 .

    • 它使 git fetch <remote> --tags 带宽效率低下,但不一定存储效率低下 . 您可以随时建议您的同事不要使用它 .

    • 您必须定期使用 git gc 技巧从您不想要的任何文件中清除您的存储库 .

    • 它不如bupgit-bigfiles有效 . 但它正在尝试做更多现成的工作 . 您可能会遇到数十万个小文件或数千兆字节文件的问题,但请继续阅读以获取解决方法 .

    Adding the Binary Files

    在开始之前确保您已提交所有更改,您的工作树是最新的,并且您的索引不包含任何未提交的更改 . 如果发生任何灾难,将所有本地分支推送到远程(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 足以使其保持活动状态 .

    Checking out the Binary File

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

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

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

    Completely Deleting the Binary File

    如果您决定从本地存储库,远程存储库和同事的存储库中完全清除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 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) . 当您尝试覆盖遥控器上的标签时,您必须使用 -f ,如下所示: git push -f <remote> <tagname>

    Afterword

    • OTABS并没有使用二进制文件臃肿您的源代码历史记录,您必须将其作为单独的工作进行清理 . This script可能有用 .

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

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

    • 您可能希望编写OTABS的部分脚本以便更快地使用 . 特别是,从完全删除二进制文件到 update git钩子的脚本步骤2-3可以给git fetch("fetch and delete everything that is out of date")一个引人注目但可能是危险的语义 .

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

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

    • 如果您的二进制文件经常更改,例如构建工件,那么编写一个解决方案可能是一个好主意,该解决方案在孤立标签 monday_bintuesday_bin ,..., friday_bin 以及孤儿中存储5个最新版本的工件 . 每个版本的标签 1.7.8bin 2.0.0bin 等 . 您可以每天旋转 weekday_bin 并删除旧的二进制文件 . 通过这种方式,您可以获得两个世界中最好的:保留源代码的 entire 历史记录,但只保留二进制依赖项的 relevant 历史记录 . 获取给定标记的二进制文件也很容易 without 获取包含其所有历史记录的完整源代码: git init && git remote add <name> <url> && git fetch <name> <tag> 应该为您完成 .

  • 12

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

    一旦我的web应用程序二进制数据缺口 above the 3 GB mark ,我个人已经遇到了一些我的 Cloud 主机 synchronisation failures with Git . 我当时认为BFT Repo Cleaner,但感觉就像是黑客 . 从那时起,我开始将文件保留在Git范围之外,而是利用 purpose-built tools (如Amazon S3)来管理文件,版本控制和备份 .

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

    是 . Hugo themes主要以这种方式管理 . 这有点胖,但它完成了工作 .


    我的建议是 choose the right tool for the job . 如果's for a company and you'在GitHub上管理你的代码行付钱并使用Git-LFS . 否则,您可以探索更多创意选项,例如分散式加密file storage using blockchain .

    要考虑的其他选项包括Minios3cmd .

  • 8

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

    但是,您可以在单独的仓库中管理文件,然后使用git-submodule以理智的方式将它们拉入您的项目中 . 所以,你'd still have the full history of all your source but, as I understand it, you' d只有你的图像子模块的一个相关修订版 . git-submodule 工具应该帮助您保持正确版本的代码与图像的正确版本一致 .

    这是来自Git Book的好introduction to submodules .

  • 1

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

  • -1

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

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

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

    你的旅费可能会改变 .

  • 1

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

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

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

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

  • 172

    看看camlistore . 它不是基于Git的,但我发现它更适合你必须做的事情 .

相关问题