gemのリポジトリにGemfile.lock をコミットするか、gitignoreするか

TL;DR

2017-07-20 から、bundle gem my-awesome-gem の生成物で、Gemfile.lockをgit ignoreしなくなった。
Stop gitignoring Gemfile.lock in default template #5822

なんでgit ignoreしていたのか、なぜするべきなのか、どうしてしなくなったのか、あたりを整理する。
なおわたしはignoreしているほうがいいとおもってる。

きっかけ

わたしがこう反応したら、

そりゃgemの開発者は無いと困るけどさ 利用者のが圧倒的に多いじゃん
理解できねー

こういう反応を複数もらったので。

あれ、利用者がgemfile.lockあってなんか困ります?

直接それが原因では困らないが、実質困るケースが増えると思う。

環境

$ ruby -v
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]

$ bundle --version
Bundler version 1.16.2

$ bundle gem test-pack
(snip)

$ cat .gitignore
/.bundle/
/.yardoc
/_yardoc/
/coverage/
/doc/
/pkg/
/spec/reports/
/tmp/

定説的なやつ

たとえばrailsアプリなど、アプリケーションはGemfile.lockをコミットすべき。
gemはGemfile.lockをコミットしないべき。

どっかできいたことあるはず。んで、よく引き合いに出されるのがClarifying the Roles of the .gemspec and Gemfile

日本語訳はgemspecとGemfileの役割をはっきりさせておく
許可取ってるか取ってないかわからない(許可取ってたらごめんね)翻訳ですが、これを勝手に許可無く掘り起こしてる人がいる。

今読み返すと、それコミットしてもいいでしょ、って言えるぐらいだなー。なので掘り下げる。

gem installやbundle installでrubygems.org 及びそのクローンの場合

metadataをみてるはず(要出典)。

metadataってなんだよ

$ bundle exec rake build

test-pack-0.1.0.gemができる
中身は
checksums.yaml.gz
data.tar.gz
metadata.gz

metadataの中身はこう。

--- !ruby/object:Gem::Specification
name: test-pack
version: !ruby/object:Gem::Version
  version: 0.1.0
platform: ruby
authors:
- Sanemat
autorequire:
bindir: exe
cert_chain: []
date: 2018-07-22 00:00:00.000000000 Z
dependencies:
- !ruby/object:Gem::Dependency
  name: bundler
  requirement: !ruby/object:Gem::Requirement
    requirements:
    - - ">="
      - !ruby/object:Gem::Version
        version: '0'
  type: :development
  prerelease: false
  version_requirements: !ruby/object:Gem::Requirement
    requirements:
    - - ">="
      - !ruby/object:Gem::Version
        version: '0'
- !ruby/object:Gem::Dependency
  name: rake
  requirement: !ruby/object:Gem::Requirement
    requirements:
    - - ">="
      - !ruby/object:Gem::Version
        version: '0'
  type: :development
  prerelease: false
  version_requirements: !ruby/object:Gem::Requirement
    requirements:
    - - ">="
      - !ruby/object:Gem::Version
        version: '0'
description: fix me
email:
- o.gata.ken@gmail.com
executables: []
extensions: []
extra_rdoc_files: []
files:
- ".gitignore"
- CODE_OF_CONDUCT.md
- Gemfile
- Gemfile.lock
- LICENSE.txt
- README.md
- Rakefile
- bin/console
- bin/setup
- lib/test/pack.rb
- lib/test/pack/version.rb
- test-pack.gemspec
homepage: http://example.com
licenses:
- MIT
metadata:
  allowed_push_host: 'TODO: Set to ''http://mygemserver.com'''
post_install_message:
rdoc_options: []
require_paths:
- lib
required_ruby_version: !ruby/object:Gem::Requirement
  requirements:
  - - ">="
    - !ruby/object:Gem::Version
      version: '0'
