こんにちは、かつコーチです。
「うっかりmainに直接pushしてしまい、本番が壊れた」というインシデントは、チーム開発をしていれば一度は聞いたことがあるはずです。
Pull RequestやGit Flowの運用ルールを整えても、それを守らせる仕組みがなければ、疲れているときや急いでいるときにヒューマンエラーは起きます。
この記事では、GitHubのProtected Branchを使って、ルールを「性善説」ではなく「仕組み」で担保する方法を解説します。
Pull Requestやブランチ運用の基本は前提知識として進めます。
Protected Branchとは?
本線に鍵をかけて許可制にする仕組み
Protected Branch(保護ブランチ)とは、指定したブランチへの直接push・強制push・削除を制限し、決めたルールを満たしたPull Requestだけをマージできるようにする機能です。
イメージとしては、工事現場の本線(メインの通路)に鍵をかけ、決められた手続きを踏んだ人だけが通行証をもらって通れるようにする仕組みだと考えてください。
鍵がない状態では、誰でも本線に直接資材を持ち込めてしまい、手順を無視した危険な作業が紛れ込むリスクがあります。
Protected Branchは、mainブランチという「本線」に鍵をかけ、レビューという「許可証」を持つ変更だけを通す役割を果たします。
なぜルールをコードではなく仕組みで守るべきか
「レビューをもらってからマージする」というルールをドキュメントに書くだけでは、繁忙期や新メンバーの見落としによって、いずれ形骸化します。
Protected Branchを設定しておけば、ルールに違反する操作自体をGitHubがブロックするため、運用ルールの遵守を個人の注意力に依存させずに済みます。
これは「気をつけましょう」という張り紙ではなく、「鍵付きのドア」を設置する対策であり、事故防止の確実性が段違いです。
実装手順:Protected Branchの設定
手順1:Branch protection ruleを作成する
リポジトリのSettings > Branches から、対象ブランチ(通常はmain)にルールを追加します。
gh CLI経由でAPIを叩く場合は、以下のようになります。
$ gh api repos/your-org/your-repo/branches/main/protection \
--method PUT \
--input protection.json
protection.jsonには、必須にしたい条件をJSONで定義します。
{
"required_status_checks": {
"strict": true,
"contexts": ["test", "lint"]
},
"enforce_admins": true,
"required_pull_request_reviews": {
"required_approving_review_count": 2,
"dismiss_stale_reviews": true
},
"restrictions": null
}
手順2:レビュー必須数と承認の失効ルールを決める
required_approving_review_countで、マージに必要な承認者数を指定します。
チームの規模やレビュー文化に応じて1〜2名が現実的な水準です。
dismiss_stale_reviews: trueにしておくと、承認後に新しいコミットがpushされた際、既存の承認が自動で無効化されます。
これにより「承認後にこっそりコードが変わっていた」という抜け道を塞げます。
手順3:ステータスチェックを必須化する
required_status_checksで、CIのテストやLintが通っていることをマージの条件にできます。
GitHub Actionsのワークフロー名(jobのname)をcontextsに指定すると、そのチェックがパスするまでマージボタンが押せない状態になります。
name: CI
on: [pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
このjob名testをprotection.jsonのcontextsに含めることで、テストが失敗しているPull Requestは物理的にマージできなくなります。
運用上の注意点
enforce_admins: trueを忘れると、Adminロールを持つメンバーはルールを無視して直接pushできてしまいます。
「自分は管理者だから大丈夫」という例外を作らないことが、事故防止の一貫性を保つ上で重要です。
よくあるつまずきポイント・エラー対処
管理者だけルールから除外していて事故が起きた話
以前関わっていたプロジェクトで、Protected Branchは設定していたもののenforce_adminsをfalseにしていたことがありました。
❌ Before:管理者はルールの対象外にしていた
{
"enforce_admins": false
}
急ぎの修正だからと、管理者権限を持つメンバーがレビューなしで直接mainにpushしたところ、そのコミットに未検証のバグが含まれており、本番環境で障害が発生しました。
鍵付きのドアを作ったのに、責任者だけは合鍵で素通りできる状態にしていたようなものです。
✅ After:管理者も例外なくルールの対象にする
{
"enforce_admins": true
}
以降は、緊急対応であっても必ずPull Requestを経由し、最低1名のレビューを通す運用に改めました。
本当に一刻を争う場合は、レビューのハードルを下げるのではなく、レビュー担当者への緊急連絡フローを別途整備する方向で対応しています。
応用・一歩先の使い方
Rulesetsで複数ブランチにまとめてルールを適用する
近年GitHubには、従来のBranch protection ruleより柔軟なRulesetsという機能も追加されています。
mainやrelease/*のように複数ブランチへパターンでルールを一括適用でき、組織全体のリポジトリに共通ポリシーを配布する運用にも向いています。
エンタープライズでの標準化を検討する段階になったら、Rulesetsへの移行も選択肢に入れてみてください。
CODEOWNERSと組み合わせて承認者を自動指定する
.github/CODEOWNERSファイルで領域ごとのオーナーを定義し、required_pull_request_reviewsと組み合わせることで、変更されたファイルに応じて適切なレビュアーを自動でアサインできます。
鍵を持つ人を「誰でもいい2人」から「その領域の責任者」に絞り込むことで、レビューの質そのものも底上げできます。
まとめ
この記事のポイント
- Protected Branchは、本線に鍵をかけて許可制にする仕組みで、ルール遵守を個人の注意力に依存させない
required_status_checksとrequired_pull_request_reviewsで、CI通過とレビュー承認をマージの必須条件にできるenforce_admins: trueを忘れると、管理者だけがルールから除外されてしまう- より柔軟な運用にはRulesetsやCODEOWNERSとの組み合わせも検討する
次に読むべき記事
CIによる自動チェックそのものの作り方は、「GitHub Actionsとは?コードの変化に反応して自動で動く仕組み」で解説しています。
Protected Branchと組み合わせることで、レビューとテストの両方が揃わないとマージできない、安全な開発フローが完成します。