Mastering Pull Requests: The Complete Collaboration Guide

What Are Pull Requests?

A Pull Request (PR) is a fundamental collaboration feature in Git-based platforms like GitHub and GitLab. It's a formal request to merge changes from one branch into another, typically used for:

  • Code Review: Team members review proposed changes before they're merged
  • Discussion: Collaborative discussion about implementation details
  • Quality Control: Ensure code meets team standards before integration
  • Documentation: Record of why changes were made and how
  • Continuous Integration: Trigger automated tests and builds

Simple Analogy: Think of a Pull Request like submitting a draft to an editor. You've written your article (made code changes), but before it gets published (merged into main codebase), other editors (team members) review it, suggest improvements, and ensure it meets publication standards.

The Pull Request Lifecycle

Create Branch
Isolate changes
Make Changes
Implement feature
Create PR
Submit for review
Code Review
Team feedback
Merge
Integrate changes

Why Pull Requests Matter

Pull Requests transform individual coding into team collaboration. Here's why they're essential:

Knowledge Sharing

Team members learn from each other's code. When you review someone's PR, you understand new patterns, techniques, and the codebase better.

Bug Prevention

Multiple eyes on code catch issues early. Studies show code review catches 60-90% of defects before they reach production.

Documentation

PR discussions document why decisions were made. This becomes invaluable when debugging or understanding code later.

Warning: Without a proper PR workflow, teams risk code quality issues, knowledge silos, and production bugs. Even small teams benefit from PRs.

Pull Request vs Merge Request

You might hear both terms. Here's the difference:

Aspect Pull Request (GitHub) Merge Request (GitLab)
Terminology "Pull" - You're requesting to pull changes into a branch "Merge" - You're requesting to merge branches
Platform GitHub's term GitLab's term
Concept Same concept, different name Same concept, different name
Functionality Code review, discussion, CI/CD integration Code review, discussion, CI/CD integration

Tip: The terms are functionally identical. This guide uses "Pull Request" but applies to both GitHub PRs and GitLab MRs.

Complete Pull Request Workflow

1

Step 1: Planning & Branch Creation

Before writing any code:

# Always start from an updated main branch
git checkout main
git pull origin main

# Create a descriptive branch name
git checkout -b feature/user-authentication

# Good branch naming conventions:
feature/description
bugfix/issue-number
hotfix/critical-issue
release/version-number

Why this matters: Starting from updated main ensures you're building on the latest code. Descriptive branch names help everyone understand what the PR is about.

2

Step 2: Making Changes & Committing

Development best practices:

# Make small, focused commits
git add file1.js
git commit -m "Add user model validation"

# Not like this:
git add .
git commit -m "Update everything"

# Good commit message structure:
feat: add user authentication
fix: resolve login error for expired tokens
docs: update API documentation
style: format code according to guidelines
refactor: simplify authentication logic

Commit Guidelines:

  • One commit = one logical change
  • Commit messages should explain why not just what
  • Keep commits small (easier to review)
  • Use conventional commits format if your team prefers it
3

Step 3: Pushing & Creating the Pull Request

When your feature is ready for review:

# Push your branch to remote
git push -u origin feature/user-authentication

# Then create PR on GitHub/GitLab
# Or use command line (GitHub CLI):
gh pr create --title "Add user authentication" \
  --body "Implements JWT-based authentication system" \
  --reviewer team-member1,team-member2
Add user authentication system
#142 by @developer feature/user-authentication → main

## Description
Implements JWT-based authentication with refresh tokens.

## Changes Made
- Added User model with validation
- Created auth middleware
- Implemented login/logout endpoints
- Added unit tests

## Testing
- All tests pass
- Manual testing completed

src/models/User.js +142 -0
src/middleware/auth.js +89 -0
tests/auth.test.js +203 -0

PR Description Best Practices:

  • Clearly explain what changes do and why they're needed
  • Include screenshots for UI changes
  • Link to related issues/tickets
  • Document testing performed
  • Note any breaking changes
4

Step 4: Code Review Process

The heart of collaboration:

JS
John Smith (Reviewer)
2 hours ago

Great start! I have a few suggestions:

src/models/User.js:45-50

Consider adding input sanitization here to prevent NoSQL injection.

src/middleware/auth.js:23

Should we add rate limiting to prevent brute force attacks?

AD
Alice Developer (Author)
1 hour ago

Thanks for the review! I've addressed your comments:

src/models/User.js:45-50

