複数のDependabot PRを連続マージすると事故が怖い

同一リポジトリでDependabotが作成した複数のPull Requestをgh pr mergeで連続マージすると、後続のPRが直前のマージの影響でコンフリクトを起こすことがある。

例えばlockファイルを更新するPR同士は、片方をマージした時点でもう片方のベースブランチとの差分が変わる。そのままマージするとコンフリクトしたコードを取り込んでしまう恐れがあるため、マージボタンを押す前にマージ可否を確認する習慣が必要である。

gh pr viewでマージ可否を確認する

gh pr view--jsonオプションを使うと、GitHub PR APIのmergeablemergeStateStatusを直接取得できる。

$ gh pr view 123 --json mergeable,mergeStateStatus

mergeableフィールドの見方

mergeableはPRのブランチをベースブランチにマージできるかをGitHubが試算した結果であり、値は3種類ある。

  • MERGEABLE: コンフリクトなくマージできる
  • CONFLICTING: コンフリクトがあり、そのままではマージできない
  • UNKNOWN: GitHub側でまだ判定計算が終わっていない

UNKNOWNは一時的な状態である点に注意が必要である。GitHubはこの判定を非同期のバックグラウンド処理で計算しており、mergeableが未計算の間はUNKNOWNを返す。経験上、直前に別のPRを同じベースブランチにマージした直後は、他のオープンなPRの判定が再計算されるらしく、マージ直後に確認すると一瞬UNKNOWNになることがある。

mergeStateStatusフィールドの見方

mergeStateStatusmergeableよりさらに詳細な状態であり、CIのステータスやブランチ保護ルール(必須レビューなど)も加味した、実際にマージボタンを押せる状態かを示す。

  • CLEAN: ブランチ保護ルールも含めてすべて満たし、すぐマージ可能
  • BLOCKED: 必須チェック未完了、または必須レビュー不足
  • BEHIND: ベースブランチより遅れていて、保護ルール上マージ前に更新が必要
  • DIRTY: コンフリクトがある(mergeable: CONFLICTINGに対応)
  • UNKNOWN: 計算中

ほかにUNSTABLE(必須でないチェックの失敗)やHAS_HOOKSDRAFT(ドラフトPR)といった値もあるが、Dependabot PRのコンフリクト確認という用途では上記5値を押さえておけば十分である。

連続マージの運用手順

同一リポジトリで複数PRを連続マージする場合は、以下の手順で進める。

  1. 1件目をマージする(gh pr merge 123 -d -m
  2. マージ直後に2件目のgh pr view 124 --json mergeable,mergeStateStatusを叩く
  3. UNKNOWN/UNKNOWNが返ってきた場合はGitHubが再計算中のサインなので、数秒〜十数秒待ってから再度チェックする
  4. CLEAN/MERGEABLEになっていればコンフリクトなしと判断してマージを進める
  5. CONFLICTING/DIRTYだった場合はコメントで@dependabot rebaseを依頼し、MERGEABLEに変わるまで待ってから再度マージを試みる

lockファイル同士が競合するケースでは、rebaseを依頼すると数分でDependabotが自動でリベースしてくれることが多い。

まとめ

gh pr view --json mergeable,mergeStateStatusを使うと、マージボタンを押す前にPRのコンフリクト有無とマージ可能状態をCLIから確認できる。同一リポジトリで複数のDependabot PRを連続マージする際は、マージ直後のUNKNOWNを早合点でコンフリクトと誤判定しないよう、数秒待ってから再チェックする運用が有効である。

gh pr view