Better Pull Requests
The Complete Guide
Learn how to write pull requests that get reviewed faster and approved more often. Includes code examples, PR checklists, description templates, and best practices for GitHub, GitLab, and Bitbucket.
Table of Contents
What Makes a Great Pull Request?
A great pull request isn't just about working code. It's about making your reviewer's job easier. When reviewers can quickly understand what changed and why, they approve faster and give better feedback.
Research from Google and Microsoft shows that PRs under 400 lines get reviewed 2x faster and have 50% fewer defects than larger PRs. But size is just one factor. Great PRs also have:
Clear Context
The description explains why the change exists, not just what changed. Links to issues, tickets, or design docs give full background.
Focused Scope
One logical change per PR. No mixing refactoring with feature work, no unrelated cleanup, no scope creep.
Thorough Testing
Evidence that the code works: test results, screenshots, demo videos, or step-by-step reproduction instructions.
Respectful of Reviewer Time
Self-reviewed first, automated checks pass, no obvious mistakes, and formatted consistently with the codebase.
Key Takeaway
Great PRs optimize for reviewer experience. Every minute you spend making your PR easier to review saves time across all your reviewers. On a team of 5, that's 5x ROI on your documentation time.
Anatomy of a PR That Gets Approved Fast
Fast-approved PRs share a common structure. Here's the anatomy of a PR that reviewers love:
Descriptive Title (50 chars max)
Use imperative mood: "Add user authentication" not "Added authentication". Start with a verb. Follow team conventions (e.g., feat:, fix:).
feat: Add OAuth2 authentication with GoogleUpdated some files for auth stuffContext Section
Explain why this change exists. Link to the issue/ticket. Describe the problem being solved.
Changes Section
Bullet list of what changed. Focus on what, not how (code shows how).
Testing Section
Prove it works. Screenshots, test results, or step-by-step instructions.
Notes Section (Optional)
Breaking changes, migration steps, deployment notes, or areas needing extra attention.
Pro Tip
Use a PR template to enforce this structure. GitHub, GitLab, and Bitbucket all support templates in .github/pull_request_template.md. It takes 5 minutes to set up and saves hours of back-and-forth.
Writing PR Descriptions That Reviewers Love
Your PR description is the first thing reviewers see. A good description answers questions before they're asked, while a bad description wastes everyone's time.
The Bad PR Description
What's wrong? No context, vague changes, no testing info. Reviewers have to read the entire diff to figure out what's happening.
The Good PR Description
Why it's better: Clear problem statement, specific changes, testing evidence, deployment notes. Reviewers know exactly what to expect.
Common Mistake
Don't just copy commit messages into the PR description. Commit messages are implementation details. PR descriptions are for humans reviewing the overall change. Focus on the why and what, not the how.
Keeping PRs Small and Focused
The single most impactful change you can make is to keep PRs small. Data from Google, Microsoft, and Cisco shows that smaller PRs are reviewed faster, have fewer defects, and get better feedback.
The Numbers
How to Keep PRs Small
1. Split by Functionality
Break large features into incremental PRs: first the data model, then the API, then the UI. Each PR should be independently deployable or use feature flags.
2. Separate Refactoring from Features
Never mix refactoring with new features. First PR: refactor existing code. Second PR: add new feature using refactored code. This makes both PRs easier to review.
3. Use Feature Flags
Ship incomplete features behind flags. This lets you merge small PRs continuously without exposing work-in-progress to users.
4. Exclude Generated Code
Don't include auto-generated files (migrations, build artifacts, lock files) in your line count. Focus reviewer attention on hand-written code.
Real-World Strategy
When you start a feature branch, plan your PR sequence upfront. Write down the logical steps and commit boundaries. This prevents the dreaded "giant PR" at the end. You'll merge faster and get better feedback along the way.
Code Examples: Good vs Bad PRs
Let's look at real code changes. These examples show common mistakes and how to fix them.
Example 1: Mixed Concerns
// PR: Add user profile feature
// 📁 src/auth/AuthService.ts
class AuthService {
- login(username, password) {
+ async login(credentials: LoginCredentials) {
// ... refactored auth logic
}
+ async updateProfile(userId, profile) {
+ // ... new profile feature
+ }
}Problem: Reviewer has to mentally separate refactoring (login signature change) from new feature (updateProfile). This slows down review and increases error risk.
// PR 1: Refactor AuthService to async/await
class AuthService {
- login(username, password) {
+ async login(credentials: LoginCredentials) {
// ... refactored auth logic
}
}// PR 2: Add user profile update feature
class AuthService {
async login(credentials: LoginCredentials) {
// ... existing code
}
+ async updateProfile(userId, profile) {
+ // ... new profile feature
+ }
}Why it's better: Each PR has one clear purpose. Reviewers can approve the refactoring quickly, then focus on the new feature logic separately.
Example 2: Vague Commit Messages
abc1234 fix stuff def5678 update code ghi9012 oops jkl3456 final changes
Problem: No context for what changed or why. Reviewers can't use commit history to understand the evolution of the PR.
abc1234 feat: Add UserProfile model and database migration def5678 feat: Implement updateProfile API endpoint ghi9012 feat: Add profile update form to dashboard jkl3456 test: Add unit tests for profile update flow
Why it's better: Each commit has a clear purpose. Reviewers can understand the implementation sequence. Use interactive rebase to clean up "fix typo" commits before review.
Example 3: Missing Context in Code
if (user.loginAttempts > 5) {
user.locked = true;
user.lockUntil = Date.now() + 1800000;
}Problem: Why 5 attempts? What is 1800000? Reviewers have to calculate (30 minutes) and guess business rules.
// Lock account after too many failed login attempts to prevent brute force
const MAX_LOGIN_ATTEMPTS = 5;
const ACCOUNT_LOCK_DURATION_MS = 30 * 60 * 1000; // 30 minutes
if (user.loginAttempts > MAX_LOGIN_ATTEMPTS) {
user.locked = true;
user.lockUntil = Date.now() + ACCOUNT_LOCK_DURATION_MS;
}Why it's better: Business logic is self-documenting. Reviewers immediately understand the security policy without mental math.
Self-Review Checklist
Before requesting review, check your own PR for these issues:
- No magic numbers — use named constants
- No mixing refactoring with features
- Commit messages describe why, not just what
- No commented-out code or debug logs
- Code follows team style guide
PR Templates and Checklists
Templates enforce consistency and reduce cognitive load. Here's a battle-tested PR template you can use with GitHub, GitLab, or Bitbucket.
PR Description Template
Pre-Submit Checklist
Use this checklist before clicking "Create Pull Request":
Implementation Guide: Save the template as .github/pull_request_template.md (GitHub), .gitlab/merge_request_templates/default.md (GitLab), or configure in Bitbucket repository settings.
Automating PR Quality Checks
Great teams automate quality checks so reviewers can focus on logic and architecture. Here are the must-have automations for every PR:
1. CI/CD Pipeline
Run tests, linting, type checking, and build on every PR. Block merging if checks fail. Use GitHub Actions, GitLab CI, or Bitbucket Pipelines.
# .github/workflows/pr-checks.yml
name: PR Checks
on: [pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
- run: npm run lint
- run: npm run type-check
- run: npm run build2. Code Coverage Enforcement
Require test coverage on new code. Tools like Codecov or Coveralls comment on PRs with coverage delta. Block PRs that decrease coverage.
3. AI Code Review
Use AI to catch bugs, security issues, and code smells before human review. Tools like Git AutoReview run Claude, Gemini, and GPT on every PR with human approval before posting.
4. Automated Security Scanning
Scan for vulnerabilities in dependencies (npm audit, Snyk, Dependabot) and code (CodeQL, Semgrep). Block PRs with critical security issues.
5. PR Size Checks
Automatically flag PRs over 400 lines. Use GitHub Actions or Danger.js to comment on large PRs: "This PR is large (847 lines). Consider splitting for faster review."
Automation Philosophy
Automate the boring stuff (syntax, formatting, tests) so human reviewers can focus on the interesting stuff (architecture, edge cases, maintainability). Every automated check is one less thing reviewers have to manually catch.
Common PR Anti-Patterns
Avoid these mistakes that slow down reviews and frustrate your team:
The Kitchen Sink PR
Multiple unrelated changes in one PR: new feature + refactoring + dependency updates + bug fixes. Reviewers don't know where to start.
The "Fix Review Comments" Commit
Responding to feedback with commits like "fix review comments" or "address feedback". Reviewers have to diff the diff to see what changed.
The Force-Push Rewriter
Force-pushing to rewrite history during active review. Reviewers lose their place, comments get orphaned, and everyone is confused.
The No-Description PR
Empty description or just "See title". Reviewers have to reverse-engineer your intent from code alone.
The "Works on My Machine" PR
No testing evidence, failing CI, or "tests pass locally" comments. Reviewers can't trust the code works.
The Merge-Without-Approval PR
Self-approving or merging before reviewers finish. Defeats the entire purpose of code review.
How AI Can Improve Your PRs
AI code review tools can catch issues before human reviewers see your PR. But not all AI tools are created equal. Human-in-the-loop approval prevents AI mistakes from cluttering your pull requests.
What AI Can Catch
Security Vulnerabilities
SQL injection, XSS, insecure dependencies, exposed secrets, authentication bypasses
Code Quality Issues
Unused variables, duplicate code, overly complex functions, inconsistent naming
Logic Errors
Off-by-one errors, null pointer exceptions, race conditions, incorrect API usage
Best Practice Violations
Missing error handling, improper resource cleanup, synchronous blocking in async code
Git AutoReview: Human-in-the-Loop AI
Git AutoReview runs Claude, Gemini, and GPT on your PR, but you approve every suggestion before it posts to your pull request. This prevents the 29-45% of AI hallucinations from reaching reviewers.
Try Git AutoReview Free
Install from VS Code Marketplace. Run AI review on your next PR. Approve the good suggestions, reject the hallucinations. No credit card required.
Install Git AutoReview FreeFrequently Asked Questions
How big should a pull request be?
Keep PRs under 400 lines of code changes. Research shows PRs under 400 lines get reviewed 2x faster and have 50% fewer defects than larger PRs. If your change is bigger, split it into multiple PRs with logical boundaries.
What should I include in a PR description?
Every PR description should answer: What changed? Why did it change? How was it tested? Include links to related issues, screenshots for UI changes, and migration steps for breaking changes. Use the template: Context, Changes, Testing, and Notes.
How to handle large PRs that can't be split?
For genuinely large changes (refactoring, migrations), provide extra documentation: architecture diagrams, step-by-step explanations, file-by-file guides, and schedule a synchronous review meeting. Consider draft PRs for early feedback before marking ready for review.
Should I squash commits before creating a PR?
Keep meaningful commit history during development, but clean it up before final review. Use interactive rebase to squash 'fix typo' and 'oops' commits, but keep logical steps separate. Many teams squash all commits on merge anyway, so prioritize PR-level clarity over commit-level perfection.
How do I write a good PR title?
Use the imperative mood ('Add feature' not 'Added feature'), start with a verb, keep it under 50 characters, and follow your team's convention (e.g., 'feat:', 'fix:', 'refactor:'). Good: 'Add user authentication with OAuth'. Bad: 'Updated some files'.
What's the best way to respond to PR feedback?
Respond to every comment (even if just 'Done' or thumbs up), push fixes in a new commit (don't force-push until approved), explain your reasoning when you disagree, and mark conversations as resolved only after the reviewer approves. Thank reviewers for their time.
How long should I wait before pinging reviewers?
Depends on team culture, but 24-48 hours is reasonable for most teams. If urgent, mention it in the PR description and ping in Slack/Teams. Set up PR notifications so reviewers see new requests immediately. Use draft PRs if you're not ready for review yet.
Should I use PR templates?
Yes. PR templates ensure consistency, reduce cognitive load for reviewers, and prevent missing critical information like testing steps or breaking changes. GitHub, GitLab, and Bitbucket all support PR templates in .github/pull_request_template.md.
Write Better Pull Requests Today
Use Git AutoReview to catch issues before human review. Human-in-the-loop AI with Claude, Gemini, and GPT. Works with GitHub, GitLab, and Bitbucket. Free to install.