Added input sanitization using mongoose-sanitize.

src/middleware/auth.js:23

Implemented rate limiting of 5 attempts per minute.

Code Review Checklist

Code Quality
Is the code clean, readable, and well-structured?
Functionality
Does it work as intended? Are edge cases handled?
Tests
Are there adequate tests? Do they pass?
Security
Any security vulnerabilities or concerns?
Performance
Will this impact performance negatively?

Reviewer Etiquette:

  • Be constructive, not critical
  • Explain why you're suggesting changes
  • Review within agreed timeframe (usually 24-48 hours)
  • Focus on important issues first
  • Use line comments for specific suggestions
5

Step 5: Addressing Feedback & Updating PR

Responding to review comments:

# Make requested changes locally
git checkout feature/user-authentication
git add .
git commit -m "Add input sanitization as suggested"

# Push updates to the same branch
git push origin feature/user-authentication

# The PR automatically updates with new commits
# Mark resolved comments on GitHub/GitLab

Important: Never force push during code review unless you're squashing commits. Force pushing removes the review history and makes it hard for reviewers to see what changed.

Handling Different Opinions:

  • Discuss technical merits, not personal preferences
  • If stuck, involve a third person or team lead
  • Sometimes agree to disagree and schedule follow-up
  • Document decisions in PR comments
6

Step 6: Final Approval & Merging

When all reviews are addressed:

# Reviewer approves the PR
# GitHub/GitLab shows approval status

# Merge options (choose one):
1. Merge commit - Preserves all individual commits
2. Squash and merge - Combines all commits into one
3. Rebase and merge - Linear history, no merge commit

# Delete feature branch after merge (recommended)
git branch -d feature/user-authentication
git push origin --delete feature/user-authentication

Merge Strategy Guidelines:

  • Merge commit: Good for preserving history of collaborative work
  • Squash and merge: Best for cleaning up many small commits
  • Rebase and merge: Creates clean linear history, but rewrites history

Pre-Merge Checklist:

  • ✅ All required approvals received
  • ✅ CI/CD pipelines passed
  • ✅ No merge conflicts
  • ✅ Documentation updated if needed
  • ✅ Product/QA sign-off if required

Interactive Pull Request Demo

Try It: Complete a Pull Request Workflow

Walk through a simulated PR from creation to merge:

Feature: Add Dark Mode
#1 by You feature/dark-mode → main

Status: Draft

Reviewers: Not assigned

Checks: ❌ CI not run

src/theme/dark-mode.js +0 -0
tests/theme.test.js +0 -0
PR Status: Not created
Files Changed: 0
Review Status: No reviews

Advanced Pull Request Techniques

Draft Pull Requests

Use draft PRs when you want to:

  • Share work in progress for early feedback
  • Trigger CI/CD before formal review
  • Coordinate with other developers
  • Get architecture feedback before completion
# Create draft PR (GitHub CLI)
gh pr create --draft

PR Templates

Standardize PR descriptions with templates:

## Description
[What does this PR do?]

## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change

## Testing
[How was this tested?]

Store in .github/PULL_REQUEST_TEMPLATE.md

Automation & Bots

Automate PR workflows:

  • Dependabot: Automatic dependency updates
  • Codecov: Enforce test coverage
  • Semantic PRs: Enforce commit message format
  • Auto-assign: Assign reviewers based on code changes
  • Stale bot: Close inactive PRs

Real-World Scenarios & Solutions

A

Large PR That's Hard to Review

Problem: PR with 50+ files changes takes days to review.

# Solution: Break into smaller PRs
# 1. Create feature branch from main
git checkout -b feature/large-refactor

# 2. Split into logical pieces
git checkout -b feature/refactor-part1
# Work on first logical unit...
git push -u origin feature/refactor-part1
# Create PR for part 1

# 3. Continue from same base
git checkout feature/large-refactor
git checkout -b feature/refactor-part2
# Work on second logical unit...

Better Approach: Plan for smaller increments from the start. If you find yourself with a large PR:

  1. Identify logical boundaries in your changes
  2. Create separate branches for each logical unit
  3. Submit PRs in dependency order
  4. Use feature flags if changes are interdependent
B

Merge Conflicts During Review

Problem: Other changes merged to main cause conflicts with your PR.

# Solution: Regularly sync with main
git checkout main
git pull origin main
git checkout feature/your-feature
git merge main

# OR use rebase (cleaner history)
git checkout feature/your-feature
git fetch origin
git rebase origin/main

