Gemfileでのgitオプション利用のリスク

去年の失敗談から。まだ RubyGems にリリースされていない gem について、git オプションを使って以下のような指定をした。多少改変しているけれどだいたいこんな感じ。イメージは伝わると思う。

# Use therubyracer from GitHub until cowboyd/therubyracer#413 is released.
#
# therubyracerにRuby 2.4対応の以下のコミットが含まれたリリースがされたらgitオプションを削除できる。
# https://github.com/cowboyd/therubyracer/commit/f5966bb55a4b0434964d66ef765907d940b4c109
gem 'therubyracer', git: 'https://github.com/cowboyd/therubyracer', ref: 'f5966bb'

Gemfile.lock の方にもこんな感じでコミットのリビジョンが記される。

GIT
  remote: https://github.com/cowboyd/therubyracer
  revision: f5966bb55a4b0434964d66ef765907d940b4c109
  ref: f5966bb
  specs:
    therubyracer (0.12.2)
      libv8 (~> 3.16.14.15)
      ref

結論から言うと、GitHub リポジトリ上で rebase して force push されるとハッシュ値 (リビジョン) が変わって、開発時には存在していた対象コミットがリリース時の bundle install で取得できなくて死ぬ。後出しジャンケンで書いてみれば当たり前の話。

ちなみにこの事例で cowboyd/therubyracer リポジトリ上で rebase して force push したのは自分自身だったので気付く余地はあったわけだけど、基本的に誰がいつどう手を加えるか分からない (自分の管理にない) GitHub 上のコードは生物なので開発時に Gemfile に指定しているコミットがリリース時に存在しているとは限らない。

他にもあるかもだけど思いつくあたりでこのリスクを避ける方法は以下。

  • そもそも git オプションを使わずにリリースされている Gem を使う
  • git オプションを使うなら、自分の (管理できる) リポジトリに fork して指定する
  • 対象の gem (コード) をリリース時の対象物に予め含めておくなど、リリース時の bundle install を不要にしておく

教訓として記しておいた。

追記

2案目について sue445 さんからいいアドバイスをもらえたので追記。