読者です 読者をやめる 読者になる 読者になる

Gemfile.lockのマージミスってハマった話

結論を言えば、マージ気をつけましょう、以上って感じなのだけど、少し実験する。

  • ruby 2.4.1
  • gem 2.6.11
  • bundler 1.4.16

例えば以下のような Gemfile を書いたとする。

source 'https://rubygems.org' do
  gem 'rake'
  gem 'rspec'
end

これをbundle installすると、以下のような Gemfile.lock が生成される。

GEM
  remote: https://rubygems.org/
  specs:
    diff-lcs (1.2.5)
    rake (12.0.0)
    rspec (3.5.0)
      rspec-core (~> 3.5.0)
      rspec-expectations (~> 3.5.0)
      rspec-mocks (~> 3.5.0)
    rspec-core (3.5.4)
      rspec-support (~> 3.5.0)
    rspec-expectations (3.5.0)
      diff-lcs (>= 1.2.0, < 2.0)
      rspec-support (~> 3.5.0)
    rspec-mocks (3.5.0)
      diff-lcs (>= 1.2.0, < 2.0)
      rspec-support (~> 3.5.0)
    rspec-support (3.5.0)

PLATFORMS
  ruby

DEPENDENCIES
  rake!
  rspec!

BUNDLED WITH
   1.14.6

DEPENDENCIES の項に、実際に記述したgem一覧が書かれていて、 GEM の項には、実際に必要となるgem(依存の依存の・・・と辿ったものを含む)とそのバージョン、そして依存treeが記載されている。

Rubyコンソールで Bundler.require すると、これらのgemがrequireされ、使えるようになっていることがわかる。

[1] pry(main)> require 'bundler'
=> true
[2] pry(main)> Bundler.require
=> [Gem::Dependency.new("rake", Gem::Requirement.new([">= 0"]), :runtime),
 Gem::Dependency.new("rspec", Gem::Requirement.new([">= 0"]), :runtime)]
[3] pry(main)> Rake
=> Rake

ここで、 Gemfile.lockGEM の項のみから rake を消してみる。

GEM
  remote: https://rubygems.org/
  specs:
    diff-lcs (1.2.5)
    rspec (3.5.0)
      rspec-core (~> 3.5.0)
      rspec-expectations (~> 3.5.0)
      rspec-mocks (~> 3.5.0)
    rspec-core (3.5.4)
      rspec-support (~> 3.5.0)
    rspec-expectations (3.5.0)
      diff-lcs (>= 1.2.0, < 2.0)
      rspec-support (~> 3.5.0)
    rspec-mocks (3.5.0)
      diff-lcs (>= 1.2.0, < 2.0)
      rspec-support (~> 3.5.0)
    rspec-support (3.5.0)

PLATFORMS
  ruby

DEPENDENCIES
  rake!
  rspec!

BUNDLED WITH
   1.14.6

人間が見ると、 GEM の項と DEPENDENCIES の項が矛盾しているが、この状態で bundle install しても、 Gemfile.lock はrakeの行が消えたままで変化しない

この状態で、もう一度Rubyコンソールを叩いてみる。

[1] pry(main)> require 'bundler'
=> true
[2] pry(main)> Bundler.require
=> [Gem::Dependency.new("rake", Gem::Requirement.new([">= 0"]), :runtime),
 Gem::Dependency.new("rspec", Gem::Requirement.new([">= 0"]), :runtime)]
[3] pry(main)> Rake
NameError: uninitialized constant Rake
from (pry):3:in `__pry__'

Bundler.requirerake を認識しているが、実際には rake はrequireされていないので、実行時エラーになる。

まとめ

git mergeするときに Gemfile.lock のマージをミスると、

  • bundlerがエラーを吐いていないことを確認
  • 念のため bundle install してみる

などをしても気づかず、実行して初めて気づくということが、起こり得るよ。