GitHub の merge queue は、main ブランチへのマージを自動で直列化し、CI を通してからマージする仕組みです。一方、CODEOWNERS を設定すると、指定されたオーナーのレビュー承認がマージの条件になります。
チーム運用では「普段は CODEOWNERS レビューを必須にしつつ、緊急時や特定のメンバーは bypass してマージしたい」というニーズがあります。このとき merge queue が正常に動作するのかを検証しました。
- 検証リポジトリ: merge-queue-bypass-demo(README に検証結果をまとめています)
結論
現時点では、CODEOWNERS レビューを bypass しつつ merge queue を維持する方法はありません。
- Branch Protection の bypass は CODEOWNERS をスキップできるが、merge queue も一緒にスキップされる
- Rulesets の bypass はルールごとに制御できるはずだが、merge queue が有効な環境では CODEOWNERS bypass が機能しない
検証環境
| 項目 | 内容 |
|---|---|
| リポジトリ | codenote-net/merge-queue-bypass-demo(public) |
| デフォルトブランチ | main |
| CI | echo "CI passed" を実行するだけのシンプルなワークフロー |
CODEOWNERS ファイルでは、Organization のチーム @codenote-net/reviewers をオーナーに設定し、bypass 対象者(自分)が CODEOWNERS レビューの bypass を検証できる状況を作りました。
# .github/CODEOWNERS
* @codenote-net/reviewersCI ワークフローは pull_request と merge_group の両方をトリガーに設定しました。merge_group は merge queue が CI を実行する際に使われるイベントです。
# .github/workflows/ci.yml
name: CI
on:
pull_request:
merge_group:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: echo "CI passed"検証シナリオと結果
4 つのシナリオで検証しました。
| シナリオ | 保護方式 | bypass | CODEOWNERS bypass | merge queue 動作 | マージ方法 |
|---|---|---|---|---|---|
| 1(PR #7) | Branch Protection | なし | N/A(承認済み) | ✅ 動作する | queue 経由 |
| 2(PR #8) | Branch Protection | あり | ✅ できる | ❌ スキップされる | 直接マージ |
| 3(PR #9) | Rulesets(分割) | あり | ❌ できない | ❌ ブロック | N/A |
| 4(PR #10) | Rulesets(単一) | あり | ❌ できない | ❌ ブロック | N/A |
シナリオ 1: Branch Protection(bypass なし)
ベースラインとなるシナリオです。Branch Protection で以下を有効にしました。
- Require pull request reviews before merging
- Require review from Code Owners
- Require merge queue
- Require status checks to pass(CI)
CODEOWNERS のオーナーにレビューを承認してもらい、「Merge when ready」を押すと merge queue に追加されました。CI が通り、自動マージされました。これが正常な動作です。
シナリオ 2: Branch Protection(bypass あり)
シナリオ 1 の設定に加え、「Allow specified actors to bypass required pull requests」に自分を追加しました。
PR を作成すると、CODEOWNERS レビューなしで「Confirm bypass rules and merge」ボタンが表示され、これを押すと merge queue を経由せず直接マージされました。
Branch Protection の bypass は all-or-nothing です。 CODEOWNERS だけを bypass して merge queue を残すことはできません。
シナリオ 3: Rulesets(分割構成、bypass あり)
Branch Protection を削除し、Rulesets で 2 つのルールセットを作成しました。
- Ruleset A「Merge Queue and CI」(bypass なし): merge queue + status checks
- Ruleset B「Code Review」(bypass あり): PR reviews + CODEOWNERS
狙いは「merge queue は全員に適用しつつ、CODEOWNERS レビューだけを bypass する」ことでした。
しかし、PR を作成すると bypass が機能せず、「Merging is blocked: Waiting on code owner review」のまま merge queue に追加できませんでした。
Rulesets で bypass 対象を分割しても、merge queue が有効な環境では CODEOWNERS bypass は機能しません。
シナリオ 4: Rulesets(単一構成、bypass あり)
比較のため、すべてのルールを 1 つの Ruleset にまとめました。
- merge queue + status checks + PR reviews + CODEOWNERS + bypass
結果はシナリオ 3 と同じで、CODEOWNERS レビューが bypass されず、merge queue に追加できませんでした。Rulesets を分割しても単一にしても結果は変わりません。
Branch Protection と Rulesets の比較
| 挙動 | Branch Protection | Rulesets |
|---|---|---|
| CODEOWNERS bypass | ✅ できる | ❌ できない |
| merge queue の動作 | ❌ bypass 時にスキップされる | ❌ ブロック(queue に入れない) |
| bypass の粒度 | ⚠️ all-or-nothing | ⚠️ ルールごとに設定可能(だが期待通りに動かない) |
原因の推測
- Branch Protection: bypass はすべての保護ルールを一括で迂回します。merge queue も Branch Protection の一部であるため、bypass 時にスキップされます
- Rulesets: bypass はアクターごとに特定のルールを免除する設計ですが、merge queue が有効な場合、PR が queue に入る前提条件として CODEOWNERS レビューが必須と扱われているようです。bypass 権限が正しく評価されていない可能性があります
現時点での回避策
完全な解決策はありませんが、運用で対処する方法はあります。
- Branch Protection bypass + merge queue なし: 緊急時は bypass で直接マージし、merge queue の恩恵は諦める
- Rulesets + CODEOWNERS なし: CODEOWNERS を使わず、通常の PR レビュー必須のみにする。通常の PR レビューは Rulesets bypass で正常にスキップできる
- GitHub の改善を待つ: Rulesets の bypass が merge queue 環境で正しく動作するようになることを期待する
まとめ
GitHub の CODEOWNERS bypass と merge queue の共存を 4 シナリオで検証しました。Branch Protection の bypass は all-or-nothing で merge queue もスキップされ、Rulesets の bypass は merge queue 環境で CODEOWNERS を bypass できません。
チームで merge queue と CODEOWNERS を併用している場合、bypass 運用の設計には注意が必要です。検証の詳細は merge-queue-bypass-demo リポジトリの README と各 PR を参照してください。
以上、CODEOWNERS bypass と merge queue の共存を検証してみた、現場からお送りしました。