Pull Request Standards
The quality of a pull request directly determines the quality of the review it receives. A well-structured PR with a clear title, detailed description, and a focused set of changes invites a thorough, thoughtful review. A massive PR with a vague title and no description invites a cursory "LGTM" and a rubber stamp. Establishing pull request standards is one of the highest-leverage improvements a team can make to their code review process.
Pull request standards are not about bureaucracy. They are about communication. A PR is a message from the author to the reviewer, and like any good communication, it should be clear, complete, and respectful of the reader's time. The standards in this lesson will help your team write PRs that reviewers can understand quickly and review effectively.
Keep PRs Small
The single most impactful standard you can adopt is keeping pull requests small. Research from SmartBear, Google, and Microsoft consistently shows that review effectiveness drops dramatically as PR size increases. The ideal pull request is between 200 and 400 lines of code changed. Beyond that threshold, reviewers miss more bugs, provide less useful feedback, and take longer to complete their review.
Why does size matter so much? Small PRs are easier to understand because the reviewer can hold the entire change in their head at once. They are faster to review because there is less to read and reason about. They are less likely to cause merge conflicts because they touch fewer files and are merged sooner. They are easier to revert if something goes wrong because the change is isolated. And they are easier to bisect when tracking down a regression because each commit represents a small, focused change.
If you find yourself with a PR that exceeds 400 lines, consider whether it can be split. Common strategies include:
- Refactoring first: If your feature requires refactoring existing code, submit the refactoring as a separate PR before the feature itself. This lets reviewers verify that the refactoring preserves existing behavior before evaluating the new functionality.
- Backend then frontend: For full-stack changes, submit the API or database changes first, then the UI changes in a follow-up PR. This naturally divides the work along architectural boundaries that are easier to review independently.
- Horizontal slicing: Break a large feature into independently shippable increments. For example, if you are building a user profile page, you might first PR the profile data model, then the API endpoint, then the basic UI, then the edit functionality. Each PR is small, focused, and delivers value.
- Feature flags: Use feature flags to merge incomplete features behind a toggle. This allows you to submit small, incremental PRs that build toward a larger feature without exposing unfinished work to users.
Descriptive Titles and Descriptions
Every pull request needs a clear, descriptive title that summarizes what the change does and why. The title is the first thing a reviewer sees, and it sets the context for the entire review. A good title answers the question "What does this PR do?" in one line.
Effective PR titles follow a consistent format:
- Start with a verb: "Add user authentication middleware," "Fix race condition in cart checkout," "Refactor payment processing to use strategy pattern."
- Be specific: "Fix bug" tells the reviewer nothing. "Fix null pointer exception when user has no shipping address" tells them exactly what to expect.
- Include the scope: If your project is large, prefix the title with the area of the codebase affected: "[Auth] Add rate limiting to login endpoint" or "[Cart] Fix subtotal calculation for discounted items."
The PR description should provide the context that the title cannot. A good description includes:
- What changed: A brief summary of the technical changes in the PR. What files were modified? What new components were added? What was removed?
- Why it changed: The motivation behind the change. Was it a bug fix? A feature request? A performance improvement? A security patch? Link to the relevant issue, ticket, or discussion.
- How to test: Instructions for how a reviewer can verify that the change works as intended. This might include specific test cases to run, URLs to visit, or steps to reproduce the original bug.
- Screenshots or recordings: For UI changes, include before-and-after screenshots or a screen recording that demonstrates the visual change. This saves reviewers time and eliminates ambiguity about what the change looks like.
- Anything unusual: If the PR includes a workaround, a temporary hack, a known limitation, or a decision that might surprise reviewers, explain it upfront. This prevents unnecessary back-and-forth and shows that you have thought carefully about the trade-offs.
PR Templates
The best way to ensure consistent PR descriptions is to use a pull request template. GitHub supports PR templates through a file at .github/PULL_REQUEST_TEMPLATE.md in your repository. When a developer opens a new PR, the template is automatically populated in the description field, providing a structured format to fill in.
A good PR template includes sections for the key information reviewers need without being so long that developers skip it. Here is an example structure:
- Summary: A brief description of what changed and why.
- Related issues: Links to relevant issues or tickets (e.g., "Closes #123").
- Changes: A bullet-point list of the specific changes made.
- How to test: Steps to verify the change works correctly.
- Screenshots: Before-and-after images for UI changes.
- Checklist: A checkbox list of items the author should verify before requesting review (tests pass, documentation updated, accessibility checked).
The template should be a guide, not a burden. If a particular section does not apply to a given PR, the author should remove it rather than filling it with "N/A." The goal is to provide useful information to the reviewer, not to check boxes.
Draft PRs for Early Feedback
GitHub's draft pull request feature is an underused tool for improving code quality. A draft PR signals that the work is not yet ready for formal review but that the author wants early feedback on their approach. This is particularly valuable for:
- Large features: Open a draft PR early to get feedback on your overall approach before investing hours in implementation details that might need to change.
- Unfamiliar territory: If you are working in an area of the codebase you do not know well, a draft PR lets a more experienced team member confirm that you are on the right track.
- Experimental approaches: When you are trying a new pattern, library, or architecture, a draft PR lets the team weigh in before you commit to the approach.
Draft PRs reduce wasted work by catching fundamental issues early, when they are cheap to fix. They also make formal review faster because the reviewer has already seen the high-level approach and can focus on details.
Self-Review Before Requesting Review
Before requesting review from others, review your own PR. Read through the diff as if you were a reviewer seeing it for the first time. This simple practice catches a surprising number of issues: debug logging you forgot to remove, commented-out code, missing tests, typos in variable names, incomplete error handling, and temporary hacks that should be cleaned up.
Self-review also shows respect for your reviewers' time. When a reviewer encounters obvious issues that the author could have caught themselves, it signals that the author did not invest time in preparing the PR for review. This can erode trust and make reviewers less willing to invest their own time in thoughtful feedback.
A useful self-review checklist includes: Does the PR do only what its title says? Are there any unnecessary changes (formatting, imports, unrelated refactoring)? Do all tests pass? Is the description complete? Would I be able to review this if I did not write it?
Screenshots and Recordings for UI Changes
For any PR that modifies the user interface, include visual evidence of the change. A screenshot or screen recording communicates the result of the change instantly and unambiguously. It also serves as documentation of what the UI looked like at this point in time, which can be valuable for tracking design evolution.
Include both "before" and "after" screenshots when the PR modifies existing UI. For new features, include screenshots of the new UI in different states (empty state, loading state, error state, populated state). For responsive changes, include screenshots at different viewport widths. For accessibility-related changes, include screenshots of the screen reader output or keyboard focus indicators.
Linking to Issues and Tickets
Every PR should link to the issue, ticket, or discussion that motivated it. This connection creates a traceable chain from requirement to implementation that is invaluable for understanding why a change was made, even months or years later. GitHub supports automatic issue closing with keywords like "Closes #123" or "Fixes #456" in the PR description.
If a PR addresses part of a larger issue, note that explicitly: "This PR implements the database schema changes for #123. The API endpoints will follow in a separate PR." This helps reviewers understand the scope and prevents confusion about whether the work is complete.
Required Reviewers and CODEOWNERS
GitHub's CODEOWNERS file allows you to automatically assign reviewers based on which files a PR modifies. A CODEOWNERS file maps file patterns to GitHub usernames or teams, ensuring that the right people are notified when their areas of expertise are affected.
For example, you might configure the CODEOWNERS file so that changes to the authentication module always require review from the security team, changes to the database schema always require review from the DBA, and changes to the CI/CD pipeline always require review from the platform team. This ensures that specialized knowledge is applied where it matters most.
CODEOWNERS works best when combined with branch protection rules that require approval from the designated owners before a PR can be merged. This creates a safety net that prevents changes to critical parts of the codebase from being merged without appropriate review.
Squash vs Merge Commits
How you merge pull requests affects the readability of your Git history. There are three common strategies, each with trade-offs:
- Squash and merge: Combines all commits in the PR into a single commit on the target branch. This creates a clean, linear history where each commit represents a complete, reviewed change. It is the best choice for most teams because it makes the history easy to read, easy to bisect, and easy to revert.
- Merge commit: Creates a merge commit that preserves the individual commits from the PR branch. This preserves the detailed history of how the change was developed but can make the main branch history harder to follow, especially with many concurrent PRs.
- Rebase and merge: Replays the individual commits from the PR branch onto the target branch without a merge commit. This creates a linear history but preserves individual commits. It requires that the author keep their commits clean and well-organized.
Most teams benefit from squash and merge as the default strategy, with the PR title and description serving as the commit message. This ensures that the main branch has a clean, descriptive history regardless of how messy the development process was.
Branch Naming Conventions
Consistent branch naming makes it easier to understand what a branch contains and how it relates to your project management workflow. A common convention is:
feature/short-descriptionfor new featuresfix/short-descriptionfor bug fixesrefactor/short-descriptionfor refactoringdocs/short-descriptionfor documentation changeschore/short-descriptionfor maintenance tasks
Some teams include the ticket number in the branch name (e.g., feature/PROJ-123-user-authentication) to create a direct link between the branch, the PR, and the project management tool. This makes it easy to trace work from a Jira ticket or GitHub issue to the specific code changes that implemented it.
Whatever convention you choose, document it and enforce it consistently. Automation can help: Git hooks or CI checks can validate branch names against your convention and reject non-conforming branches.
Resources
- GitHub Pull Requests Documentation — Official documentation on creating, reviewing, and managing pull requests on GitHub
- Atlassian: The Written and Unwritten Guide to Pull Requests — Best practices for creating effective pull requests