はじめに
ここ数日になって、Ruby project に関わり始めた新米が 「Bundle update ***
すると実際に何が起きるんだ?」 という疑問について調べてまとめてみました。
間違ってるよ、とか、公式のここにちゃんと書いてあるよ、等あればやさしく教えて下さい m(_ _)m
(そもそも) Bundle update *gems とは?
bundle update rails
の様に、指定した GEM をアップデートする際に使用します。
実際にはアップデートされるのは指定した GEM だけではなく以下の2点になります。
- 指定した GEM (↑のケースでは
rails
) - 指定した GEM の 全ての依存 (rails の場合 actioncable, railties, ... ) と、その子孫
For instance, in the scenario above, imagine that nokogiri releases version 1.4.4, and you want to update it without updating Rails and all of its dependencies. To do this, run bundle update nokogiri.
Bundler will update nokogiri and any of its dependencies, but leave alone Rails and its dependencies.
指定した GEM のみを上げたい (不必要に依存は上げたくない) 場合は --conservative
オプションを使用します。
bundle update --conservative rails
説明の前提
以降、以下のような GEM, プロジェクトがある〜という前提で話を進めます。
Gems
GEM Name | Version | 依存 GEM |
---|---|---|
gem-common | 1.0 | -- |
1.1 | -- | |
2.0 | -- | |
gem-a | 1.0 | gem-common (= 1.0) |
1.1 | gem-common (= 1.1) | |
2.0 | gem-common (= 2.0) | |
gem-b | 1.0 | gem-common (~> 1.0) |
1.1 | gem-common (~> 1.0) | |
2.0 | gem-common (~> 2.0) |
Gemfile (.lock)
既にプロジェクトに ↓ の Gemfile (.lock) があるものとします。
Gemfile
source 'https://rubygems.org'
gem 'gem-a'
gem 'gem-b'
Gemfile.lock
GEM
remote: https://rubygems.org/
specs:
gem-common (1.0)
gem-a (1.0)
gem-common (= 1.0)
gem-b (1.0)
gem-common (~> 1.0)
この .lock ファイルが作られた当時は、
1.0
が最新だったのでしょう、という仮定。
検証 (ケーススタディ)
1-1. Gemfile を変更しないで bundle update gem-a
Gemfile を変更せずに bundle update gem-a
をします。
source 'https://rubygems.org'
gem 'gem-a'
gem 'gem-b'
結果、 gem-a
は 1.1
に、gem-common
も 1.1
にアップデートされます。
2.0
にはなりません!gem-b
の依存gem-common (~> 1.0)
を満たさないからです。
GEM
remote: https://rubygems.org/
specs:
- gem-common (1.0)
- gem-a (1.0)
- gem-common (= 1.1)
+ gem-common (1.1)
+ gem-a (1.1)
+ gem-common (= 1.1)
gem-b (1.0)
gem-common (~> 1.0)
1-2. Gemfile を変更しないで bundle update gem-b
Gemfile を変更せずに bundle update gem-b
をします。
source 'https://rubygems.org'
gem 'gem-a'
gem 'gem-b'
結果、 gem-b
は 1.1
にアップデートされます。
gem-common
は元のバージョンのままです。
gem-common
がアップデートされるとgem-a
の依存gem-common (= 1.0)
に違反するからです。
GEM
remote: https://rubygems.org/
specs:
gem-common (1.0)
gem-a (1.0)
gem-common (= 1.0)
- gem-b (1.0)
+ gem-b (1.1)
gem-common (~> 1.0)
2-1. バージョン 2.0
を指定して bundle update gem-a
バージョン 2.0
を指定して bundle update gem-a
をします。
source 'https://rubygems.org'
#
- gem 'gem-a'
+ gem 'gem-a', '= 2.0'
gem 'gem-b'
結果、以下のエラーが発生して、アップデート (.lock ファイルの更新) はされません。
gem-a
の依存 gem-common
を 2.0
にしたいが、それは gem-b
(※アップデート対象ではない!) の依存 gem-common (~> 1.0)
に違反するからです。
Bundler could not find compatible versions for gem "gem-common":
In Gemfile:
gem-a (= 2.0) was resolved to 2.0, which depends on
gem-common (= 2.0)
gem-b was resolved to 1.0, which depends on
gem-common (~> 1.0)
Running `bundle update` will rebuild your snapshot from scratch, using only
the gems in your Gemfile, which may resolve the conflict.
この場合は、コマンドを bundle update gem-a gem-b
に変えて、gem-a
, gem-b
両方ともアップデート対象にします。
GEM
remote: https://rubygems.org/
specs:
- gem-common (1.0)
- gem-a (1.0)
- gem-common (= 1.0)
- gem-b (1.0)
- gem-common (~> 1.0)
+ gem-common (2.0)
+ gem-a (2.0)
+ gem-common (= 2.0)
+ gem-b (2.0)
+ gem-common (~> 2.0)
無事に両方とも 2.0
にアップデートされました。
つまり、Gemfile の
gem 'gem-a', '= 2.0'
バージョン指定は不必要だった (gem 'gem-a'
のままでいい) という事になります。