Ruby の初心者向け記事を眺めていると,Gemfile.lock について誤解していると思われる記述が目につきます。
そんなアレコレをこの記事では見ていきます。
最初に,Gemfile と Gemfile.lock についておさらいをしておきましょう。
まず,Gemfile はそのプロジェクトで使用する gem を指定するものでしたね。
gem の名前だけでなくバージョンも指定することができます。「○○以上」「○○未満」のような幅をもった指定もできます。また,
gem "hoge", "~> 3.5.2"
と書けば,hoge
gem で,「3.5.2 以上,3.6.0 未満」という意味の指定になるのでした。
一方,Gemfile.lock は,Bundler によって生成されるファイルでした。
Gemfile.lock がまだ存在しない状態で,
bundle install
とすると,Bundler は Gemfile の記述を元に gem をインストールしていくのですが,さきほどの記述を例に取ると,hoge
gem の「3.5.2 以上,3.6.0 未満」を満たすバージョンのうち,実際に存在している最も高いバージョンの gem を選びます。そしてそのバージョンを Gemfile.lock に記録し,まだインストールされていない場合はインストールします。
ここで以下のような誤解が生じます。
- Gemfile.lock にはインストールされている gem のバージョンが書かれている。
確かに上述の状況ではそのようになります。
しかし,Gemfile.lock が生成されたあとで当該の gem をアンインストールすることができます。
また,チーム開発などでは,誰かの環境で作られた Gemfile.lock が Git 管理されて自分の手元にやってくることもありますね。この場合,そこに書かれた gem はこちらではまだインストールされていないかもしれません。
それに,Gemfile.lock に書かれていないバージョンの gem もインストールされているかもしれません。
こうしてみると,Gemfile.lock の記述と(あなたの環境に)インストールされている gem(のバージョン)は無関係と言えることが分かります。
Gemfile.lock は,「そのプロジェクトにおいて現時点で使うことになっている gem(のバージョン)」が記述されている,と考えればいいと思います。
次に,よくある誤解が
- Gemfile.lock が存在する場合,
bundle install
すると,Gemfile.lock に従って gem がインストールされる。
です。
わりと正しいのですが,既にインストールされている場合はインストールは行われませんし(当たり前),Gemfile.lock に従わないケースすらあります。
それは Gemfile.lock に書かれたバージョンが Gemfile に書かれたバージョンの条件を満たさない場合です。
例えば,Gemfile.lock が 1.0.3
となっているときに,Gemfile のほうを >= 1.1
と書き換えたら,bundle install
では 1.0.3
は採用されず,>= 1.1
を満たすバージョンが選ばれ,Gemfile.lock は書き換えられることになります。
Gemfile と Gemfile.lock の関係はちょっぴりだけ複雑です。