You have finished your feature on a branch. Now what? You could merge it directly into main, but that skips the most valuable step in professional software development: code review. Pull requests are the mechanism that makes code review practical, and they are the single biggest quality improvement you can add to any team workflow.
Every major tech company uses pull requests. They exist not because developers do not trust each other, but because a second pair of eyes catches mistakes that the author is blind to. The author has been staring at the code for hours and has lost perspective. A reviewer sees it fresh.
Anatomy of a good pull requestWhat is pull request?A proposal to merge code changes into a shared branch, where teammates review the diff before it's accepted.
A pull request has several components that work together to communicate your changes effectively.
The title
Keep it short and descriptive. Use the same conventional commitWhat is commit?A permanent snapshot of your staged changes saved in Git's history, identified by a unique hash and accompanied by a message describing what changed. format you use for commits:
feat: add email validation to registration form
fix: resolve race condition in user lookup
refactor: extract payment logic to separate moduleThe description
The description is where you explain the why, not just the what. A good template:
## What does this PR do?
Adds email validation to the registration form to prevent
invalid emails from reaching the backend.
## Why?
Users were submitting malformed emails that caused silent
failures in the welcome email service (see issue #142).
## How to test
1. Go to /register
2. Enter an invalid email like "notanemail"
3. Verify the form shows a validation error
4. Enter a valid email and verify registration works
## Screenshots
(if UI changes)The diffWhat is diff?A comparison showing exactly which lines were added, removed, or changed between two versions of code.
Keep your PRs small and focused. Research shows that review quality drops sharply after 400 lines of changes.
| PR size | Review quality | Time to review | Chance of catching bugs |
|---|---|---|---|
| < 200 lines | Excellent | 15-30 min | High |
| 200-400 lines | Good | 30-60 min | Medium |
| 400-1000 lines | Poor | 1-2 hours | Low |
| > 1000 lines | Rubber stamp | "LGTM" | Very low |
If your PR is over 400 lines, consider splitting it into smaller, independent PRs that can be reviewed and merged separately.
The code review process
As a reviewer
When reviewing someone else's code, focus on these areas in order of importance:
- Correctness: Does the code actually do what the PR claims? Are there edge cases that are not handled?
- Security: Are there SQL injectionWhat is sql injection?An attack where user input is inserted directly into a database query, letting the attacker read, modify, or delete data. Parameterized queries prevent it. risks, XSSWhat is xss?Cross-Site Scripting - an attack where malicious JavaScript is injected into a web page and runs in other users' browsers, stealing data or hijacking sessions. vulnerabilities, or leaked credentials?
- Design: Is the code in the right place? Does it follow the existing patterns in the codebase?
- Readability: Can you understand the code without the author explaining it to you?
- Style: Does it follow the team's coding conventions?
# Check out the PR branch locally to test it
git fetch origin
git checkout feature/email-validation
# Run the tests
npm test
# Try the feature manually
npm run devAs an author
Respond to every comment. If you disagree with a suggestion, explain your reasoning rather than ignoring it. Common responses:
- "Good catch, fixed in abc1234"
- "I considered that approach, but X because Y"
- "I'll address that in a follow-up PR to keep this one focused"
Branch protection rules
Branch protection prevents anyone from pushing directly to important branches. On GitHub, you configure these in Settings > Branches.
Essential protections for main:
# GitHub branch protection settings
Require pull request reviews: true
Required approving reviews: 1 # At least one approval
Dismiss stale reviews: true # Re-review after new commits
Require status checks: true # CI must pass
Include administrators: true # Rules apply to everyone| Protection | What it prevents |
|---|---|
| Require PR reviews | Direct pushes to main |
| Required approvals | Merging without review |
| Dismiss stale reviews | Merging after changes without re-review |
| Require status checks | Merging broken code |
| Include admins | Anyone bypassing the rules |
Without branch protection, a single developer can accidentally push broken code to main and take down production. Protection rules make this physically impossible.
Merge strategies
When a PR is approved, you have three options for how to merge it:
# 1. Merge commit (preserves all commits + adds merge commit)
git merge feature/email-validation
# 2. Squash and merge (combines all commits into one)
git merge --squash feature/email-validation
# 3. Rebase and merge (replays commits on top of main)
git rebase main feature/email-validation| Strategy | History | Best for |
|---|---|---|
| Merge commit | All commits preserved + merge commit | Detailed history, large features |
| Squash merge | One clean commit per PR | Clean main history |
| Rebase merge | Linear history, no merge commit | Teams that value linear logs |
Most teams use squashWhat is squash?Combining multiple commits into a single commit, typically done before merging a feature branch to keep the main branch history clean. merge for a clean main history where each commitWhat is commit?A permanent snapshot of your staged changes saved in Git's history, identified by a unique hash and accompanied by a message describing what changed. corresponds to one PR.
Quick reference
| Concept | Best practice |
|---|---|
| PR size | Under 400 lines of changes |
| PR title | Conventional commit format (feat:, fix:) |
| PR description | Explain why, not just what |
| Review focus | Correctness > Security > Design > Readability > Style |
| Branch protection | Require reviews + CI checks on main |
| Merge strategy | Squash merge for clean history |