Gardenscapes如何几乎被挫败一次

免责声明:这个故事发生在几年前。但是似乎它仍然没有失去其相关性。





...我们开发了Gardenscapes。它仍然保留了Windows下旧的Gardenscapes的痕迹。它甚至都不是Match-3,而是一个隐藏的对象。没有人甚至无法想象游戏将达到高度



然后是美好的一天...



一切如何开始



访问存储库时,我们看到以下消息:



“此存储库已被禁用。由于过度使用资源,违反了我们的服务条款,GitHub工作人员已禁止访问此存储库。请联系支持以恢复对该存储库的访问。阅读此处以了解有关减小存储库大小的更多信息。”



您可能已经猜到了,我们使用github托管git存储库。因此,突然之间,没有宣战,github阻止了我们的存储库超出了允许的最大大小。没有提供他们网站上的确切数字。锁定时,.git文件夹的大小约为25 GB。 (注意2020:现在限制更高了,并且github站点明确指出存储库的大小不应超过100 GB)。



我们如何设法建立这么大的存储库?原因很明显:我们在其中存储二进制文件。到处都写着不建议这样做,但这对我们来说要容易得多。我们希望立即从存储库中启动游戏,而无需付出额外的努力。因此,我们将图形和其他游戏资源提交到资源库。



但这还不错。我们从整个故事中学到了一个重要的教训:永远不要告诉任何人有关Fight Club的信息,您不能将二进制文件频繁更改的文件提交到存储库。我们做到了:我们提交了可执行文件和纹理图集。现在,我们变得更加聪明了,我们拥有Teamcity,可以编译二进制文件并构建地图集,以及可以将所有这些东西下载给用户的特殊脚本。但这是一个完全不同的故事... 对于超大文件,我们使用Git LFS,Google Drive和其他文明优势。



为历史而战



因此,任何人都无法使用。我们告诉团队,他们将不得不在当地工作一天,但不要非常努力,否则他们将在以后解决冲突(每个人都非常沮丧,并立即去喝茶)。他们开始思考该怎么做。很明显,需要一个新的存储库,但是在那里提交什么呢?一个简单的方法是所有分支的当前状态。但是我们不是很喜欢它,因为更改的历史将丢失,每个人都喜欢的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的更多信息,包括我们的博客:



  1. Git:新手技巧-第1部分
  2. Git:新手技巧-第2部分
  3. Git:新手技巧-第3部分


因此,我们在本地有很多提交,这些提交是正确的,也就是说,没有二进制文件的历史记录。看起来执行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。同时,所有重要的提交历史记录-除二进制文件外的所有内容都将保留。游戏设计师喝了比平时更多的茶。程序员获得了难忘的经历。他们急切地开始考虑如何执行此操作,这样就不必将可执行文件提交到存储库,但同时进行将很方便。



All Articles