# Resolve conflicts, then continue
git rebase --continue
git push --force-with-lease

Prevention:

  • Keep PRs small and focused (reduces conflict surface)
  • Rebase daily when working on long-lived branches
  • Coordinate with team on overlapping changes
  • Use feature branches for isolated work

Important: Only force push (--force-with-lease) during active development, not after review has started, unless you're squashing commits.

C

Getting Stuck in Review Cycles

Problem: PR has been in review for days with back-and-forth comments.

# Solution: Schedule a pairing session
# 1. Identify blocking issues
git checkout feature/stuck-pr
# 2. Invite reviewer to pair program
# 3. Resolve issues together in real-time

# Alternative: Request final decision
# Comment on PR:
"@team-lead Can you make a final decision on these remaining items?"

Strategies to Avoid Review Stalls:

  • Timebox reviews: "Please review by EOD"
  • Escalate early: Involve team lead after 2 rounds
  • Pair upfront: Discuss approach before coding
  • Accept partial: Merge what's agreed, track follow-ups

Pull Request Templates & Automation

# .github/PULL_REQUEST_TEMPLATE.md

## 🎯 Description
Briefly describe the purpose of this change

## 🔗 Related Issues
Link to any related issues (e.g., "Fixes #123")

## 📋 Changes Made
- [ ] List key changes
- [ ] Use bullet points

## 🧪 Testing
- [ ] Unit tests added/updated
- [ ] Integration tests pass
- [ ] Manual testing completed

## 📸 Screenshots (if UI changes)
Add before/after screenshots

## ✅ Checklist
- [ ] Code follows team conventions
- [ ] Self-review completed
- [ ] Documentation updated if needed
- [ ] No console errors/warnings
- [ ] No new linting errors
# GitHub Actions: Auto-assign reviewers
# .github/workflows/assign-reviewers.yml
name: Assign Reviewers
on:
  pull_request:
    types: [opened, ready_for_review]

jobs:
  assign:
    runs-on: ubuntu-latest
    steps:
      - name: Assign based on file changes
        uses: kentaro-m/auto-assign-action@v1.2.1
        with:
          configuration-path: '.github/auto_assign.yml'

Best Practices Summary

For PR Authors

Keep PRs Small
Focus on one thing. If it's large, split it up.
Write Clear Descriptions
Explain what, why, and how. Include testing details.
Self-Review First
Review your own code before requesting reviews.
Respond Promptly
Address review comments within 24 hours.

For Reviewers

Review Within 24 Hours
Don't leave PRs hanging. If busy, at least acknowledge.
Be Constructive
Focus on code, not person. Explain reasoning.
Check the Important Stuff
Security, performance, correctness first. Style later.
Approval Means "Ship It"
Don't approve if you have significant concerns.

For Teams

Establish Clear Guidelines
Document PR expectations, review timelines, merge rules.
Use Templates & Automation
Standardize processes to reduce friction.
Regularly Retrospect
Discuss what's working/not working in PR process.
Celebrate Good PRs
Recognize well-written PRs and thorough reviews.

Frequently Asked Questions

How small should a pull request be?

The ideal PR size is small enough to review in 30-60 minutes. Here's a practical guide:

Size Lines of Code Review Time When to Use
Small 1-100 lines 5-30 minutes Bug fixes, small features, documentation
Medium 100-300 lines 30-90 minutes Typical feature implementation
Large 300-500 lines 1-2 hours Complex features, refactoring
Too Large 500+ lines 2+ hours Should be split into multiple PRs

The "Soccer Ball Test": Imagine explaining your changes while kicking a soccer ball back and forth with a teammate. Could you explain it completely before getting tired? If not, it's too big.

Signs your PR is too large:

  • Reviewers take days to respond
  • Comments focus on different aspects (architecture, style, bugs)
  • You're making changes in multiple unrelated areas
  • You can't describe the change in one sentence

How to split large changes:

  1. Architecture-first: Submit API/interface changes first
  2. Feature flags: Hide incomplete features behind flags
  3. Horizontal slices: Build foundation, then layers
  4. Extract refactoring: Separate refactoring from new features
# Example: Splitting a large authentication feature
# PR 1: Database schema and models
git checkout -b auth/schema
# PR 2: Authentication middleware
git checkout -b auth/middleware
# PR 3: Login/register endpoints
git checkout -b auth/endpoints
# PR 4: Frontend components
git checkout -b auth/frontend
How do I write a good pull request description?

