GitHub Actionsにおけるactions/checkout@4の挙動を確かめてみた

menu事業部マイクロサービス基盤チームに所属している、新卒1年目の立木です。

menu事業部では、ビルド・デプロイの自動化などのCI/CDツールとして、GitHub Actionsを使用しています。

GitHub Actionsでは、さまざまな操作を行う際に、リポジトリをランナー内にクローンすることがほぼ必須になります。その際に頻繁に使用されるのが、actions/checkoutです。

github.com
今回はこのactions/checkout の挙動を紹介します!

簡単なGitHub Actionsのワークフロー

このbra1ブランチには、コミットがプッシュされた際にワーキングディレクトリを出力するだけのワークフローが設定されています。 このコミットをbra1ブランチにプッシュしてワークフローを発火させてみましょう。

name: Sample workflow bra1
on:
  push:
jobs:
  bra1:
    runs-on: ubuntu-latest
    steps:
      - run: echo $PWD

出力: GitHub Actionsのワーキングディレクトリは /home/runner/work/{トリガーされたリポジトリ}/{トリガーされたリポジトリ} になっており、actions/checkout を使用した時も、クローンされたリポジトリがこの場所に展開されます。

actions/checkout を試してみる

先ほどのsample_bra1.yamlを書き換え、actions/checkout を使用してリポジトリをクローンしその中身と git branch を表示するようにしました。
ワークフローを bra1 ブランチにプッシュしてみましょう。

name: Sample workflow bra1
on:
  push:
jobs:
  bra1:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: |
          ls -a
          echo "" 
          git branch -a

出力: actions/checkout はデフォルトで、ワークフローをトリガーしたリポジトリとブランチのみをクローンします。
今回トリガーした bra1ブランチがクローンされ、ワーキングディレクトリに展開されます。またbra1 ブランチとそのリモート追跡ブランチが追加されています

連続で別のリポジトリをクローンした場合

問題です。次のようなワークフローをプッシュしたら出力はどうなるでしょう?
このワークフローでは、トリガーしたリポジトリをactions/checkoutした後、続けて別のリポジトリをactions/checkoutしています。

name: Sample workflow bra1
on:
  push:
jobs:
  bra1:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      # 続けてoctocat/hello-worldをクローン
      - uses: actions/checkout@v4
         with:
           repository: octocat/hello-world
      - run: |
          ls -a
          echo "" 
          git branch -a

actions/checkout では、repository オプションを使用してクローンするリポジトリを指定できます。

答え: bra1ブランチの内容が消えて、octocat/hello-worldの内容だけになってますね。 actions/checkout は、続けて別のリポジトリをクローンすると、最初のリポジトリの内容や.gitを上書きします。

複数のリポジトリを共存させたい場合は、path オプションでクローン先のディレクトリを分けて指定するのがオススメです。

連続で別のブランチをクローンした場合

次に新しいブランチとしてbra2ブランチをmainから切ります。 bra2ブランチの構成は以下のようになっています。

次の問題です。bra1とbra2を連続でactions/checkoutするとどうなるでしょうか? bra2ブランチのsample_bra2.yamlを以下のようにしてbra2ブランチにプッシュしてみます。

GitHub Actionsはon pushにおいては、プッシュ先のブランチに対応するワークフローを実行します。つまり、このプッシュは 先ほどのsample_bra1.yaml ではなく、sample_bra2.yaml ワークフローをトリガーします。

name: Sample workflow bra2
on:
  push:
jobs: 
  bra2:
    runs-on: ubuntu-latest
    steps:
      # bra1ブランチをクローン
      - uses: actions/checkout@v4
        with: 
          ref: bra1
      # 現在のブランチ(bra2)をクローン
      - uses: actions/checkout@v4
      - run: |
          ls -a
          echo ""
          git branch -a

actions/checkout では、ref オプションを使ってクローンするブランチを指定できます。

答え: 先ほどと同様に、同じリポジトリであっても、後でクローンした bra2 ブランチの内容に上書きされ、bra2ブランチにチェックアウトされています。 しかし、git branch -aの出力のremotes/origin/bra1に注目してください。
最初にクローンしてきた bra1 ブランチのリモート追跡ブランチが残っています。同じリポジトリである場合、リモート追跡ブランチだけは残るようです。 このリモート追跡ブランチは、例えば git diff bra2..remotes/origin/bra1 みたいに、ブランチ間の差分を確認したいときに利用できるかもしれません。

とはいえgit fetchでいいですし、ぱっと見何やってるかわからないのが難点です。

プルリクエストの場合

pull_request をトリガーにする場合は、actions/checkoutのデフォルトの挙動が少し変わります。 このワークフローをプッシュして、bra2 ブランチから bra1 ブランチへのプルリクエストを作成し、ワークフローをトリガーしてみましょう。

name: Sample workflow bra2
on: 
  pull_request:
jobs:
  main:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: |
          ls -a 
          echo "" 
          git branch -a

出力: HEAD が pull/11/merge というリファレンスを指しています。 この pull/数字/merge というのは、プルリクエストがマージされた結果を指す特殊なコミットです。
つまりプルリクエストの場合、headとbaseのマージ後の結果がクローンされます。 その証拠に、bra1ブランチのbra1.txtとbra2ブランチのbra2.txtが共存しています。
もしheadブランチやbaseブランチをクローンしたい場合は、actions/checkout の際に ref: ${{ github.head_ref }}ref: ${{ github.base_ref }} のようにブランチを指定する必要があります。

以上、覚えておくと役に立つかも?なactions/checkoutの挙動でした!