Git & PR Discipline
Boris Cherny merged 141 pull requests in a single day. That number is not a flex — it is a signal about how his workflow is structured. At that velocity, manual PR hygiene would be impossible. The discipline has to be automated and internalized by every participant, including Claude.
This page covers the three rules that make high-velocity AI-assisted development sustainable.
The Three Rules
Rule 1: Squash Merge Always
Every PR, regardless of how many commits it contains, lands on main as a single commit.
# GitHub: set squash merge as the only allowed merge method# Repository Settings → General → Pull Requests# ✓ Allow squash merging# ✗ Allow merge commits# ✗ Allow rebase merging# Local git alias for quick squash mergesgit config --global alias.squash-merge '!f() { git merge --squash $1 && git commit; }; f'Why squash merge matters for AI-assisted work:
Claude generates many intermediate commits. “Fix lint”, “oops fix typo”, “try different approach”, “revert that”, “actually the first way was right” — these are useful during development but add noise to your main branch history.
Without squash merge, git log on main becomes unreadable. git bisect breaks because half the commits are in broken states. Reverting a feature means reverting 23 individual commits.
With squash merge, every entry in git log main represents a complete, working, intentional unit of work. Revert is one command. Bisect is reliable.
# Messy history WITHOUT squash merge* a7f3c2e fix: actually fix the lint error this time* 9b1d4a8 wip: trying different approach* 3e8f1c5 revert: revert previous attempt* 7c2a9b3 fix: address review comment* 1f4e6d2 fix: forgot to update types* 8a3c7e1 feat: add user authentication
# Clean history WITH squash merge* 2d9f4a1 feat: add user authentication (#142)Rule 2: 118-Line Median PR Size
Boris’s PRs average 118 lines changed. This is not a rule he enforces — it is an outcome of how he breaks down work.
Small PRs:
- Are reviewed faster (reviewers can hold the whole change in their head)
- Are safer to merge (less surface area for unexpected interactions)
- Are easier to revert if something goes wrong
- Accumulate into large features without any single PR being risky
The problem: Claude wants to do everything at once. Ask Claude to “add authentication” and it will implement the database schema, the API routes, the middleware, the frontend forms, the email templates, and the test suite in one session — and try to put it all in one PR.
You have to push back explicitly.
# Prompt template: splitting work into small PRs
I need to implement user authentication. Break this into the smallestpossible independent PRs. Each PR should:- Be mergeable without the others (or clearly depend on a previous one)- Change fewer than 150 lines where possible- Have a single clear purpose in its title
List the PRs before writing any code. I will approve the breakdownbefore you start implementing.Claude will propose something like:
PR 1: Add users table migration (12 lines)PR 2: Add User model with validations (45 lines)PR 3: Add POST /api/auth/register endpoint (67 lines)PR 4: Add POST /api/auth/login endpoint + JWT signing (89 lines)PR 5: Add auth middleware for protected routes (34 lines)PR 6: Add frontend login form (112 lines)PR 7: Add frontend registration form (98 lines)PR 8: Add auth integration tests (156 lines)Each can be reviewed and merged independently. If PR 6 has a design problem, PRs 1-5 are already in main and the work is not lost.
Rule 3: Accept Outliers for Coordinated Changes
The 118-line median has outliers. Some changes are genuinely large:
- Renaming a type used in 80 files
- Upgrading a dependency with a changed API
- Applying a consistent pattern across an entire layer
- Large database migrations with many columns
For these, Boris accepts a larger PR — but with extra discipline:
# Prompt for coordinated large changes
This PR will be large because it renames UserRecord → User across theentire codebase. It is a purely mechanical change with no logic modifications.
Please:1. Make ALL changes in a single commit titled "refactor: rename UserRecord to User"2. Do not mix any other changes into this PR3. Run the full test suite before marking complete4. In the PR description, note: "mechanical rename, no logic changes"The key: large coordinated changes are easy to review because they are boring. Every diff is the same pattern. Mixed large changes (refactor + feature + bugfix) are the problem — not large changes by themselves.
CI/CD Must Match Your Velocity
141 PRs/day means roughly one PR every 6 minutes during working hours. If your CI pipeline takes 15 minutes, you can never merge that fast.
Boris’s workflow implies fast CI:
# .github/workflows/ci.yml — optimized for speedname: CI
on: [pull_request]
jobs: fast-checks: runs-on: ubuntu-latest timeout-minutes: 5 # Hard limit — if it takes longer, fix the tests steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - run: npm ci --prefer-offline - run: npx tsc --noEmit - run: npm run lint -- --max-warnings 0 - run: npm test -- --passWithNoTestsFor low-risk mechanical changes (renames, dependency patches, doc updates), consider automatic merge when CI passes — no manual approval gate required.
AI-Assisted Development Changes PR Hygiene
Before AI coding tools, a PR typically represented hours of focused work. The commits inside were authored by a human who made deliberate choices.
With Claude, a PR might represent 3 minutes of human direction and 8 minutes of Claude iteration. The commits inside include scaffolding, false starts, and intermediate states that are only meaningful in context.
This is why squash merge is not just useful — it is necessary. Without it, your git log becomes a record of Claude’s thinking process rather than your project’s history.
# What git log looks like without squash merge on AI-generated code* 1a2b3c4 fix tests* 9d8e7f6 forgot to handle null case* 5c4b3a2 add type annotation* 8f7e6d5 claude: try different implementation* 2a1b9c8 initial implementation
# With squash merge — all of the above becomes:* 3f2e1d0 feat: add null-safe user lookup (#89)Commit Discipline Within a Session
Even within a single Claude session, how commits are structured matters. Boris’s preferred pattern: one commit per logical file group.
# Instruct Claude to commit in focused groups
After implementing each logical unit, create a focused commit:- Schema changes → one commit- Model/service layer → one commit- API routes → one commit- Tests → one commit
Use conventional commit format: feat/fix/refactor/test/choreDo not combine unrelated files in a single commit.This makes the squash merge commit message meaningful — Claude’s work history shows what was done, and the squash commit captures the intent.
The PR Flow
Prompt Template: PR Creation
Use this template when asking Claude to open a PR after completing work:
Create a PR for the changes in this branch. Requirements:- Title: conventional commit format (feat/fix/refactor/etc)- Body: 3-5 bullet points of what changed and why- Keep the title under 72 characters- Do not include implementation details in the title — save those for the body- If tests were added or modified, note which scenarios are now covered
Target branch: mainPrompt Template: Splitting Large Changes
This change is too large for a single PR. Split it into the minimumnumber of independent, mergeable PRs.
Rules for splitting:1. Each PR must leave the codebase in a working state when merged alone2. Order PRs so each builds on the previous (note dependencies)3. Prefer splitting by layer: data → logic → API → UI → tests4. Flag any file that must appear in multiple PRs (shared types, etc.)
Output the split plan as a numbered list before writing any code.Related
- Parallel Execution — how small PRs enable running many Claude instances without conflicts
- Verification-First — how tests make safe merging possible at this pace
- Automation Workflows — using
/scheduleto auto-generate release notes from merged PRs
Attribution: The 141 PRs/day figure and squash-merge discipline are from Boris Cherny’s public posts (March 2026). Boris created Claude Code at Anthropic.