この記事は2026年8月時点のGitHubを前提にしています。GitHubの画面構成や機能名は変更される可能性があります。
はじめに
一人で開発していると、GitHubのPull Requestやレビューは「チーム開発のための機能」に見えるかもしれません。
しかし、GitHub CopilotやChatGPT CodexなどのAIを使って開発する場合、むしろ一人開発でもPull Requestが重要になります。
AIを使うと、コードの生成や修正は速くなります。一方で、次の問題も起こりやすくなります。
- 変更量が増え、何を変えたのか分かりにくくなる
- 修正コミットが大量に作られる
- AIの提案を十分に確認せず取り込んでしまう
- CIが成功したことと、公開してよいことを混同する
- APIキーやバックアップなどを誤ってGitへ追加する
-
mainへ直接pushして、レビュー履歴が残らない - 複数のAIが異なる前提で変更し、整合性が崩れる
そこでリポジトリを立ち上げる際に、次の運用を構築しました。
Issue
↓
作業ブランチ
↓
Draft Pull Request
↓
GitHub Actions
↓
GitHub Copilotレビュー
↓
ChatGPT Codexレビュー
↓
指摘の修正と会話の解決
↓
人間による最終確認
↓
手動Squash merge
↓
mainで再検証
この記事では、設定項目の意味、なぜ必要なのか、Squash mergeと他のマージ方式の違い、実際に遭遇した設定ミスまで整理します。
結論:AIは作業者と助言者、人間は承認者
今回の構成で最も重要な原則は、次の分離です。
AI
実装
テスト
調査
レビュー
修正提案
GitHub
履歴
差分
機械検査
ルール強制
監査証跡
人間
目的の確認
事実の確認
リスク判断
公開判断
最終マージ
AIレビューを増やしても、AIに最終決定を任せるわけではありません。
GitHub Copilotのコードレビューは、ApproveやRequest changesではなくCommentとして投稿され、必須承認数にはカウントされません。マージを直接ブロックするものでもありません。
そのため、今回の構成では次の組み合わせにしました。
Required approvals: 0
Pull Request: 必須
CI: 必須
レビュー会話の解決: 必須
Copilotレビュー: 自動
Codexレビュー: 実施
Auto-merge: 無効
最終マージ: 人間が手動実行
Repository settingsとRulesetは役割が違う
最初に理解しておきたいのが、Repository settingsとRulesetの違いです。
| 設定 | 主な役割 |
|---|---|
| Repository settings | リポジトリで利用可能な機能を決める |
| Ruleset | 特定ブランチへの変更条件を強制する |
| GitHub Actions | テストやビルドなどの機械検査を実行する |
| Pull Request | 差分、レビュー、判断、議論を記録する |
| Security settings | 秘密情報や依存関係のリスクを検出する |
例えば、Repository settingsでSquash mergeを有効にすると、Squash mergeを選択できるようになります。
一方、RulesetでAllowed merge methods: Squashを設定すると、対象ブランチではSquash以外を使えなくなります。
Repository settingsとRulesetが矛盾すると、マージできなくなることがあります。GitHub公式ドキュメントでも、リポジトリ側で許可していないマージ方式をRulesetで要求するとマージ不能になると説明されています。
今回採用したRepository settings
Default branch:
main
Pull Request merge:
Squash merge: Enabled
Merge commit: Disabled
Rebase merge: Disabled
Auto-merge: Disabled
Branch:
Delete head branch after merge: Enabled
Suggest updating pull request branches: Enabled
Other:
Wiki: Disabled
Discussions: Disabled
GitHub Pages: Disabled
Squash mergeのみを有効にする
一人開発とAI支援開発では、作業ブランチに次のようなコミットが増えがちです。
initial implementation
fix tests
address Copilot comments
fix Codex P1
format files
fix CI
update docs
これらをすべてmainへ残すより、Pull Request単位で次の1コミットにまとめます。
Add typed content governance model (#11)
こうすると、mainの履歴自体がプロジェクトの進行記録になります。
Bootstrap Astro and Cloudflare foundation (#1)
Add content governance model (#11)
Add accessible design system (#12)
Implement URL migration model (#13)
Add authenticated preview controls (#14)
Auto-mergeを無効にする
Auto-mergeを有効にすると、CIやレビュー条件が満たされた時点で自動的にマージできます。
便利ですが、CIが成功したことと、公開してよいことは同じではありません。
CIで確認できるのは、主に次です。
ビルドできる
テストが通る
形式違反がない
既知の検査に合格する
CIでは判断できないものもあります。
この変更を今取り込むべきか
会社の事実として公開してよいか
顧客承認が済んでいるか
DNSや本番環境を変更してよいか
変更時期は適切か
そのため、Auto-mergeは無効にし、最後は人間がSquash and mergeを実行します。
マージ後にブランチを自動削除する
マージ済みのfeature branchを自動削除すると、作業中のブランチだけが残ります。
ブランチを削除しても、Pull Request、レビューコメント、コミット、マージ履歴はGitHub上に残ります。
今回採用したRuleset
対象はデフォルトブランチ、つまりmainです。
Ruleset:
main-protection
Enforcement:
Active
Target:
Default branch
設定内容は次のとおりです。
Restrict deletions
Block force pushes
Require linear history
Require a pull request before merging
Required approvals:
0
Require Code Owner review:
Disabled
Require review conversation resolution:
Enabled
Allowed merge methods:
Squash only
Require status checks:
validate
Require branches to be up to date:
Enabled
Automatically request Copilot review:
Enabled
Review new pushes:
Enabled
Review draft pull requests:
Enabled
Bypass actors:
None
GitHubのRulesetでは、ブランチ削除、force push、Pull Request必須、ステータスチェック、Linear historyなどを組み合わせられます。
各Ruleset項目の意味
Restrict deletions
mainブランチの削除を禁止します。
防止したい事故は次のようなものです。
操作ミスでmainを削除
スクリプトが誤ったbranchを削除
AIエージェントが削除対象を間違える
デフォルトブランチでは、原則として有効にします。
Block force pushes
mainへのforce pushを禁止します。
通常のpushでは履歴の続きを追加します。
A - B - C
force pushでは、既存の履歴を別の履歴へ置き換えられます。
変更前:
A - B - C
変更後:
A - X - Y
他のブランチやPull RequestがBやCを基準にしていると、競合や履歴破損の原因になります。
mainではforce pushを禁止し、feature branchをrebaseした場合だけ、必要に応じて次を使います。
git push --force-with-lease
--force-with-leaseは、リモートが想定外に更新されていた場合に上書きを止めるため、単純な--forceより安全です。
Require a pull request before merging
mainへの直接pushを禁止し、すべての変更をPull Request経由にします。
一人開発でも、Pull Requestを使うと次が残ります。
変更目的
Issueとの対応
差分
CI結果
Copilotレビュー
Codexレビュー
修正経緯
人間の最終判断
マージ日時
Pull Requestは、他人に承認してもらうためだけのものではありません。
変更を1つのレビュー可能な単位にまとめるためのものです。
Required approvalsを0にする理由
一人プロジェクトでRequired approvalsを1にすると、自分のPull Requestを自分で承認できないため、マージできなくなります。
GitHubではPull Requestの作成者は自分のPull Requestを承認できません。Copilotのレビューも必須承認にはカウントされません。
そこで、今回は次の構成にしました。
Required approvals: 0
Pull Request: 必須
CI: 必須
Conversation resolution: 必須
AIレビュー: 実施
人間の手動マージ: 必須
Required approvalsを1以上にするのは、次のような場合です。
- 開発者が2人以上いる
- 変更者と承認者を分離したい
- 顧客データや個人情報を扱う
- 認証、決済、給与、会計などの高リスクシステム
- セキュリティ担当者の承認が必要
- 監査上、職務分掌が求められる
Require Code Owner reviewを無効にする理由
CODEOWNERSを使うと、ファイルやディレクトリごとの担当者を指定できます。
/cloudflare/ @infrastructure-team
/src/content/ @content-team
/security/ @security-team
チーム開発では有効ですが、一人プロジェクトで必須にすると自己承認できず、運用が停止する可能性があります。
そのため、現段階では無効にしています。
担当者が増えた時点で、例えば次のように分けることができます。
採用情報:
採用担当者
法務ページ:
管理部門
Cloudflare設定:
インフラ担当者
セキュリティ関連:
セキュリティ担当者
Require conversation resolution
レビューコメントに未解決の会話がある場合、マージできなくします。
Copilot:
入力値の検証が不足しています
状態:
Unresolved
修正した場合は、変更内容を返信してResolve conversationします。
修正しない場合も、理由を記録してから解決します。
今回は公開入力を受け付けないため対象外
Issue #123で別途対応
設計上意図した挙動
AIレビューを使う場合、Required approvalsよりもこの設定の方が実用的です。
Require status checks to pass
今回の必須チェックは次です。
validate
重要なのは、Rulesetに指定するのはワークフローの表示名ではなく、GitHubが報告するcheck context、通常はjob名だという点です。
例えば次のGitHub Actionsがあるとします。
name: Validate corporate website
jobs:
validate:
name: validate
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- run: pnpm install --frozen-lockfile
- run: pnpm test
- run: pnpm build
Rulesetへ登録するのは、次です。
validate
次ではありません。
Validate corporate website / validate
GitHub Actions
名前を間違えると、Pull Requestに次の表示が残ります。
Expected — Waiting for status to be reported
CIは成功しているのに、Rulesetが別の名前のチェックを待ち続けている状態です。
Require branches to be up to date before merging
これはStrict status checkとも呼ばれる設定です。
Pull Requestを作成した後、別のPull Requestがmainへマージされた場合を考えます。
PR作成時:
main A - B
feature A - B - C
別PRマージ後:
main A - B - D
feature A - B - C
featureのCIは成功していても、DとCを組み合わせた状態はテストされていません。
Strict設定では、featureへ最新mainを取り込んでから再度CIを実行します。
A - B - D - C'
安全性は上がりますが、mainが更新されるたびにCIの再実行が必要になります。
GitHubでは、StrictとLooseを次のように区別しています。
| 方式 | 最新mainへの更新 | 特徴 |
|---|---|---|
| Strict | 必須 | 安全性が高いが、CI再実行が増える |
| Loose | 不要 | CI回数は減るが、最新mainとの組合せを未検証でマージできる |
コードやビルド成果物を扱うリポジトリではStrict、文書中心のリポジトリではLooseも選択肢になります。
Require linear history
Linear historyを有効にすると、mainへmerge commitを作れなくなります。
履歴を次の形に保ちます。
A - B - C - D - E
次のような分岐を残しません。
A - B -------- M
\ C - D /
GitHubでは、Linear historyを有効にしたブランチではSquash mergeまたはRebase mergeが必要です。
Copilot review on draft and push
今回の設定では、Draft Pull RequestにもCopilotレビューを実行し、新しいcommitがpushされるたびに再レビューします。
Copilotは、通常は一度レビューした後、新しいpushを自動で再レビューしません。RulesetでReview new pushesを有効にすると、更新後も再レビューされます。
Draft段階からレビューさせる利点は、正式レビュー前に次を修正できることです。
- 入力検証不足
- 例外処理不足
- テスト漏れ
- セキュリティ上の問題
- 命名や保守性
- リポジトリ固有ルールとの不一致
リポジトリには、次のような指示ファイルも置けます。
.github/copilot-instructions.md
AGENTS.md
.github/skills/code-review/SKILL.md
Copilotは.github/copilot-instructions.mdやAGENTS.mdを使って、リポジトリ固有のレビュー方針を理解できます。
Bypass actorを設定しない
Rulesetを無視できるユーザーやAppを設定していません。
つまり、管理者であっても通常は次を行えません。
CIを無視してマージ
Pull Requestを使わずmainへpush
未解決会話を残してマージ
force push
Squash以外でマージ
緊急時の例外経路を作ることもできますが、例外は通常経路になりやすいため、小規模プロジェクトでは設けない方が単純です。
Squash merge、Merge commit、Rebase mergeの違い
前提として、次の履歴があるとします。
main:
A - B
feature:
C - D - E
Merge commit
結果は次です。
A - B -------- M
\ C - D - E /
feature branchの各コミットを残し、統合点としてMというmerge commitを追加します。
GitHubの通常のMerge pull requestは、feature branchのコミットを保持し、--no-ff相当のmerge commitを作ります。
長所
- 個々のコミットをすべて保持できる
- ブランチの分岐と統合が分かる
- 長期開発の経緯を追いやすい
- release branchなどに向く
短所
- 履歴が複雑になる
- WIPや修正途中のコミットも残る
- AIによる細かい修正コミットが大量に残る
- PR単位で履歴を読むのが難しくなる
向いている場合
- 大規模チーム
- 長期feature branch
- release branch
- 個々のコミットに独立した意味がある
- 分岐構造を保存したい
Squash merge
結果は次です。
A - B - S
C、D、Eを1つの新しいコミットSへまとめます。
S = C + D + Eの最終差分
GitHubのSquash mergeは、Pull Request内の複数コミットを1つに統合してbase branchへ追加します。
長所
- 1 Pull Request = 1 commitになる
-
mainの履歴が読みやすい - PR単位でrevertしやすい
- WIPコミットを残さなくてよい
- AI支援開発と相性がよい
- Issue、PR、commitの対応が明確になる
短所
- 元のcommit SHAは
mainに残らない - 個々の修正時点や詳細履歴を失う
- PR内のcommit単位で
git bisectしにくい - 複数の無関係な変更を1PRに入れると、1つにまとめられてしまう
向いている場合
- 一人または少人数
- 1 PRを1つの論理変更として管理する
- AIが複数回修正commitを作る
-
mainを変更履歴として読みたい - PR単位で取り消したい
今回の運用ではSquash mergeを採用しました。
Rebase and merge
結果は次です。
A - B - C' - D' - E'
merge commitは作らず、feature branchの各コミットをmainの先頭へ並べ直します。
GitHubのRebase and mergeでは各コミットがbase branchへ個別に追加されますが、新しいcommit SHAが生成されます。
長所
- Linear historyになる
- 個々のコミットを残せる
- merge commitが増えない
- 整理されたcommit群を維持できる
短所
- commit SHAが変わる
- WIPコミットも残る
- commitが整理されていないと履歴が汚れる
- rebaseや競合解消の理解が必要
- PR全体を一度にrevertしにくい
向いている場合
- 各commitが独立して完成している
- commit単位の履歴が重要
- OSSなどで各変更の意味を残したい
- 開発者がrebase運用に慣れている
3方式の比較
| 項目 | Merge commit | Squash merge | Rebase merge |
|---|---|---|---|
| PR内commitを保持 | ○ | × | ○ |
| ブランチ構造を保持 | ○ | × | × |
| Linear history | × | ○ | ○ |
| 履歴の読みやすさ | △ | ◎ | ○ |
| PR単位のrevert | ○ | ◎ | △ |
| WIP commitを除去 | × | ◎ | × |
| AI支援開発との相性 | △ | ◎ | △ |
| 長期branchとの相性 | ◎ | △ | ○ |
| 一人プロジェクト | △ | ◎ | ○ |
Squash mergeとstacked Pull Requestの注意点
Squash mergeには、複数のPull Requestを積み重ねるstacked PRで注意点があります。
PR #1:
main → branch-A
PR #2:
branch-A → branch-B
PR #1をSquash mergeすると、mainにはbranch-Aの元commitではなく、新しいSquash commitが作られます。
そのため、PR #2をそのままmain向けへ変更すると、PR #1の変更が重複して見える場合があります。
安全な手順は次です。
git fetch origin
git switch branch-B
git rebase origin/main
git push --force-with-lease
その後、PR #2のbaseをmainへ変更します。
Squash mergeを使う場合は、次のどちらかが扱いやすいです。
PRを順番に作り、1件ずつマージする
または
stacked PRを使い、前段マージ後に後段をrebaseする
AIレビューの役割分担
今回の運用では、複数のAIを同じ役割にせず、少し異なる観点で使います。
GitHub Copilot
- Draft段階から自動レビュー
- 新しいpushごとに再レビュー
- 行単位の指摘
- 既存コードとの整合性
- 実装上の問題
- 修正候補の提示
ChatGPT Codex
- Pull Request全体のレビュー
- 設計境界の確認
- P1/P2レベルの問題抽出
- テストの不足
- セキュリティや運用上の抜け
- exact headを指定した最終レビュー
GitHub Actions
- ビルド
- テスト
- lint
- 型検査
- リダイレクト整合性
- 秘密情報やバックアップ混入検査
- 再現可能な機械判定
人間
- 目的に合っているか
- 公開してよい情報か
- AIの指摘を採用するか
- リスクを許容できるか
- マージするか
- 本番へ反映するか
Codexを含むAIが生成した変更も、通常のPull Requestレビュー工程で人間が確認する前提にします。OpenAIも、Codexが生成した変更はレビューしてからマージまたは取り込む形で案内しています。
Final human gate
Pull Request本文には、人間の最終確認欄を設けます。
## Final human gate
- [ ] 対象Issueと目的を確認した
- [ ] 最新head SHAを確認した
- [ ] 必須CIがすべて成功している
- [ ] Copilotの指摘を確認した
- [ ] CodexのP1/P2が残っていない
- [ ] 未解決conversationがない
- [ ] 秘密情報やRestrictedデータを含まない
- [ ] 本番環境を変更しない、または別途承認済み
- [ ] 手動Squash mergeを実行する
最後の項目は、実際にはマージ操作そのものです。
運用上はマージ直前に確認済みとしてチェックし、GitHubのmerged状態とmerge commit SHAを最終的な実行証跡にします。
セキュリティ設定
Dependency graph
package.jsonやlockfileを解析し、直接・間接依存関係を把握します。
Dependabot alertsやDependabot security updatesの基礎になります。
Dependabot alerts
既知の脆弱性を含む依存関係を検出します。
Dependabotは、GitHub Advisory Databaseへ新しい脆弱性が追加された場合や、dependency graphが変更された場合に検査します。
Dependabot security updates
修正バージョンへ更新するPull Requestを自動作成します。
脆弱性検出
↓
修正バージョンを特定
↓
Dependabot PR
↓
CI
↓
人間確認
↓
Squash merge
Secret scanning
commit済みのAPIキー、token、秘密鍵などを検出します。
検出された場合は、ファイルから削除するだけでは不十分です。
秘密情報を失効
新しい値を発行
利用履歴を確認
Git履歴から除去
影響範囲を調査
Push protection
秘密情報がGitHubへpushされる前にブロックします。
GitHubのPush protectionは、対応するsecret patternを検出するとpushを停止します。
ただし、すべての独自パスワードや機密データを検出できるわけではありません。
そのため、リポジトリ側でも次を行います。
.envをgitignore
wp-config.phpを禁止
SQL、WXR、バックアップarchiveを禁止
独自validator
PRレビュー
Restricted storageとの分離
Admin権限を常用しない
GitHub OrganizationのRepository roleには、Read、Triage、Write、Maintain、Adminがあります。
GitHubはMaintainを「機密性の高い操作や破壊的操作を除き、リポジトリを管理する人向け」、Adminを「セキュリティ管理やリポジトリ削除を含む完全な権限が必要な人向け」と位置付けています。
今回、Adminを一時的に使ったのは次の設定のためです。
Ruleset
Merge方式
Secret scanning
Push protection
Dependabot
Copilot automatic review
設定完了後はMaintainへ戻します。
これは最小権限の原則です。
再利用できる設定テンプレート
一人+AIレビュー型
repository:
visibility: private
default_branch: main
merge:
squash: true
merge_commit: false
rebase: false
auto_merge: false
delete_branch_after_merge: true
suggest_update_branch: true
ruleset:
target: default_branch
enforcement: active
restrict_deletions: true
block_force_pushes: true
require_pull_request: true
required_approvals: 0
require_code_owner_review: false
require_conversation_resolution: true
allowed_merge_methods:
- squash
required_status_checks:
- validate
require_up_to_date_branch: true
require_linear_history: true
copilot:
review_drafts: true
review_new_pushes: true
bypass_actors: []
security:
dependency_graph: true
dependabot_alerts: true
dependabot_security_updates: true
secret_scanning: true
push_protection: true
小規模チームになった場合
Required approvals: 1
Code Owner review: 必要な領域だけ有効
Dismiss stale approvals: 有効
Require last push approval: 必要に応じて有効
高リスクシステムの場合
Required approvals: 2
Code Owner review: 必須
Security review: 必須
Staging deployment: 必須
Merge queue: 検討
Production environment approval: 必須
限定的な緊急bypass: 手順と監査付き
実際の標準運用
1. Issueを作る
2. Issue番号に対応したbranchを作る
3. 実装する
4. Draft PRを作る
5. CIを実行する
6. Copilotレビューを確認する
7. Codexレビューを確認する
8. 指摘を修正する
9. conversationを解決する
10. 最新mainを取り込む
11. latest headでCIを再実行する
12. PRをReadyにする
13. exact head SHAを確認する
14. 人間がFinal human gateを確認する
15. 手動Squash merge
16. mainのCIを確認する
17. branchを自動削除する
18. Issueが閉じたことを確認する
実際に遭遇した設定ミス
Rulesetの対象branchが空
Ruleset自体はActiveでも、Target branchが空ならどのbranchにも適用されません。
Target branches:
Include default branch
まで設定する必要があります。
必須チェック名が不一致
Ruleset:
Validate corporate website / validate
実際のcheck context:
validate
結果:
Expected — Waiting for status to be reported
必須チェックには、実際にGitHubへ報告されるjob名を指定します。
Required approvalsを1にする
一人プロジェクトでは自己承認できず、マージ不能になります。
AIレビューは必須承認数には含まれません。
Code Owner reviewを必須にする
一人プロジェクトでCODEOWNERSを必須にすると、将来CODEOWNERSファイルを追加した時点で自己承認できなくなる可能性があります。
Repository settingsとRulesetのマージ方式が矛盾
Ruleset:
Squash only
Repository:
Squash disabled
この構成ではマージできません。
AIレビューを人間承認の代わりにする
AIは有用ですが、会社の事実、公開可否、顧客承認、本番変更時期までは判断できません。
AIの役割は、最終承認ではなく、見落としを減らすことです。
まとめ
今回の運用は、次の考え方に集約できます。
mainを直接変更しない
すべての変更をPRとして可視化する
機械検査を必須にする
AIレビューを早い段階から使う
AIレビューを人間承認の代わりにしない
未解決の指摘を残さない
1 PRを1 Squash commitとして履歴へ残す
本番変更は人間が最後に決める
Admin権限を常用しない
一人でAIを使って開発すると、作業速度は上がります。
その速度を安全につなげるためには、AIを信頼することよりも、AIの変更を必ず通過させる仕組みを作ることが重要です。
GitHubのRuleset、Pull Request、CI、AIレビュー、Squash mergeを組み合わせれば、一人開発でも安全性と履歴の明確さを両立できます。
参考資料
- GitHub Docs「About merge methods on GitHub」
- GitHub Docs「Available rules for rulesets」
- GitHub Docs「Using GitHub Copilot code review on GitHub」
- GitHub Docs「Repository roles for an organization」
- GitHub Docs「Dependabot alerts」
- GitHub Docs「Enabling push protection for your repository」
- OpenAI「Using Codex with your ChatGPT plan」