Pull Requestイベントでactions/checkoutがチェックアウトするブランチ

TL;DR

  • actions/checkoutがチェックアウトするブランチは、Pull Requestのブランチの最新コミットではなく、refs/pull/<pr_number>/mergeになる
  • refs/pull/<pr_number>/mergeは、Pull Requestをマージしたときの結果を確認するために作成される仮想リファレンス
  • ローカルで同じ状況を再現したければ、refs/pull/<pr_number>/mergeをfetchしてチェックアウトする

発生した問題

GitHub ActionsでlintのCIが落ちていたが、ローカルでlintを実行しても、エラーの再現ができなかった。
CIのログを見ていると、CIの実行されるブランチが、ローカルにはないコミットSHAになっていることに気づいた。

Pull RequestイベントでCIが実行されるブランチ

GitHub Actionsのactions/checkoutでは、refを明示的に指定しない場合github.context.refにチェックアウトされる。
参照:actions/checkout - input-helper.ts
Pull Requestイベントでは、github.context.refrefs/pull/<pr_number>/mergeが指定される。

refs/pull/<pr_number>/mergeは、Pull Requestを作成したときにGitHubが自動作成するリファレンスで、Pull Requestをマージしたときの結果を確認するために作成される。
つまり、このリファレンスにはPull Requestの「base」に指定したブランチと、Pull Requestのブランチ(headブランチ)をマージした結果が格納されている。

図:ブランチのイメージ

今回、Pull Requestのブランチを切った時点からbaseに指定したブランチが進んでいて、lintが失敗する状態になっていると、Pull Requestのブランチ内では問題なさそうに見えてもCIは落ちてしまう。
ローカルでPull Requestのブランチのheadに対してlintを実行しても、問題が再現しない。

Pull Requestのheadに対してCIを実行する方法

actions/checkoutのrefにPull Requestのheadを指定する。

- uses: actions/checkout@v4
  with:
    ref: ${{ github.event.pull_request.head.sha }}

CIが実行されるブランチをローカルで確認する方法

ローカルでは、refs/pull/<pr_number>/mergeに移動してを確認する必要がある。 移動するには、refs/pull/<pr_number>/mergeをfetchして、その結果が格納されているFETCH_HEADにチェックアウトする。

git fetch origin pull/<pr_number>/merge
# git fetch origin pull/10/merge

git checkout FETCH_HEAD