A good PR description saves reviewers time and helps them understand your changes quickly. Think of it as a mini-documentation for your code change.

# Excellent PR Description Template

## 🎯 What does this PR do?
Adds dark mode support to the application. Users can now toggle between light and dark themes.

## 🔗 Related Issues
Fixes #123 (Dark mode feature request)
Related to #456 (Accessibility improvements)

## 📋 Changes Made
- Added ThemeContext for state management
- Created dark/light CSS variables
- Updated header component with theme toggle
- Modified 5 components to use CSS variables
- Added localStorage persistence

## 🧪 Testing
- [x] Manual testing: toggle works in all browsers
- [x] Unit tests: ThemeContext tests added
- [x] Accessibility: contrast ratios meet WCAG AA
- [x] Performance: no significant bundle size increase

## 📸 Screenshots
| Light Mode | Dark Mode |
|------------|-----------|
| ![Light](url) | ![Dark](url) |

## 🚨 Breaking Changes
None - backward compatible

## 📝 Notes for Reviewers
- Focus on CSS variable naming convention
- Check contrast ratios in dark mode
- Test localStorage behavior

What makes this description good:

  • Clear purpose: Immediately tells what the PR does
  • Context: Links to related issues for background
  • Scannable: Uses bullet points and clear sections
  • Actionable: Tells reviewers what to focus on
  • Complete: Includes testing, screenshots, notes

Common mistakes to avoid:

# ❌ Bad examples:
# Too vague:
"Update files"

# No context:
"Fix bug"

# Just the ticket number:
"JIRA-1234"

# Too technical without explanation:
"Refactor useEffect dependencies"

