博客
2015 年 2 月 1 日
撰写历史,实际上是对历史进行重写。
作者:Arthur Nogueira Neves
问题
RubyGems.org 正在失控,但问题并不在于代码,而是 git 存储库实在是太大了。每次有人想要克隆存储库时,都将需要很长时间,因为该存储库的大小超过了 500MB。代码本身并不是很大,但我们需要打包我们使用的所有宝石。你可能想知道,为什么我们需要打包 RubyGems.org 宝石依赖项。当大多数项目在部署时都可以简单地从 RubyGems.org 安装宝石。但 RubyGems.org 本身可能存在会导致其不可用的严重错误。部署此类错误的唯一方法是确保 RubyGems.org 代码库并不依赖于 RubyGems.org 服务的可用性。打包 100 多个宝石会消耗空间,而且每次都会更新新的宝石时,旧版本都会永久地保留在历史记录中。Git 是分布式源代码管理,当克隆存储库时,你将克隆与它们关联的所有分支、标签和历史记录。话虽如此,存储库只会不断增长,而且克隆也会变得越来越困难。
其他解决方案
运行 git clone --depth=1
将是一种更简单的解决方案。然而,此方法的问题在于,每个克隆存储库的人都必须了解 depth
标志。此方法的另一个问题是,你不会在本地克隆历史记录,因此搜索或类似 git-blame
之类的东西将无法正常工作。
解决方案
在另一个 git 存储库中创建一个单独的 vendor/cache
文件夹,并将其添加为 git 子模块。如果 vendor/cache
文件夹不属于主存储库,则该文件夹的历史记录将不会受到主存储库的跟踪。因此,随着每个宝石更新,RubyGems.org 存储库将不会大量增长。
然而,这并不能解决 600MB 的存储库问题。为了解决此问题,我们必须重写存储库的历史记录,以从历史记录中删除所有打包的文件。而这正是我们所做的。在我们重写历史记录时,我们还决定从历史记录中删除一些其他大型文件夹和文件
- server/rubygems.html
- rubygems.txt
- server/rubygems.txt
- vendor/bundler_gems
- vendor/gems
- vendor/rails
- 供应商/插件
最后,我们将供应商/缓存
从历史记录移至另一个存储库
为什么?
RubyGems.org 是一个开源项目,始终欢迎贡献,因此,一个较小且更快的存储库是使社区更能接近该项目的关键。
最终结果
$ git clone [email protected]:rubygems/rubygems.org-backup.git
$ du -skh .
536M .
$ git clone [email protected]:rubygems/rubygems.org.git
$ du -skh .
11M .
对开发的影响
每个人都必须变基
任何针对rubygems/rubygems.org
拥有公关的每个人都必须针对新历史记录进行变基。在本地,这意味着rubygems/rubygems.org
的克隆可以将其删除并再次克隆,或者仅git fetch --all; git pull --rebase
。
安装依赖项
没有改变,仍然bundle install
将会完成其工作。
更新或添加新的 gem
只需将 gem 添加到Gemfile
或运行bundle update gem_name
,然后仅向Gemfile
和Gemfile.lock
发送包含更改的公关。不再需要更新供应商/缓存
文件夹或向供应商存储库发送公关。RubyGems 团队将确保更新供应商文件夹。