gitの習慣

gitの話です。

突然ですけど、コンフリクトって怖いですよね。
コンフリクトの解消時にバグが入りがちですし、地味に面倒ですし。

最近気づいたのですが、「コンフリクト怖い」と言っている人ほど、コンフリクトが発生しやすく、対応が難しくなる方法を採用しているように見えます。

個人的な経験としては、コンフリクトの予防は

  • 事実を認識する
  • 習慣

の2つが大事だと思っています。

事実

コンフリクトは怖い

冒頭にも書いたとおり、コンフリクトが発生するとバグが混入しやすく、手間もかかります。
コンフリクトは避けられない場合もありますが、極力発生しないほうが良いのです。
また、ひとつのコンフリクトの対応は簡単であればあるほど、リスクは下がります。

差分があるほどコンフリクトしやすい

1000ファイルの変更と1ファイルの変更、どちらがコンフリクトしやすいでしょうか。
マージ先との差分があればあるほどコンフリクトしやすいのは自明だと思います。

時間が経つほどコンフリクトしやすい

これは「差分があるほどコンフリクトしやすい」から導出される事実です。

1秒前に切ったブランチと、15年前に切ったブランチ、マージする場合にどちらがコンフリクトしやすいでしょうか。

時間が経てば経つほど、マージ先のブランチのコミットは積み上がっていくでしょう。
つまり、時間が経つだけで差分は広がっていくのです。

コンフリクト対象が多いほど間違いやすい

1個のコンフリクトを解消するのと、10個のコンフリクトを解消するのでは、どちらが大変でしょうか。

コンフリクトの量が多ければ多いほど、対応は大変になり、バグが混入する可能性は増えます。

コンフリクトの発覚が遅れるほど作業量が増える

開発中にコンフリクトに気づけば、自分が作業をするだけで済みます。
一方で、コードレビューを依頼後にコンフリクトが発覚すれば、レビュアーとの調整も作業に入るでしょう。
誰かがレビュー完了した後にコンフリクトが発覚すれば、レビューを再依頼しないといけないかもしれません。

複雑なログほど見づらい

コンフリクトが発生した際、またはそれによりバグが混入した際に、ログを参照すると思います。
では、以下のログはどちらが見やすいでしょうか。

1
f:id:chiroruxx:20200724120511p:plain

2
f:id:chiroruxx:20200724120523p:plain

私は最初のほうが見やすいです。
これは簡単な例ですが、現場ではもっと込み入ったログになります。
なるべくログをシンプルに保つことで、コンフリクト解消の難易度を下げられます。

習慣

基本的に、「ログをシンプルに保つ」ということを意識すると、コンフリクトは発生しにくくなり、コンフリクト対応の難易度が下がります。

ここではブランチモデルはGitHubFlowで行い、GitHubのPullRequestでコードレビューを依頼後、マージしているものとします。
ですが、他の方法を採用していても、するべきことは同じです。

毎朝masterブランチをpullする

出勤したら、まずローカルのmasterを最新の状態にします。
これ自体はコンフリクト解消に役立ちませんが、他の習慣の誤動作を防ぐ役割があります。

毎朝、PRを出していないfeatureブランチをmasterブランチからrebaseする

いま自分が作業しているものを常に最新からの差分にします。

早期にコンフリクトを発見でき、なおかつ1度のコンフリクト解消量を削減できます。

また、最新にすることでローカルのログが読みやすくなります。

featureブランチを作成する際は最新のmasterブランチから作成する

ブランチを作成する際は必ず最新のmasterブランチから作成します。
自分のローカルにあるmasterブランチが古いと、(ローカルにある)古いmasterブランチから作成しがちです。(これは「毎朝masterブランチをpullする」で防ぐことができます)

古いmasterブランチから作成するということは、作成した時点で差分があるということです。
差分を減らすためにも、最新のmasterブランチから作成しましょう。

リモートリポジトリにpushする前に最新のmasterブランチからrebaseする

作業が完成したらpush!・・・する前に、最新のmasterブランチからrebaseします。

レビュー前にコンフリクトに気付くことができ、なおかつログをシンプルにすることができます。

mergeする前に最新のmasterブランチからrebaseする

レビューが完了したら、最新のmasterブランチからrebaseします。
これでログがシンプルになります。

ただし、rebaseを行うと fource push を行う必要があります。
チームによってはfource pushを禁止しているチームもあるので、「可能なら」というレベル感です。

また、Squash Mergeを採用している場合は不要です。

まとめ

ここに書いていることは、たしかざっくりですが「アジャイルサムライ」にも似たようなことが書いてあった気がします。
つまり、とてもとても基礎的なことということですね。
「基礎的なことを当たり前にできるようになる」というのは案外難しいものですが、基礎の積み重ねが品質として表れるので、気を付けていきたいところです。