TL;DR
ミニマムなバージョンアップを行いたいときは bundle update --conservative
を使おう
gem の更新
ライブラリのバージョンアップをしようとしているとする。単に bundle update
と叩いてすべての依存を一括でバージョンアップするのは、差分を追うことがまず不可能になってしまうから、個別のライブラリをひとつずつアップグレードしていきたい。
功利的にも、例えば LRU 方式で一日ひとつずつのライブラリをアップグレードしていく、くらいのやり方であれば、それなりの頻度で更新を行っていけるし、チームに対してもよい影響を与えていけるだろう。
というわけで、個別のライブラリをターゲットに bundle update
を実施したいわけであるが、必ずしもそれで十分ではないことがある。変更範囲を最小限に bundle update
を実行するには、 --conservative
オプションを使おう、というのが今日の学びである。
サンプル
適当な Gemfile と Gemfile.lock を用意してみた。
Gemfile に記載された3つの gem のうち、 Gemfile.lock に定義されたバージョンと最新バージョンの乖離をテーブル化するとこうなる。
name | current_version | upstream_version |
---|---|---|
capistrano | 3.11.0 | 3.14.1 |
capistrano-bundler | 1.4.0 | 2.0.1 |
capistrano-rails | 1.4.0 | 1.6.1 |
# frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } group :development do gem 'capistrano' gem 'capistrano-bundler' gem 'capistrano-rails' end
GEM remote: https://rubygems.org/ specs: airbrussh (1.4.0) sshkit (>= 1.6.1, != 1.7.0) capistrano (3.11.0) airbrussh (>= 1.0.0) i18n rake (>= 10.0.0) sshkit (>= 1.9.0) capistrano-bundler (1.4.0) capistrano (~> 3.1) sshkit (~> 1.2) capistrano-rails (1.4.0) capistrano (~> 3.1) capistrano-bundler (~> 1.1) concurrent-ruby (1.1.7) i18n (1.8.5) concurrent-ruby (~> 1.0) net-scp (3.0.0) net-ssh (>= 2.6.5, < 7.0.0) net-ssh (6.1.0) rake (13.0.1) sshkit (1.21.1) net-scp (>= 1.1.2) net-ssh (>= 2.8.0) PLATFORMS ruby DEPENDENCIES capistrano capistrano-bundler capistrano-rails BUNDLED WITH 2.1.4
この設定のプロジェクトについて、 capistrano-rails
だけを最新バージョンに更新してみよう。
単に bundle update capistrano-rails
を実行する
単に bundle update capistrano-rails
と実行すると、差分としてはこうなる。
specs: airbrussh (1.4.0) sshkit (>= 1.6.1, != 1.7.0) - capistrano (3.11.0) + capistrano (3.14.1) airbrussh (>= 1.0.0) i18n rake (>= 10.0.0) sshkit (>= 1.9.0) - capistrano-bundler (1.4.0) + capistrano-bundler (2.0.1) capistrano (~> 3.1) - sshkit (~> 1.2) - capistrano-rails (1.4.0) + capistrano-rails (1.6.1) capistrano (~> 3.1) - capistrano-bundler (~> 1.1) + capistrano-bundler (>= 1.1, < 3) concurrent-ruby (1.1.7) i18n (1.8.5) concurrent-ruby (~> 1.0)
capistrano-rails
だけを更新することを意図したつもりが、依存先の capistrano
と capistrano-bundler
も同時に更新されている。依存は解決されているため現実的に問題ないかもしれないとはいえ、例えば capistrano-bundler
のメジャーバージョンが意図せず上がってしまっているのは実に気持ちが悪い。あくまで capistrano-rails
を単体で更新するにはどうするのがよいだろう?
--conservative
オプションを与えて実行する
bundle update capistrano-rails --conservative
とオプションを追加してあげればよい。結果、次の通りにきちんと狙った gem だけが更新できており、依存先の更新を巻き込んでしまわずに済んでいる。
specs: airbrussh (1.4.0) sshkit (>= 1.6.1, != 1.7.0) capistrano (3.11.0) airbrussh (>= 1.0.0) i18n rake (>= 10.0.0) sshkit (>= 1.9.0) capistrano-bundler (1.4.0) capistrano (~> 3.1) sshkit (~> 1.2) - capistrano-rails (1.4.0) + capistrano-rails (1.6.1) capistrano (~> 3.1) - capistrano-bundler (~> 1.1) + capistrano-bundler (>= 1.1, < 3) concurrent-ruby (1.1.7) i18n (1.8.5) concurrent-ruby (~> 1.0)
conservative
というと必ずしもいい響きに聞こえないけれども、ことライブラリの更新というタスクについていうと、保守的に進めて悪いことなんかないと思っている。というより、デフォルトの振る舞いが --conservative
であることを期待していた身にとっては、オプションを明示しない限り変更範囲が最小とならないというのはちょっと意外であった。思わぬ形でえた学びとして、正しく Today I Learned であった。