日々常々

ふつうのプログラマがあたりまえにしたいこと。

コミット対象をよりわけるのをやめてみよう

git add {ファイル名} でステージングするファイル単位で選べます。10ファイル変更しててそのうち3ファイルだけコミットしたい時とかに便利です。

git add -p でステージングする変更を行の塊単位で選べます。関係ないコメントを足しちゃったのとか、うっかりついでに変えてしまった変更をコミットから避けたり、別のコミットにしたい時とかに便利です。

間違いなく便利な機能ではあるんだけど、常用するものじゃないと思ってます。

なので

git add -A を基本にする。

……とか言いつつ git add . を常用している私。単にタイプ数と手の慣れ。ちなみにgitのaliasは使わない派です。これは違う環境でコマンド叩く機会が多かったりする都合です。

理由

を並べてみます。

コミット対象を選択するのがいちいちブロッキングなので時間がかかる

10ファイルの変更から3ファイル選択する時間は git add . より絶対に長い。tabで1文字で補完できるとしても git add x<tab> y<tab> z<tab> が必要になる。どれを選ぶかの判断もしなきゃいけなくなる。選び間違いもある。

これはデバッガで止めながら動作確認しているようなものだと思う。デバッガは強力で間違いなく有用なんだけど、それ一辺倒になると時間が無限に溶ける。デバッガは道具箱には入れておかないといけないものではあるけど、きっと最初に使う選択肢ではないはずなんだ(脱線)

コミットした状態は自分の手元で過去のどの瞬間にも存在しなかった状態になる

そのコミットでコンパイルやテストが通るかは確認できていないし、きっとその確認もしないままになる。必要になった時、たとえば git bisect とかでその辺が混じるとよくわからないことになってしまう。

コミット漏れが発生する原因になる

  • A 「pushしました!」
  • B 「ありがとう!……コンパイル通らないんだけど?」
  • A 「あ、コミット忘れてました!!」

……なやりとりをする必要があるの、だいたいこれのせい。二往復したりもする。言ってることは一つ前と同じ。

コミットしちゃいけないファイルの存在を許すことになる

ローカルで動作させるためにコードを変更する必要があるライブラリやフレームワークは存在した。今もする。 コードではなくローカル用に設定ファイルを編集するのは当たり前だったりした。 ある程度は制約や効率もあるんで仕方がない。

けれど、クラウドやコンテナが後押しになって、秘匿情報は環境変数など他のもの経由で渡せるようになってきている。本当に仕方がないかは見直してもいいと思う。

もう日本語訳が出版されて9年経っている継続的デリバリーだけど、ビルドしたバイナリがすべての環境で同一のものを使うことを示していた。当時はwarやearの中に環境依存の設定をねじ込んでいたんで難しいだろうって思っていたけど、今はほとんどそう言うのも見なくなっている。

なんでこんなこと書いてるかってと

コミットしちゃいけないファイルや変更がある場合「コミットしないように気をつける」ことになる。 人の注意力に頼ったプロセスは、その事象を起こしてしまって良いように設計しなければならない。

でなければ誤った際に「注意不足でした」「もっと注意します」しかなくなる。 こうなると問題の責めが個人に持っていかれて、改善の発見がしづらくなる。

……とか言いつつ、自分が注意不足でやらかす側だから、自分を甘やかすために仕組みの方に持っていきたいだけなんだけどね。

一部のコミットだけ丁寧に取り繕っても意味がない(04-01T11:21 追記)

「コミット粒度を揃えよう!」と掲げるプロジェクトは結構あります。それがうまく機能している現場はあまり見ません。できてるところもありますが、私の観測範囲では多数派ではないです。

Gitの使い方すらままならないこともしばしばです。 チームメンバーが漏れなく壊さずコミットできるかを確認する必要がある程度には、Gitを前提に置くのは難しいです。 もちろんcommitやpushはできますが、複雑なコンフリクトが発生した時にスムーズに解消したり、ローカルリポジトリがおかしくなった時に原因を切り分けたりとかは一定水準以上のスキルだと思っています。

そんな状況で「自分の意図した変更だけ選んでコミットする」ようなことを「やるべきこと」に加えるのは、余計な問題の発生を増やすことになります。ぶっちゃけどうでもいいから手元のファイルを全部確実にコミットしてくれれば、あとはどうとでもなるんです。コミットされていない、pushされていない状況だとどうしようもないんで、先に挙げたような「コミット漏れてました!」なんてのが起こらないのがまずありきです。……脱線が過ぎた。

閑話休題。コミットログを読んだりする時は「コミット粒度はバラバラなものだし、コミットには複数の変更が混ざっている」を前提に読んでます。たまに読みとりやすいコミットもありますが、それは儲けってくらいの温度感。もちろん混ざってない方がいいんで、それを目指すのは諦めずに。

