...我们开发了Gardenscapes。它仍然保留了Windows下旧的Gardenscapes的痕迹。它甚至都不是Match-3,而是一个隐藏的对象。没有人甚至无法想象游戏将达到的高度。
然后是美好的一天...
一切如何开始
访问存储库时,我们看到以下消息:
“此存储库已被禁用。由于过度使用资源,违反了我们的服务条款,GitHub工作人员已禁止访问此存储库。请联系支持以恢复对该存储库的访问。阅读此处以了解有关减小存储库大小的更多信息。”
您可能已经猜到了,我们使用github托管git存储库。因此,突然之间,没有宣战,github阻止了我们的存储库超出了允许的最大大小。没有提供他们网站上的确切数字。锁定时,.git文件夹的大小约为25 GB。 (注意2020:现在限制更高了,并且github站点明确指出存储库的大小不应超过100 GB)。
我们如何设法建立这么大的存储库?原因很明显:我们在其中存储二进制文件。到处都写着不建议这样做,但这对我们来说要容易得多。我们希望立即从存储库中启动游戏,而无需付出额外的努力。因此,我们将图形和其他游戏资源提交到资源库。
但这还不错。我们从整个故事中学到了一个重要的教训:永远不要
为历史而战
因此,任何人都无法使用。我们告诉团队,他们将不得不在当地工作一天,但不要非常努力,否则他们将在以后解决冲突(每个人都非常沮丧,并立即去喝茶)。他们开始思考该怎么做。很明显,需要一个新的存储库,但是在那里提交什么呢?一个简单的方法是所有分支的当前状态。但是我们不是很喜欢它,因为更改的历史将丢失,每个人都喜欢的git blame命令将中断,并且所有内容都会翻筋斗。因此,我们决定这样做:擦除二进制文件的历史记录,并保留文本文件的历史记录。
步骤1.删除二进制文件的历史记录
我们拥有该存储库的完整本地副本。我们要做的第一件事是找到出色的BFG Repo-Cleaner实用程序。同时非常简单和快速,而且名称很好。
执行场景示例:
java -jar bfg.jar bfg --delete-files *.{pvrtc,webp,png,jpeg,fla,swl,swf,pbi,bin,mask,ods,ogv,ogg,ttf,mp4} path_to_repository
参数包含我们可以提供的二进制文件的所有扩展名。从世界上所有提交中,有关具有这些扩展名的文件的信息都将被删除。该实用程序很智能,删除文件的历史记录时会保留其最新版本。此外,此最新版本将包含在分支的最新提交中。我们还想删除exe和dll文件的历史记录,但该实用程序出现了错误。显然,由于某种原因,禁止使用* .exe形式的处理。此外,如果您明确指定一个文件,例如gardenscapes.exe,则一切正常。(注意2020:该错误可能已经修复)。
步骤2.压缩存储库
第一步之后,存储库的大小仍然很大。这样做的原因是git的工作方式。我们仅删除了文件链接,但文件本身仍然保留。
要物理删除文件,您需要运行git gc命令,即:
git reflog expire --expire=now --all
然后:
git gc --prune=now --aggressive
这是实用程序作者推荐的命令序列。在这里,gc确实需要很长时间。另外,使用默认存储库设置,git客户端没有足够的内存来完成操作,并且需要使用铃鼓跳舞。(注意2020:当时我们有一个32位版本的git。最有可能的是,这些问题不再出现在64位版本中)。
步骤3.将提交写入新存储库
事实证明,这是任务中最有趣的部分。
要了解后面的内容,您需要了解git的工作原理。您可以在许多地方阅读有关git的更多信息,包括我们的博客:
因此,我们在本地有很多提交,这些提交是正确的,也就是说,没有二进制文件的历史记录。看起来执行git push就足够了,并且一切都会自动进行。但不是!
如果只执行命令git push -u master,然后git兴高采烈地开始将数据上传到服务器的过程,但是由于大约2 GB的错误而崩溃。这意味着您将无法一次上传这么多的提交。我们将部分吃掉大象。我们认为2,000次提交可能适合2GB。这样,我们存储库的总大小约为20,000次提交,分布在4个分支之间:master-v101-v102-v103。(注意2020:嗯,青年!从那时起,一切都变得更加严重。此存储库中已经有超过100,000个提交,并且有几十个发布分支。同时,我们仍然符合Github限制)
首先,我们考虑分支的提交数量帮助命令:
git rev-list --count <branch-name>
例如,master分支中大约有10,000个提交。现在,我们可以对git push命令使用扩展语法,即:
git push -u origin HEAD~8000:refs/origin/master
HEAD〜8000:refs / origin / master是所谓的refspec。左侧说您需要进行一次提交,直到HEAD为止的提交距离为8,000,即仅2,000次提交。右侧是您需要将它们推送到远程主分支。此处需要refs / origin / master分支的完整路径。
之后,仍然没有master分支,例如,git fetch将无法下载它。这不足为奇-毕竟,指向她的HEAD的提交还不存在。尽管如此,通过重复命令git push HEAD〜8000:refs / origin / master,我们看到了这些提交已经在服务器上的答案,因此工作已经完成。
接下来,我们认为该过程很清楚,其余工作可以分配给该脚本。最后的提交将非常大,因为所有二进制文件都将包含在其中。因此,以防万一,最后10次提交将分别填写。脚本结果如下:
git push origin HEAD~6000:refs/origin/master
git push origin HEAD~5000:refs/origin/master
git push origin HEAD~4000:refs/origin/master
git push origin HEAD~3000:refs/origin/master
git push origin HEAD~2000:refs/origin/master
git push origin HEAD~1000:refs/origin/master
git push origin HEAD~10:refs/origin/master
git push origin master
git checkout v101
git push -u origin HEAD~1000:refs/origin/v101
git push origin HEAD~10:refs/origin/v101
git push origin v101
git checkout v102
… ..
也就是说,我们始终将所有分支写入服务器,每次推送2,000次提交,最后10次单独提交。
整个故事花了很多时间,晚上的时钟显示为接近12点。因此,我们把剧本留了一夜,向克苏鲁祈祷(注2020:当时还是比较受欢迎),然后回家了。
决赛。好结局
早晨,在github站点上打开存储库后,我们确保脚本成功运行并且所有提交和分支均已就绪。
结果:存储库(.git文件夹)的大小已从25 GB减少到7.5 GB。同时,所有重要的提交历史记录-除二进制文件外的所有内容都将保留。游戏设计师喝了比平时更多的茶。程序员获得了难忘的经历。他们急切地开始考虑如何执行此操作,这样就不必将可执行文件提交到存储库,但同时进行将很方便。