Pro tips:

  • Write the description for your future self (you'll forget details)
  • Include before/after screenshots for UI changes
  • Mention any trade-offs or decisions made
  • Update the description if the PR changes significantly
  • Use emojis sparingly for visual scannability
What's the difference between squash merge and regular merge?

Understanding merge strategies is crucial for maintaining a clean Git history. Here's a detailed comparison:

Aspect Regular Merge (Merge Commit) Squash Merge Rebase & Merge
Git History Shows all individual commits with merge commit Single commit representing all changes Linear history, commits appear in sequence
Commit Messages Preserves all original commit messages Creates new commit message (often PR title) Preserves original commit messages
Review History Individual commits remain visible Loses individual commit history Individual commits remain visible
Reverting Revert merge commit to undo all changes Revert single squash commit Revert individual commits or range
Best For Collaborative features with multiple contributors Cleaning up "work in progress" commits Maintaining linear project history

Visual comparison of Git history:

# Regular Merge History
* e4f2d1a (HEAD -> main) Merge pull request #123
|\
| * 8c3f2b1 (feature/branch) Add validation
| * 5a1b3c2 Fix bug in form
| * 2d4e5f6 Initial feature implementation
|/
* 9a8b7c6 Previous commit on main

# Squash Merge History
* e4f2d1a (HEAD -> main) Add user authentication feature
* 9a8b7c6 Previous commit on main

# Rebase & Merge History
* e4f2d1a (HEAD -> main) Add validation
* 5a1b3c2 Fix bug in form
* 2d4e5f6 Initial feature implementation
* 9a8b7c6 Previous commit on main

When to use each:

Use Regular Merge When:

  • Multiple people contributed to the feature
  • You want to preserve the detailed development history
  • Individual commits tell a meaningful story
  • You might need to revert or cherry-pick specific commits later

Use Squash Merge When:

  • The PR contains many "WIP" or "fix typo" commits
  • You want a clean, high-level project history
  • The feature is a single logical unit
  • Individual commit messages aren't important

Use Rebase & Merge When:

  • You want a perfectly linear history
  • The feature branch was kept up-to-date with rebases
  • You're working on a library or open-source project
  • You want commits to appear in chronological order

Team strategy recommendation: Choose one primary strategy for your team and document it. Many teams use squash merge for feature branches but regular merge for release branches.

How do I handle a pull request that needs major changes?

Sometimes a PR needs significant rework. How you handle this situation impacts team morale and productivity.

Don't do this: "This is all wrong. Start over." This is demoralizing and unhelpful.

Better approach - The "Architecture Review" method:

# 1. Schedule a quick call (15-30 minutes)
# Message: "Can we hop on a quick call to discuss architecture?"

# 2. Discuss the approach, not the code
# Focus on:
# - What problem are we solving?
# - What are the constraints?
# - What alternatives exist?

# 3. Create an action plan together
# Document decisions in PR comments

Specific scenarios and solutions:

  1. PR implements wrong solution:
    # Comment template:
    "Thanks for working on this! I think we might be solving different problems here.
    The issue (#123) is about X, but this solution addresses Y.
    Let's discuss: Should we solve X first, or is Y actually the priority?"
  2. PR violates architecture patterns:
    # Comment template:
    "I notice this uses approach A, but our pattern for this is B.
    Here's the documentation on pattern B: [link]
    Would you like to pair on converting this to use pattern B?"
  3. PR is too complex for the problem:
    # Comment template:
    "This looks comprehensive! For this specific issue (#123),
    I wonder if we could use a simpler solution like [suggestion].
    What do you think about trying this simpler approach first?"
  4. PR introduces new dependencies without discussion:
    # Comment template:
    "I see you've added [library]. Before we add new dependencies,
    we usually discuss in our weekly tech meeting.
    Could you present this library choice at the next meeting?"

When to suggest starting over:

  • The approach is fundamentally flawed
  • It would take more time to fix than rewrite
  • Multiple major issues exist (architecture, security, performance)
  • Always pair with the author if suggesting a rewrite

Prevention is better than cure:

# Implement early feedback mechanisms
# 1. Draft PRs for architecture feedback
gh pr create --draft

# 2. Design documents for complex features
# 3. Pair programming for critical components
# 4. Small proof-of-concept PRs first
How do I manage pull requests in a large team/organization?

Scaling PR processes for large teams requires structure and tooling. Here's a comprehensive guide:

Large Team PR Workflow
Multiple teams, complex dependencies

1. Organizational Structure

# Team-based CODEOWNERS file
# .github/CODEOWNERS
* @org/team-leads

/frontend/ @org/frontend-team
/backend/ @org/backend-team
/infrastructure/ @org/devops-team

# Require specific reviewers for sensitive areas
/security/ @org/security-team
/database/ @org/database-team

2. Automated Workflows

# .github/workflows/pr-checks.yml
name: PR Quality Gates
on: [pull_request]

jobs:
  checks:
    runs-on: ubuntu-latest
    steps:
      - name: Required checks
        run: |
          # 1. Size check
          if [ $(git diff --stat origin/main | wc -l) -gt 500 ]; then
            echo "PR too large (>500 lines). Please split."
            exit 1
          fi
          # 2. Ticket link check
          # 3. Description length check

3. PR Triage Process

Role Responsibilities Tools
PR Author Create PR, request reviews, address feedback GitHub CLI, draft PRs
Primary Reviewer Technical review, approve/reject Code review tools, testing environments
Secondary Reviewer Spot check, different perspective Quick scan, focus on specific areas
Merge Master Final check, merge, branch cleanup Merge queue, conflict resolution

4. Scalable Review Strategies

Staggered Reviews

Different reviewers focus on different aspects:

  • Reviewer 1: Architecture & design
  • Reviewer 2: Code quality & patterns
  • Reviewer 3: Testing & edge cases
  • Reviewer 4: Documentation & UX

Scheduled Review Times

Establish team review windows:

# Team schedule
Morning: 9-10 AM - Deep work
After lunch: 1-2 PM - PR reviews
EOD: 4-5 PM - Quick reviews & planning

5. Metrics & Continuous Improvement

# Track key metrics
- Average PR size (lines)
- Average review time (hours)
- PRs merged vs abandoned
- Review comments per PR
- Time from PR to production

# Regular retrospectives
- What's working in our PR process?
- What's slowing us down?
- How can we improve code quality?
- Are reviews timely and helpful?

6. Cross-Team Coordination

# For PRs affecting multiple teams
# 1. Create RFC (Request for Comments) first
# 2. Get alignment before implementation
# 3. Use feature flags for gradual rollout
# 4. Schedule coordination meetings

# Example: Database schema change
1. RFC shared with all teams
2. Feedback collected for 2 days
3. Implementation in backward-compatible way
4. Rollout planned with all teams

Recommended tools for large teams:

  • GitHub Enterprise/GitLab Premium: Advanced PR features
  • LinearB/GitPrime: Engineering metrics and insights
  • SonarQube/CodeClimate: Automated code quality checks
  • LaunchDarkly: Feature flag management
  • Jira/Linear: Ticket and PR integration
Previous: Working with Remotes Next: Git Hooks