うまく行っているOSSはありますが、そこにはかなりのパワーが割かれて文化が醸成された結果です。それを現場で再現するのは結構難しいんじゃないかな。仕事なんだから強いルールで縛れば?そう言うアプローチもありますね。雁字搦めの結果は推して知るべきかと思いますが、うまく行ったら教えてください。

どうすれば

.gitignore でちゃんと避ける。 環境依存な情報は外に置いて取り込めるようにする。

と言うのができる環境ならって話だけど、数年前よりは確実にやりやすくなっている。と思う。 できない環境もある。それは仕方ない。心の片隅に置いておいてください。

でも1つのコミットに複数の変更混じるじゃん

混ざる状態で進めてたんですよね、としか……(ブーメラン)

偽造するより素直に歴史おいとく方がいいよ。今よりわけられるなら未来でもよりわけられるよ。必要になった時でよくないかな、全部にやらなくてもいいと思うんだ。

コミット単位で分析してたりして、きっちりわけるルールが敷かれているリポジトリなら、わけた状態で進められるようにした方がいいと思います。 私がそう言う時にやるのは先にコミットメッセージを書いた空コミット作って、その後に変更をamendしていく形。 テストファーストやアサートファースト、チケットファーストと同じ感じでコミットファーストです。小さいゴールなら寄り道も少ないし。

先にも書いたように、混ざってていい。混ざってる事実を記録して後で振り返って、直すべきだと思ったら、混ざらないプロセスを組み立てていこう。

でもGitの一般的な機能じゃん

じゃーなんでステージングエリアなんてあるんだって話だけど、まぁ便利だからだよね……必要な時に便利に使うのはいいけど、常用するのはやることが少なくて安全なプロセスだと思う。おかしなことになった時になんとかする時、ステージングエリアがすごく役に立つ。

機能があるからと言って使わなければならないってことはないんです。

でも git add -A とかがデフォルトになると、add + commit が二段階なのが無駄に感じるよね。Subversionならcommitだけだったのに…… そうだSubversionに戻ろう!!

git add . とかした時のちょっとした反応とか、git status した時の赤と緑の具合みた時とか、そう言うとこから何か感じ取ってたりする。何か感じ取ってるのは間違いないんだけど、なんか言語化できてない。なんだろなこれ……(そのうち考えてみようかな)

私の距離感

間違いなく便利な機能ではあるんだけど、常用するものじゃないと思ってます。 使えるようになった上で、平時は使わないでおこう。それくらいの距離感。

本稿はこの本のレビュー中に思ったことだったりする。

04-01T09:52 追記: push前に整理するか否か

以前書いたブログが関連にあるので。

irof.hateblo.jp

push前にrebaseなどでコミット整理を行うかは、状況によります。とはいえ基本的にしていません。 先に書いたように

偽造するより素直に歴史おいとく方がいいよ。今よりわけられるなら未来でもよりわけられるよ。必要になった時でよくないかな、全部にやらなくてもいいと思うんだ。

って感じです。要らないコストを払う必要はない感。

イミュータブルデータモデルとかも若干近いんだけど、起こった事実はそのまま記録しておいて、見る必要があった時に編集するでいいと思っている。それが参照頻度が非常に高いものなら事前に整理しておく価値はあるのだけど、Gitのコミットを私(や関わっているプロジェクトで)見たいと思った時、綺麗に整理されていることを前提にはしていない。むしろ混沌としたコミットログを読み解くくらいの気持ちでやってて、それでも必要な情報にたどり着くまでそんな手間はかかっていない。

細かい未整理のコミットが膨大にあって読み解くのに労力がかかったところで、読み解きが必要になる(「必」ね。参考に見るくらいのは除いてる。)頻度が低いなら、コミットの整理にかかるコストを払うのはあまり効果がないんじゃないかなと思っている。参考に見るくらいなら傾向を把握したりとかなのでそもそもそんな時間かからないし。

整理されてないとcherry-pickしづらい、とかは確かにあるけど、改変された未テストのcommitをcherry-pickしてもうまくいかないことの方が多い印象がある。cherry-pickじゃなく手で移すなら整理されてるほうがいいんだろけど。

「それはあなたがコミットログを読まないだけで、他のコミットログを読む人に苦労を強いているだけでは?」とかも考えたりしますが、どちらかと言うと私はコミットログを読んだりコミットグラフとかコミット時間とか諸々見てるし、PRレビューをするときは全コミット追ったりするし(未整理で構わない。むしろ未整理の方が好ましいと考えてるくらい。)、有効に活用している方だと思ってます。もちろん恒常的に分析したりしてる人ほどではないけど……。

コミットを改変すると歴史が歪み、情報が失われる。その方がリスクが高いと思っています。と言うことで、余程でない限り、コミットの整理は不要と考えています。