Rubygemsを始めとして最近ではどの言語にも便利なパッケージ管理ツールが使えるようになった。多くのパッケージツールはインストールしたパッケージを記載したGemfile.lock
のようなlockファイルを作る。
Gemfile.lock
を消したら動いた、結果オーライみたいなことをウェブで見かけたりして、lockファイルをバージョン管理から外すべきという話があったりする。これはRubygemsに限ったことでなくCocoaPodsの Podfile.lock
などでも結構混乱している人が多いような気がしたのでこれを書いておこうと思った。
lockファイルを管理すべきかどうかはもちろんそのチームの運用による。特に理由がなければアプリケーション開発においては基本的にはバージョン管理し、チームメンバーで共有したほうがよい。
メンバーが同じ環境を構築するため
bundlerであれば Gemfile.lock
があれば Gemfile.lock
ファイルにあるパッケージのバージョンをインストールする。なければ Gemfile
ファイルに従いパッケージをインストールする。
これで何が変わるか?
もし Gemfile
に gem 'rails'
とだけ記載されていた場合 インストールを実行した時点の最新の安定バージョンがインストールされる。つまり lockファイルがないと実行したタイミングでパッケージのバージョンが変わる ということになる。後から実行するばするほど新しいものが入る。
例えば Gemfile.lock
ファイルがなくGemfile
にrailsのバージョンが記載されていないならそれがrails3のアプリケーションでもrails4など新しいバージョンがインストールされてしまう。
つまりlockファイルがないと後からチームに加わった人、マシンの買い替えで新しくセットアップしたとき、時間が経ってから昔のプロジェクトをセットアップしたとき、といったケースで新しいパッケージのバージョンがインストールされてしまい、環境によって動作が異なったり、パッケージのi/fが変わった場合は最悪プログラムが動かなくなる。
他のメンバーや自分があとで同じ環境を構築するためにlockファイルは共有しなければならない。
運用環境と同一にするため
メンバーの環境だけではなく、サーバーアプリケーションでは運用サーバ、クライアントアプリケーションではビルドマシンでも同様にlockファイルは共有すべきである。これらと同じ環境を構築しておかないと自分の環境では起きないのに運用サーバでは起きる、リリースしたビルドバージョンでは起きるという状態になりかねない。
旧バージョンを実行するため
lockファイルを管理する目的は他にもある。アプリケーションの旧バージョンを実行したいとき。
例えばiOSアプリの2.0を進めているときに致命的な問題で1.1をリリースしなければならなくなったとする。このとき1.0のタグから修正を行おうとするが、 Podfile.lock
をバージョン管理していなければその1.0の時点で利用していた依存パッケージのバージョンがわからないので アプリの旧バージョンと同じ実行環境を構築できない という問題が発生する。
最新バージョンの依存パッケージで動けばより改善されたアップデートを作れるかもしれないが、それはあくまで結果オーライであってこういった前回のビルドから何が変わったのかわからない予測不能な状態は避けなければならない。
旧バージョンの実行環境を構築するためにlockファイルはバージョン管理しなければならない。
明示的にバージョンを記載する
lockファイルだけでなく、明示的に Gemfile
や Podfile
にはパッケージのバージョンを明示的に記載しておくのも有効である。lockファイルではあくまで結果的に使うバージョンという意味が強いが Gemfile
や Podfile
に記載すればこのパッケージのこのバージョンを使うというより強い意図を表現できる。
プロトタイプや1人で開発する分には >= x.x.x
といた書き方でも良いと思うが、重要な依存ライブラリについては明示的にバージョンを固定しておき、そのパッケージの更新履歴を確認した上で新しいバージョンに更新するような運用が望ましいと思われる。
まとめ
開発者の環境をなるべく同一にするため、旧バージョンの実行のためlockファイルはバージョン管理すべきファイルである。
lockファイルを共有せず多少パッケージのバージョンが異なってもなんとなく動いてしまうのが怖いところ。時間が経つにつれ差分が大きくなる性質から問題があとになって顕在化してしまう。
lockファイルを管理しない方が良いケースももちろんあるのだが、 動きを理解しないまま自分の環境でlockファイルがなくても動いたので管理しない というやり方だと後で困るよいうだけの話。
今回はRubyGemsやCocoaPodsを例に挙げたが、多くのパッケージ管理ツールがlockファイルを作成し、同じ運用を用いることから同様のことが言えると思う。