レビューで止まるPRを減らす:小さく出して自分で説明する型
AIで速く書いたPRほどレビューで止まる。小さく分け、説明を埋め、自己レビューする型をClaude Codeで仕組み化。コピペで動く差分サイズCI付き。
「実装はできてる。あとはレビュー通すだけ」——そう思って出したPRが、3日たってもマージされない。
差分は1,800行。説明欄は「Claudeで全体を改善しました」の一行。レビュアーからは「どこから見ればいい?」「このテスト動かした?」と質問が飛んできて、僕はそのたびにコードを読み返す羽目になりました。コードを書いた時間より、PRの言い訳をしている時間のほうが長い。
おかしいですよね。Claude Codeで実装は速くなったのに、マージは前より遅くなった。原因はすぐに分かりました。速く書けるようになった分、雑に大きく出すようになったんです。レビュアーが読める形に「梱包」する手間を、僕がサボっていただけでした。
この記事は、レビューする側の話ではありません。PRを出す側が、レビューで止まらないために何をするか——小さく分ける、自分で説明する、自分で先にレビューする。その型を、Claude Codeで半自動にする話です。
この記事の要点
- レビューで止まるPRの正体は「大きすぎる差分」と「説明不足」。中身が正しくても梱包が雑だと止まる
- 出す側の品質は3つだけ意識すればいい:小さく分ける/空欄なく説明する/出す前に自分でレビューする
- PRテンプレートで説明の空欄を可視化し、Claude Codeにはテンプレを「埋める」役だけ任せる(自由作文させない)
- 差分サイズはCIで機械的に止める。コピペで動く
check-pr-size.mjsを後半に置いた(700行・35ファイルから始める) - マージされる速さは、モデルの賢さより「レビュアーがどこから読めばいいか分かるか」で決まる
レビュー観点の作り方やコミット前の最終点検は、別記事のコードレビューの仕組み化とコミット前レビューゲートで扱っています。この記事はあくまで「出す前」に集中します。
レビューで止まるPRには、たった2つの共通点がある
何十本もPRを出して気づいたのは、止まるPRの理由がほぼ2つに収束することです。
ひとつは差分が大きすぎる。命名修正、整形、機能追加、テスト、ついでのリファクタが1本に混ざっている。レビュアーは2,000行の中から「本当に見るべき変更」を自力で探さないといけない。これは集中力の問題ではなく、物理的に無理な作業です。
もうひとつは説明がない。なぜこの変更が必要なのか、どこを重点的に見てほしいのか、テストは通ったのか。これが書かれていないと、レビュアーはコードから意図を「推理」することになります。推理は時間がかかるし、外れる。
逆に言えば、この2つを潰すだけでマージは劇的に速くなります。GitHubの公式ドキュメントでもPull Requestは「変更を提案し、レビューし、議論する場」と説明されていて(About pull requests)、議論の土台はコードそのものではなく「読める差分」と「読める説明」なんですよね。
Claude Codeを使うと、この2つがどちらも悪化しやすい。広範囲を一気に直せるから差分が膨らむし、説明欄はAIっぽい長文で埋まって中身が薄い。だから出す側に、意識的なブレーキが要ります。
まず差分を小さく分ける(一番効く)
順番として、説明を頑張るより先に差分を小さくするほうが効きます。小さければ説明も短くて済むからです。
僕の中の分け方はシンプルで、1本のPRには1種類の変更しか入れません。
| 変更の種類 | 例 | 同じPRに混ぜると |
|---|---|---|
| 機械的変更 | 整形、命名一括置換、import整理 | 本物の変更が埋もれる |
| 振る舞い変更 | 機能追加、バグ修正、ロジック変更 | レビュー観点がぼやける |
| テスト追加 | テストケース、fixture | 実装の差分と混ざって読めない |
特に「整形だけ」を別PRにするのは効果絶大です。整形PRは差分が大きくてもレビューが一瞬で終わる(見るべきロジックがないから)。逆に整形と実装が混ざると、レビュアーは全行を疑わないといけない。
Claude Codeで作業していると、頼んでいないリファクタまで「ついでに」やってくれることがあります。親切なんですが、PRの観点ではノイズです。実装を頼むときは「今回のタスクに直接関係する変更だけ。整形や命名変更は別にして」と最初に釘を刺しておくと、差分が締まります。
それでも大きくなったときは、Claude Codeに分割案を出させます。
# 現在のブランチの差分を見せて、PRの分割案を出させる
git diff origin/main...HEAD | claude -p "
このdiffを、レビューしやすいPRに分割する案を出してください。
- 「機械的変更(整形・命名)」「振る舞い変更」「テスト」で分類する
- それぞれを別PRにする場合の、含めるファイルの一覧
- 依存関係があるなら、マージすべき順番
- diffに書かれていない事実は推測しない
"
分割は手間に見えますが、レビュー往復が1回減るだけで元が取れます。大きいPRの「2,000行を1回でレビュー」より、小さいPRの「200行を10回」のほうが、トータルでは速いんです。
説明の空欄をテンプレートで可視化する
差分を小さくしたら、次は説明です。ここでのコツは、自由記述にしないこと。Claude Codeに「いい感じにPR説明書いて」と頼むと、毎回粒度がぶれて、肝心の情報が抜けます。
先に .github/pull_request_template.md を置きます。GitHubはこのファイルをPR本文に自動で差し込んでくれるので(PRテンプレートの作成)、「書き忘れ」を構造で防げます。
## 変更内容
<!-- 何を変えたか。実装・設定・ドキュメントを分けて書く。 -->
## なぜ必要か
<!-- Issue、障害、要望、代替案を1-3文で。 -->
## レビューしてほしい箇所
- [ ] ビジネスロジック
- [ ] UI/UX
- [ ] DB/API契約
- [ ] セキュリティ/プライバシー
## テスト証跡
- [ ] 自動テスト(コマンドと結果):
- [ ] 手動確認:
- [ ] スクリーンショット/録画:
## 差分サイズ
- 変更ファイル数 / 追加・削除行数:
- 分割しなかった理由:
## レビュアーへの引き継ぎ
<!-- 先に読むファイル、迷った点、残課題、後続PR。 -->
テンプレートの本当の価値は、書く側が自分の空欄に気づけることです。「分割しなかった理由」が空のまま出そうとして、「あ、これ分けられるな」と気づく。「テスト証跡」が空で、「まだ動かしてないじゃん」と気づく。レビュアーに指摘される前に、自分で気づける。
そのうえで、Claude Codeにはこのテンプレを埋める役だけ渡します。自由作文ではなく、空欄を事実で埋める作業です。
# diffを読ませて、テンプレの形式で本文を埋めさせる
git diff origin/main...HEAD | claude -p "
このdiffを読み、.github/pull_request_template.md の形式でPR本文を日本語で作成してください。
条件:
- diffに書かれていない事実を断定しない
- テストを実行した証拠がなければ「未実行」と明記する
- 専門用語は初出で短く説明する
- レビュアーが最初に見るべきファイルを3つ以内に絞る
- 最後に「人間が確認すべき未確定事項」を箇条書きにする
"
「レビューしてほしい箇所」を必ず埋めさせるようにしてから、レビューコメントが目に見えて変わりました。前は「全体的に確認します」みたいな抽象的なコメントだったのが、「認可判定はここ、UIはこの画面、移行はこのファイル」と渡すと、具体的な行へのコメントが来るようになった。レビュアーに考える起点を渡すかどうかの差です。
出す前に、自分で一回レビューする
差分を分け、説明を埋めたら、最後にもうひとつ。出す前に自分でレビューする。
恥ずかしい話、僕は昔これをサボっていました。「最後はレビュアーが見るんだから」と。でもそれは、相手の時間で自分のミスを直してもらっているだけなんですよね。printデバッグの消し忘れ、コメントアウトした古いコード、tokenの直書き——こういう「自分で気づけたはずのもの」をレビュアーに拾わせるのは、単純に失礼でした。
GitHubのPR画面の「Files changed」を自分で頭から読むのが基本です。そのうえで、機械的な観点はClaude Codeに先回りさせます。特にセキュリティは、人間の目だと見落とすので必ず通します。
この差分を、PRを出す前のセルフチェックとしてレビューしてください。
確認項目:
1. secret、token、API key、パスワードが直書きされていないか
2. デバッグ用のprint/console.log、コメントアウトした古いコードが残っていないか
3. 個人情報やメールアドレスがログ・fixtureに出ていないか
4. 権限チェックがUIだけでなくサーバー側にもあるか
5. エラー時に内部パスや認証情報を返していないか
重大度をHigh/Medium/Lowで付け、該当ファイル名と行を示してください。
断定できない箇所は「要確認」として残してください。
落とし穴は、AIが「問題ありません」とすぐ言い切ること。だから僕は「断定できない箇所も残して」と必ず添えます。セルフレビューでは、確信より「保留の列挙」のほうが役に立ちます。保留があれば、それをPR本文の「確認してほしい箇所」に書けばいい。
ここまでやって出したPRは、レビュアーが「ちゃんと自分で見てから出してるな」と分かる。その信頼があると、細かい往復が減ります。
差分サイズはCIで機械的に止める
「小さく出す」を意志の力に頼ると、忙しい日に必ず破綻します。だから機械に見張らせます。diff-size budget——「このPRは何ファイル・何行まで」という上限をCIに入れる、という考え方です。
まず差分を数えるスクリプトを置きます。lockfileや生成物は数えても意味がないので除外して、人間がレビューすべき行だけをカウントします。これはコピペでそのまま動きます。
#!/usr/bin/env node
// scripts/check-pr-size.mjs : レビュー対象の差分行数・ファイル数が予算内かチェックする
import { execFileSync } from "node:child_process";
// 引数: 比較範囲, 行数上限, ファイル数上限
const [range = "origin/main...HEAD", maxLinesRaw = "700", maxFilesRaw = "35"] =
process.argv.slice(2);
const maxLines = Number(maxLinesRaw);
const maxFiles = Number(maxFilesRaw);
// レビュー不要なファイル(lockfile・ビルド生成物など)は数えない
const ignored = [
/^package-lock\.json$/,
/^pnpm-lock\.yaml$/,
/^yarn\.lock$/,
/^dist\//,
/^coverage\//,
];
function numeric(value) {
const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : 0;
}
// git diff --numstat で「追加 削除 ファイル名」を取得
const output = execFileSync("git", ["diff", "--numstat", range], {
encoding: "utf8",
}).trim();
let files = 0;
let lines = 0;
for (const row of output.split(/\r?\n/).filter(Boolean)) {
const [added, deleted, file] = row.split("\t");
if (ignored.some((pattern) => pattern.test(file))) continue;
files += 1;
lines += numeric(added) + numeric(deleted);
}
// 予算オーバーなら exit 1 で落とす(CIが赤くなる)
if (files > maxFiles || lines > maxLines) {
console.error(
`PRが大きすぎます: ${files}ファイル / ${lines}行。` +
`予算は ${maxFiles}ファイル / ${maxLines}行です。`,
);
console.error("整形・生成物・振る舞い変更を別PRに分けてください。");
process.exit(1);
}
console.log(`PRサイズOK: ${files}ファイル / ${lines}行。`);
手元で試すなら一発です。
node scripts/check-pr-size.mjs "origin/main...HEAD" 700 35
あとはGitHub Actionsで回します。workflowは .github/workflows 配下のYAMLで定義します(workflow構文)。
name: PR quality
on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
permissions:
contents: read
pull-requests: read
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Install dependencies
run: npm ci
- name: Run project checks
run: |
npm run lint --if-present
npm test --if-present
- name: Enforce PR size budget
run: node scripts/check-pr-size.mjs "origin/${{ github.base_ref }}...HEAD" 700 35
これをprotected branchesのrequired status checksに入れると、予算オーバーのPRはマージできなくなります。上限はチームで決めればよく、僕は700行・35ファイルから始めて、リファクタPRだけ例外ラベルを要求しています。数字そのものより、「分割を意志ではなくルールにした」ことに意味があります。
よくある質問
Q. 小さいPRに分けると、レビュー回数が増えて逆に面倒では? 1回あたりは増えますが、合計は減ります。2,000行を1回見るより200行を10回見るほうが、見落としも往復も少ない。レビュアーの「うっ」となる心理的ハードルも下がるので、着手が速くなります。
Q. PR本文は結局Claude Codeに全部書かせていい? 本文の「下書き」はOK、「事実の創作」はNGです。diffに書かれていないテスト結果や挙動をAIが断定したら必ず消します。テンプレの空欄を事実で埋める使い方に限定すれば、AI生成でも安全です。
Q. 差分サイズの上限、いくつから始めればいい? 700行・35ファイルが無難な初期値です。厳しすぎるとチームがルールを嫌いになるので、最初は緩めに入れて、運用しながら下げます。リファクタや自動生成は例外ラベルで逃がすのがコツです。
Q. レビューする側の仕組みは別で要る? はい、役割が違います。出す側の品質はこの記事、レビューする側(観点・CODEOWNERS・CI)はコードレビューの仕組み化、commit前の最終点検はコミット前レビューゲートで分けています。
Q. 「テスト証跡」って何を書けばいい? 実行したコマンドと結果、手動で確認した画面や入力、そして「まだ確認していないこと」の3つです。大事なのは、レビュアーが同じことを再現できる粒度で書くこと。「動きました」だけだと証跡になりません。
実際に試した結果
この型を自分のNodeプロジェクトで回してみて、効果が一番大きかったのは意外にも差分サイズCIと「整形は別PR」のルールでした。技術的には地味なんですが、「今回のPRに整形を混ぜない」と決めただけで、レビュアーからの「ここ何で変わったの?」がほぼ消えた。
PRテンプレートも効きました。Claude Codeに本文を作らせると放っておくと長文になりがちですが、入力欄を固定したら、未実行テスト・セキュリティ確認・見てほしいファイルが自然に残るようになった。そして自分で「Files changed」を頭から読む習慣をつけてから、token直書きやデバッグログの消し忘れをレビュアーに拾わせることがなくなりました。
結局のところ、PRがマージされる速さは、AIがどれだけ賢いかではなく、レビュアーがどこから読めばいいか一目で分かるかで決まる。速く書けるようになったぶん、丁寧に梱包する。遠回りに見えて、これがチーム全体では一番速い、というのが今の実感です。
このPR品質の型は、研修やテンプレート販売の中身としてもそのまま使えます。PRテンプレート・CLAUDE.md・差分サイズCI・引き継ぎメモをセットで渡すと、チームへの導入が一気に進みます。土台になるCLAUDE.mdテンプレートを整えつつ、チーム導入を相談したい方は研修・相談ものぞいてみてください。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
まず無料PDFで基本を固め、繰り返し使う作業はGumroad教材へ、チーム導入や権限設計は導入相談へ進めます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
Claude Codeに1ファイルだけ直させる指示文のつくり方
「もっと良くして」で40行も変えられた失敗から学んだ、触る範囲・検証・戻し方をセットにしたClaude Code用の依頼文テンプレートを紹介します。
Claude Code の権限拒否から復旧する: 止まった理由を次の安全手順に変える
Claude Code のコマンドが拒否されたとき、焦って許可を広げずに、拒否理由、代替手順、証拠コマンド、再試行条件へ分解する方法。
Claude Codeにビルド→スモークテスト→自動修正を回させる足場の作り方
最小スモークテストの選び方、失敗ログを食わせて直させるループ、回数上限と確認ゲートで暴走を止める方法を、コピペで動くコード付きで紹介します。