Cheatsheet: Pull requests
Voice anchor
Section titled “Voice anchor”Git stores snapshots. Every other command is just navigating those snapshots.
A pull request is a proposal to merge one set of snapshots into another.
The mechanical loop
Section titled “The mechanical loop”# 1. Branch (assumes L5)git switch -c feature/payment-flow
# 2. Do the work; commit with discipline (L3)git add .git commit -m "feat(checkout): add stripe integration"
# 3. Push the branch (-u sets upstream for future pushes)git push -u origin feature/payment-flow
# 4. Open PR on the platform UI# 5. Write the description (next section)# 6. Request reviewers# 7. Address comments (push more commits to same branch)git add fix.tsgit commit -m "address review: handle null case"git push
# 8. Merge via UI (pick a strategy)# 9. Delete the branch (button in UI after merge)Canonical PR description structure
Section titled “Canonical PR description structure”## What this changes
Brief description of what the diff does. One paragraph. Bullets if multiple distinct changes.
## Why this matters
The motivation. What problem this solves. Link to ticket / design doc / customer report.
## How it was tested
What you ran, what you observed. Manual steps if applicable. Test coverage if added.
## Notes for the reviewer
Tradeoffs considered. Alternatives ruled out. Things you're unsure about. Pre-empts reviewer questions.Optional sections (add when relevant):
## Screenshots / videosFor UI changes.
## Breaking changesFor API or schema changes.
## Migration planFor schema migrations or coordinated deploys.
## Rollback planFor anything risky.Three merge strategies, decision rule
Section titled “Three merge strategies, decision rule”| If… | Choose |
|---|---|
| Branch has messy WIP commits | Squash |
| Branch represents a discrete unit and history matters | Merge commit |
| Branch has clean commits AND team wants linear history | Rebase |
| You don’t have a team default yet | Squash (safest starter) |
Review comment prefixes (use these)
Section titled “Review comment prefixes (use these)”| Prefix | Meaning | Author response |
|---|---|---|
nit: | Style preference, not blocking | Optional, fix or skip |
suggestion: | Consider this | Optional, engage or skip |
question: | Asking for clarification | Required, answer it |
blocking: | Must address before merge | Required, fix or push back |
If you don’t use prefixes, comments are ambiguous. Pick a convention; document in CONTRIBUTING.md.
Author etiquette quick rules
Section titled “Author etiquette quick rules”- Read your own diff before requesting review
- Run tests locally
- Self-review with explanatory comments
- Respond to every comment (even “fixed in
<sha>”) - Push fixes as new commits, don’t force-push during review
- Disagree with explanation, not silence
- Escalate to synchronous after 2-3 async rounds of disagreement
Reviewer etiquette quick rules
Section titled “Reviewer etiquette quick rules”- Within 1 business day for normal PRs, hours for urgent
- Review the code, not the person
- Be specific (“consider X for reason Y”) not vague (“this isn’t great”)
- Tag blocking vs non-blocking
- Approve when good enough, not perfect
- If you can’t approve, say what would unblock approval
The 8 anti-patterns
Section titled “The 8 anti-patterns”- Mega-PR: break into logical units (200-300 line sweet spot)
- Unrelated changes PR: one logical change per PR
- No description PR: spend three minutes on description
- Scope-drifted PR: update description as scope changes
- Generated code in diff: separate generated artifacts
- No tests: tests with the code, same PR
- Friday 5pm PR: time PRs for when you can engage with review
- Self-merge bypass: if review is being skipped routinely, the team has a process gap
Drill 4 model rewrites, review comment fixes
Section titled “Drill 4 model rewrites, review comment fixes”- “This is wrong.” becomes “This case crashes when
inputis null; can we add a null check or assert upstream?” - “Why didn’t you use the existing helper?” becomes “We have a
parseUser()helper inlib/auth.tsthat handles the same case. Worth using for consistency, unless there’s a reason this needs to be custom?” - “lgtm” becomes “Looks good, clean separation of concerns, tests cover the happy path and edge cases I’d worry about. Approving.”
- “Can we just not do this?” becomes “I’m hesitant about adding this feature because [specific reason]. Could we discuss the framing in a quick sync before committing to this approach?”
- “Did you test this?” becomes “What testing did you do? I don’t see new test cases in the diff; if it’s covered elsewhere, can you link?”
Drill 5 model answers, blocking vs nit
Section titled “Drill 5 model answers, blocking vs nit”- “This variable name is misleading; rename to
userIds.” Answer: nit (style; not load-bearing) - “Doesn’t handle null input; will crash in production.” Answer: blocking (correctness)
- “Prefer trailing commas.” Answer: nit (style; should be lint-enforced)
- “SQL injection vector.” Answer: blocking (security)
- “Consider extracting this into a helper.” Answer: suggestion (structural; optional)
What’s in L7
Section titled “What’s in L7”L7 covers merge conflicts: what happens when two branches modify the same lines, and how to resolve calmly. The PR loop from L6 continues to work; you just add a conflict-resolution step before merge. The mental model is unchanged (snapshots, navigation, labels); conflicts are just git asking “you have two snapshots that disagree on this line; which do you want?”