Integration Branch & GitHub Actions Optimization Guide
目的
小さいPRによるレビュー品質・変更単位の明確さを維持しながら、GitHub Actionsの不要な実行とproduction deploy回数を削減する。
最適化の目的は「テストを減らすこと」ではない。
以下の3つを分離することが目的である。
レビュー単位
≠
統合検証単位
≠
production deploy単位
基本構成は次のとおり。
main
↑
integration/issue-<N>
↑ ↑ ↑
PR A PR B PR C
ただし、integration branchは常に使うものではない。
1. 最初に確認すること
実装前に、必ず現在のGitHub Actions構成を確認する。
確認対象:
- PRでどのworkflowが走るか
main pushでどのworkflowが走るか
- deploy workflowがいつ起動するか
- 各stepの所要時間
- 同じPRへの追加pushでCIが再実行されるか
cancel-in-progress が設定されているか
- required checkのworkflow/job名
- production deploy前にどの検証が必要か
- stale revision防止があるか
- production smokeがあるか
想像でCIを最適化しない。実測してから決める。
2. まず「Actionsコストの原因」を分類する
Actionsコスト増加には少なくとも3種類ある。
A. PRへの大量push
PR作成
↓
CI
↓
修正push
↓
CI
↓
修正push
↓
CI
...
1つのPRに数十〜数百回pushする運用では、これが最大要因になり得る。
PR CIが存在するrepoでは原則として:
concurrency:
group: ci-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
相当を検討する。
要件:
- 同一PRの新runで古いrunをcancel
- PRごとにgroupを分離
main pushとはgroupを分離
- production deployには安易に
cancel-in-progress: true を適用しない
重要
cancel-in-progress: true は、すでに終了したrunのコストを取り戻すものではない。
レビュー修正を細切れにpushするより、
複数指摘を確認
↓
まとめて修正
↓
ローカル検証
↓
1回push
を基本とする。
B. 子PRごとの重いCI
E2E、Firebase emulator、Playwright、container buildなどが子PRごとに走る場合。
この場合はintegration向けPRだけheavy stepをskipし、
子PR
→ light CI
integration → main
→ full CI
とする効果が大きい。
C. 子PRをmainへ順次mergeすることでproduction workflowが何度も走る
PR CIが存在しないrepoでも発生する。
PR A → main → Deploy
PR B → main → Deploy
PR C → main → Deploy
を、
PR A ┐
PR B ├→ integration
PR C ┘
↓
main
↓
Deploy
にすることで、production-side Actionsを減らせる。
3. integration branchを使う条件
次の場合に使用する。
- 1つの親Issueが複数PRに分かれる
- 子PR同士の統合状態を最後に検証する意味がある
- 子PRをmainへ順次mergeすると重いActions/deployが繰り返される
- 最終的に1つのproduction revisionとして安全にまとめられる
branch名:
integration/issue-<Issue番号>
例:
integration/issue-128
4. integration branchを使わない条件
以下の場合は作らない。
- 単一PRで完了する
- 複数PRでも完全に独立している
- integrationによる統合検証上の利益がない
- CIが非常に軽く、複雑化の方が大きい
- deployment contract上、複数のmain revisionが必要
「複数PRだからintegrationを使う」ではない。
判断基準は、
integration branchを追加することで、レビュー・検証・Actionsコスト・production安全性の全体が簡潔になるか
である。
5. 標準的なintegration運用
親Issueに、PR分割・順序・依存関係を先に記載する。
例:
PR1: API変更
PR2: UI対応
PR3: regression test
Final: integration/issue-N → main
実装順序:
main
↓
integration/issue-N
feature-A
↓ PR
integration/issue-N
↓ merge
最新 integration/issue-N
↓
feature-B
↓ PR
integration/issue-N
↓ merge
最新 integration/issue-N
↓
feature-C
必ず:
- 1PRずつレビューする
- merge後の最新integrationを次PRのbaseにする
- 古いintegration状態から並列に大量PRを作らない
6. 最終PR
すべての子PR完了後、
integration/issue-N
↓
main
の最終PRを作成する。
最終PRでは:
- 最新mainを取り込む
- full CI
- integration/E2E
- regression確認
- combined diff review
を行う。
最終PRを作ったあとmainが進んだ場合は、
最新mainを再取り込み
↓
影響する検証を再実行
する。
7. Closes #N の扱い
通常のintegration運用では:
- 子PR:
Refs #N
- 最終PR:
Closes #N
とする。
ただしproduction deploy後の確認までIssueを閉じてはいけないrepoでは、自動close keywordを使わない。
その場合:
Final PR merge
↓
production workflow
↓
production smoke
↓
Issueを手動close
とする。
8. Light CI / Full CI
Light CI
integration向け子PRでは、原則として高速な基本検証を残す。
例:
dependency install
typecheck
lint
unit test
build
Heavy CI
最終main PRへ集約できる候補:
Playwright install
browser E2E
preview E2E
Firebase emulator
Firestore rules emulator
full integration smoke
container build
dependency audit
benchmark
ただし、何をskipするかは実測で決める。
9. 「軽量化しすぎない」
重要な原則:
light CIは「安全性を落とすための仕組み」ではない。
子PRで省略した検証は、原則として最終main PRで必ず実行する。
変更内容そのものがheavy testを必要とする場合は、integration向けPRでも実行する。
10. Check identityを維持する
required checksが存在するrepoでは、workflowやjobそのものをbranch条件で消すと、
Required check: Pending
のままmerge不能になる可能性がある。
可能なら:
jobs:
validate:
自体は常に生成し、
- name: Heavy E2E
if: ${{ !startsWith(github.base_ref, 'integration/issue-') }}
のようにstep単位でskipする。
原則:
- workflow名を変えない
- job名を変えない
- integration PRでもcheckを生成する
- light/full差分はstep条件で表現する
11. cancel-in-progress のベストプラクティス
PR CI:
concurrency:
group: ci-pr-${{ github.event.pull_request.number }}
cancel-in-progress: true
またはPR/main共用なら:
concurrency:
group: ci-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
Production deploy
原則:
cancel-in-progress: false
production deployはCIとは別物として扱う。
途中で新しいcommitが来たからといって、deployを無条件キャンセルしない。
代わりに:
- stale SHA guard
- exact current main確認
- deployment scope判定
を使う。
12. 最大のトラップ: Deploy側の検証を削りすぎる
実際に発生した問題:
PRでfull CI済み
↓
だからDeployのlint/testは不要
と考えてDeployから検証を削除した。
しかし、
- direct push
- branch protection bypass
- required check迂回
- PR merge commitと検証SHAの差異
により、productionへ進む実際のmain SHAが未検証になる経路が残った。
したがって、
「PRで検証済みだからDeploy側の検証は消せる」
とは限らない。
production境界は独立して考える。
13. PR merge refとmain SHAは同一とは限らない
GitHubのPR CIが検証するものと、merge後にmainへ作られるcommitは一致しない場合がある。
したがって、
PR CI成功
=
production SHAそのものが検証済み
と単純には扱わない。
安全境界として必要なら:
Final PR full CI
+
Deployでexact current main SHA検証
を組み合わせる。
14. stale revision guardを維持する
production workflowでは、対象SHAが現在のmain HEADか確認する。
概念:
current_main="$(git ls-remote origin refs/heads/main | cut -f1)"
test "$GITHUB_SHA" = "$current_main"
あるいはdeployment scopeに応じて、
「mainが進んでいても、その変更が当該artifactに影響しなければ継続」
というfail-safeな判定を行う。
Actionsコスト削減を理由にstale revision protectionを弱めない。
15. Deployment contractはintegrationより優先
非常に重要。
integration branchで複数変更をまとめても、production側の契約上、
変更Aと変更Bを同一main revisionに含めてはいけない
場合がある。
例:
Hosting変更
+
Firestore / Storage resource変更
を同一revisionに含めるとfail closedする設計。
この場合、
integration → main
を1回でmergeしてはいけない。
代わりに:
integrationで開発・レビュー
↓
production-compatibleなfinal PR A
↓
main
↓
deploy
最新mainへ更新
final PR B
↓
main
↓
deploy
とする。
integration branchはproduction contractを上書きしない。
16. PR CIがないrepoにPR CIを増やさない
重要なアンチパターン。
既存repoが:
PR push
→ Actionsなし
main push
→ production validation/deploy
なら、Actions削減のために
PR push
→ 新しいCI
を追加すると、逆にコストが増えることがある。
このタイプのrepoではintegration branchの主目的は、
子PRをmainへ順次mergeすることによるproduction workflowの多重起動を減らす
ことである。
17. CIが軽いrepoでは分岐を増やさない
実測例:
CI全体: 約25秒
npm install: 約20秒
build: 約1秒
その他: 数秒
この場合、
integration PRではasset checkだけskip
のような最適化は、削減効果よりworkflow複雑化の方が大きい。
この場合は:
cancel-in-progress だけ追加
- light/full分離はしない
が正しい。
18. 重いrepoではlight CIの効果が大きい
例えば、
CI全体: 約262秒
npm ci〜build:
約64秒
Playwright + E2E + Firebase:
約190秒
のようなrepoでは、
integration子PR:
64秒程度
main最終PR:
262秒
にできるため効果が大きい。
最適化はrepoごとに変える。
19. Benchmarkは「重そう」という名前だけで判断しない
実測した結果、
benchmark: 0.26秒
しかかからないケースがあった。
名前だけ見てheavy test扱いしない。
必ずstep時間を見る。
20. Artifact再利用・Reusable Workflowを早期導入しない
一見効率的でも、
- SHA対応
- 権限境界
- artifact provenance
- workflow間依存
- rerun semantics
が複雑になる。
実測で大きな効果がなければ、
artifact共有
reusable workflow
汎用CI framework
は導入しない。
原則:
最小の条件分岐で済むなら、それを選ぶ。
21. 長寿命integration branchを作らない
アンチパターン:
main
↑
integration
↑ ↑ ↑ ↑
Issue A
Issue B
Issue C
Issue D
これでは:
- Issue境界が曖昧
- dependencyが増える
- revert困難
- 最終diffが巨大化
- production責任が曖昧
になる。
必ず:
integration/issue-123
integration/issue-456
のような短命branchとする。
22. 子PRを全部同時に作らない
アンチパターン:
integration
├ PR A
├ PR B
├ PR C
└ PR D
を最初に全部作る。
Aの変更によってB/C/Dの前提が変わると、rebase・conflict・レビュー差分が増える。
推奨:
A
↓ review
↓ merge
最新integration
↓
B
↓ review
↓ merge
最新integration
↓
C
23. 「後でintegrationで直す」を許さない
integration branchは壊れたPRを一時保管する場所ではない。
各子PRはmerge前に:
- Issue要件を満たす
- 必要なローカルテストが通る
- レビューが通る
- known regressionを残さない
こと。
Failing PR
↓
integrationへmerge
↓
最後にまとめて直す
は禁止。
24. レビュー修正のpush回数も最適化する
Actionsコストが高いrepoでは、
修正1 → push
修正2 → push
修正3 → push
...
を避ける。
レビュー指摘に対して:
- 全指摘を確認する
- Issueスコープ内か判断する
- 根本原因を修正する
- 類似箇所・副作用を確認する
- ローカル検証する
- まとめてpushする
@codex review
を基本とする。
25. Production smokeは削らない
Actions削減で最後に削るべきではないもの:
- production smoke
- authentication boundary check
- stale revision check
- deployment credential check
- exact deploy target verification
production smokeは、
「CIで正しかった」
ではなく、
「実際にproductionへ正しく出た」
ことを確認する別の安全境界である。
26. 標準的な親Issue向け指示
以下を親Issueの実装指示として利用できる。
Issueを精査し、要件・影響範囲・依存関係・完了条件の不足や矛盾を修正してください。修正後も再確認し、問題がなくなるまで繰り返してください。
独立して完了・検証できる作業はIssueまたはPRを分割してください。
複数PRを1つの親Issueとして統合検証する明確な利点がある場合は、親Issue単位の短命な integration/issue-<Issue番号> ブランチを使用してください。
複数PRの場合は、実装前に親Issueへ以下を明記してください。
- PR分割内容
- 実装順序
- PR間の依存関係
- integration branchを使う理由
- 最終統合・production publication方法
各子PRは原則として integration/issue-<Issue番号> をbaseとし、1つずつ実装・検証・レビュー・マージしてください。
各PRのmerge後は、最新integration branchを基準に次のPRを実装してください。複数子PRを古いintegration状態から同時並行で作成しないでください。
子PRでは親Issueを参照しますが、Closes / Fixes / Resolves は付けないでください。
すべての子PR完了後、integration branchを最新mainへ更新し、必要な統合・回帰検証を実施してください。
combined diffが1つのproduction revisionとして安全に成立する場合は、integration/issue-<N> → main の最終PRを作成してください。
deployment contract上、複数のmain revisionが必要な場合は、integration branchをそのまま1回でmainへmergeせず、production-compatibleなfinal PRへ分割し、依存順にmainへmergeしてください。
各final PR merge後にmainが進んだ場合は、残りのfinal PRを最新mainへ更新し、影響する検証を再実行してください。
PR CIが存在する場合は、同一PRへの追加pushで古いrunを停止できるよう cancel-in-progress: true を検討してください。ただしproduction deployでは既存の安全なconcurrency/stale revision制御を維持してください。
integration向け子PRのCI軽量化は、実測したstep時間に基づいて判断してください。workflow/job名を不必要に変更せず、required checkがPendingにならないよう、可能なら同じjob内のheavy stepだけを条件skipしてください。
Actionsコスト削減を理由に、production deployのstale revision guard、credential boundary、production smoke、必要なdeploy-time validationを弱めないでください。
PR用Actionsが存在しないrepoでは、integration運用導入だけを理由に重いPR CIを新設しないでください。
単一PRで十分なIssue、またはintegrationによる統合検証・Actions削減上の明確な利点がないIssueでは、integration branchを作成しないでください。
実装・検証後、@codex review の前にPR全体をセルフレビューしてください。要件漏れ、境界値・異常系、副作用・回帰、既存契約の破壊、類似問題、テスト不足、不要な変更や過剰な一般化がないか確認してください。
問題があれば、まずスコープ内か判断してください。スコープ内なら根本原因を修正して再検証し、スコープ外なら必要に応じて別Issueへ切り出してください。
最後に、実装・検証・セルフレビュー結果をPRへ簡潔にコメントし、末尾に @codex review を付けてください。
27. 新規repo向け初期チェックリスト
新しいrepoでは最初に以下を判断する。
PR CI
- [ ] PR pushでActionsが走るか
- [ ]
cancel-in-progress: true があるか
- [ ] 同一PRで数十回pushする運用があるか
- [ ] required check名は何か
CIコスト
- [ ] dependency install時間
- [ ] unit test時間
- [ ] E2E時間
- [ ] emulator時間
- [ ] container build時間
- [ ] audit時間
- [ ] benchmark時間
Deploy
- [ ]
main pushだけでdeployするか
- [ ] stale SHA guardがあるか
- [ ] exact current mainを確認するか
- [ ] production smokeがあるか
- [ ] deploy concurrencyは安全か
- [ ] direct push / bypass時の安全性はあるか
Integration
- [ ] 親Issueが複数PRになることが多いか
- [ ] 子PRごとのheavy CIを減らせるか
- [ ] 子PRごとのmain deployを減らせるか
- [ ] 1つのproduction revisionにまとめて安全か
28. 判断フロー
Issueは単一PRで完了する?
├─ Yes → 通常PR
└─ No
↓
複数PRを統合して検証する意味がある?
├─ No → 各PRを通常運用
└─ Yes
↓
integration/issue-N を作る
↓
PR CIはある?
├─ No
│ ↓
│ PR CIを新設する必要は本当にある?
│ ├─ No → ローカル検証 + review
│ └─ Yes → 別途CI設計
│
└─ Yes
↓
CIは重い?
├─ No → 同一CI + cancel-in-progress
└─ Yes → integration PRだけlight CI
↓
子PRを1つずつintegrationへmerge
↓
latest mainを取り込む
↓
full integration verification
↓
1 revisionでproduction可能?
├─ Yes → integration → main
└─ No → deployment-compatible final PRへ分割
↓
production workflow / smoke
↓
Issue close
29. アンチパターンまとめ
避けること:
- 全repoへ同じCI最適化をコピーする
- 複数PRなら無条件でintegrationを作る
- 長寿命integration branchを使う
- 全子PRを最初から並行作成する
- failing PRをintegrationへ積む
- required check jobそのものをbranch条件で消す
- benchmarkという名前だけでheavy扱いする
- 数秒節約のためにworkflowを複雑化する
- PR CIがないrepoにコスト削減目的でPR CIを新設する
- PRでCI済みという理由だけでDeploy validationを削除する
- production smokeを削る
- stale SHA guardを弱める
- Deployへ
cancel-in-progress: true を安易に適用する
- integration branchをproduction deployment contractより優先する
- artifact共有/reusable workflowを早期に一般化する
- レビュー指摘ごとに細切れpushする
30. 最重要原則
最適化の優先順位は次のとおり。
1. production安全性
2. correctness / regression detection
3. reviewability
4. Actionsコスト
5. workflowの見た目上の統一
GitHub Actions最適化は、
「検証をなくす」
のではなく、
「同じ検証を、最も意味のある境界で1回だけ行う」
ことを目指す。
そしてintegration branchは、
「PRをまとめる場所」
ではなく、
「レビュー単位を小さく保ったまま、統合検証とproduction publicationの回数を制御するための短命な境界」
として扱う。