required_rubygems_version: !ruby/object:Gem::Requirement
  requirements:
  - - ">="
    - !ruby/object:Gem::Version
      version: '0'
requirements: []
rubyforge_project:
rubygems_version: 2.7.6
signing_key:
specification_version: 4
summary: fix me
test_files: []

rubyとかgit ls-filesとかもう残ってない。
そして、bundle exec rake buildの場合、my-awsome-gem.gemspecの中身だけ反映されている。
Gemfileにだけ書いたものはmetadataに入ってない。

与太話: Gemfile 消したら bundle exec rake build 動かなかった :thinking:

Gemfile, Gemfile.lock

これがbundlerの独自ファイルなのは、忘れてるけど言われりゃそうだろうなと思う。

my-awsome-gem.gemspec

これはbundlerの独自ファイルだっけ? 実態として作らなきゃいけないかは定かではない。
たとえばいまはseattlerbぐらいでしか使われていないhoeの場合、gemspecファイルがリポジトリにないが、動的に作っているのか、何だったか忘れた(要出典)
使用例: https://github.com/seattlerb/ruby_parser

つまり

metadataに反映されるかされないかだけで、どうでもいい、とも言える

bundle installでgit repositoryをsourceにする場合

リポジトリのGemfileを見に行くんじゃない? (要出典)
このときlockみてるのかなあ 見てないんじゃないの(要出典)

gem install, bundle installのしくみ

このmetadataをかき集めて、それを満たす最大のバージョンをインストールする。(要出典)

前半ここまで。

Gemfile.lock

アプリケーションを作っている時に、Gemfile.lockなかったら、バージョン固定できなくてつらい。
これは説明いいよね。

gemとGemfile.lock

ここは思想の違い。
lockがあれば、CIで固定のバージョンで通ったことを確認できる。
この組み合わせだと動くよ、ってテストの範囲では言うことができる。

ただ、それってなんの意味があるの、利用者の手元でgem install, bundle installするときに、
なんの関係もないじゃん、って思ってしまう。利用者ではmetadata見るだけなので。

lockがない場合、たとえば新しいcontributorがバグフィックスしたり、新しいフィーチャー持ってくるときに、pull requestを送ったら依存でぶっ壊れてテストが真っ赤というのがよくある。

Over time, however, it became clear that this practice forces the pain of broken dependencies onto new contributors, while leaving existing contributors potentially unaware of the problem.
https://github.com/bundler/bundler/issues/5879#issue-244213907

大体の場合、new contributorsは、自分のfixやfeature入れる前に、もうぶっ壊れてることを報告して、何なら自分で直したりして、test greenにしてから、自分の変更を入れる必要がある。
new contributorsはテンション下がるよね。
まあそれはそうなんだけど、それはもうぶっ壊れてるんだよね。

つまりGemfile.lockをコミットすることで、最新バージョンで動かす責任をnew contributorsからほかのcomittersに移したと言える。
新しい人が開発しやすくなってよかったね。gemとしてリリースするものが動くかどうかはcommiterの責任ですよ。
めでたしめでたし。

なわけないじゃん。。利用者がinstallしようとするときの組み合わせではない古いlockの組み合わせで確認オッケーリリースって事故しか見えない。

そんな事故起こりうるの?って疑問には、だってそれがpainだからゆうてるやん、ってことで。

じゃあどうやって保証するのというと、保証なんてできないので、lockをignoreしておいて、定期的にciを動かしてfailしたら直し続けるしかない。
lockありのテストとlock消してbundle/gem install してテスト、の両方やるでもいいよ。

同じ話の言い換えで、ぶっ壊れてることに気づきづらくなるというのもある。Gemfile.lockを消したpull requestを定期的に送るのかな。

利用者が困る

そりゃgemの開発者は無いと困るけどさ 利用者のが圧倒的に多いじゃん
理解できねー

ぶっ壊れgemがよりリリースされやすくなって利用者が困るの説明でした。

広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中