Table of contents
Pull requests (PRs) are integral to modern software development, particularly in collaborative environments. Whether you're working on a private team or contributing to open-source projects, writing a high-quality PR is essential to ensure your changes are merged efficiently and correctly. A well-crafted PR is not just about the code—it’s about communication, clarity, and context. The goal of a PR is to make it easy for reviewers to understand what you’re doing, why you’re doing it, and how they can provide effective feedback.
In this detailed guide, we’ll cover best practices for writing high-quality pull requests. We’ll dive into essential elements like writing clear and concise commit messages, structuring your PR description, linking to relevant issues, and handling feedback efficiently. Along the way, we’ll include real-world examples, additional tips, and advice on how to improve your PR writing over time.
Why a High-Quality PR Matters
Before diving into specifics, it’s worth understanding why writing a high-quality PR is crucial.
Faster Review Process: A well-structured PR allows reviewers to quickly understand the purpose and impact of your changes, speeding up the review cycle.
Improved Collaboration: PRs facilitate communication between developers. By making your changes clear and easy to understand, you reduce the friction in discussions and make collaboration more efficient.
Maintainability: A good PR helps maintain the integrity of the codebase. If future developers need to understand the rationale behind changes, your well-documented PR can serve as a reference point.
Reduces Review Fatigue: Reviewers often look at multiple PRs in a day. By presenting your changes clearly and concisely, you reduce the cognitive load on them, leading to more focused and productive reviews.
1. Writing Clear and Concise Commit Messages
Commit messages are like the fingerprints of your codebase. Every time you make a change, a commit message is added to the repository's history. Clear commit messages not only help your peers but also future contributors, including yourself, when you need to revisit older code. Poor commit messages make it difficult to track what has changed and why.
Best Practices for Commit Messages
Use the Imperative Mood: This is a widely accepted convention in Git commit messages. It’s akin to writing commands. For example, instead of writing “Fixed bug in login,” write “Fix bug in login.”
Keep the First Line Short (50–72 characters): The first line of your commit message should provide a summary of the change. Keep it short and concise, ideally under 72 characters. This is because many tools truncate commit messages in their UI, and it improves readability in the commit history.
Provide Context in the Body: If a commit warrants more explanation (especially for complex changes), use the second paragraph of the commit message to explain why the change was necessary or how you solved a specific problem.
Focus on Atomic Commits: Commit small, logical changes rather than lumping multiple unrelated changes into a single commit. Each commit should have a single purpose. This makes it easier to revert or understand specific changes in isolation.
Reference Related Issues or PRs: If your commit is related to a specific issue or another PR, include that reference using keywords like "Closes" or "Fixes." This creates an automatic link between your commit and the issue, allowing GitHub or GitLab to close the issue when the PR is merged.
Example of a Good Commit Message
fix: Correct null pointer exception in UserService
The null pointer exception was caused by an uninitialized variable in
the user login process. This commit adds proper null checks and
initializes the variable to avoid crashing the application.
Closes #457
Example of a Bad Commit Message
misc changes
This message is vague and provides no context, making it hard to determine what changes were made and why. Such messages complicate debugging and maintaining the code in the long run.
2. Structuring a PR Description: What, Why, and How
One of the most critical aspects of writing a high-quality PR is structuring your PR description clearly. A good PR description allows reviewers to quickly understand the nature of the changes and their impact. A structured approach also minimizes misunderstandings and unnecessary review iterations.
2.1. The "What" Section
The "What" section should provide a concise summary of what your PR does. Avoid getting into implementation details here; focus on giving an overview.
What is the purpose of the PR?
What problem does it solve?
What functionality does it add or modify?
Be clear, but avoid verbosity. The aim is to give reviewers a high-level understanding of the change.
2.2. The "Why" Section
The "Why" section is crucial because it explains the reasoning behind the change. Answer the following questions:
Why are these changes necessary?
Why was this approach chosen over alternatives?
Does this PR address a specific bug, feature request, or performance issue?
If there’s any background information or external discussion (e.g., on Slack or in an issue tracker), link to those resources here.
2.3. The "How" Section
Finally, the "How" section provides a more detailed explanation of how you implemented the solution. Here, you can:
Outline architectural decisions and trade-offs.
Explain why you chose one implementation approach over another.
Describe the overall structure of your code changes.
This section is especially helpful for more complex PRs where the reviewer might need a roadmap to navigate the code.
Example of a Well-Structured PR Description
### What
This PR adds pagination to the user listing API. It introduces a new query parameter (`?page=` and `?limit=`) that allows clients to request specific pages of results.
### Why
Currently, the API returns all user records, which can lead to performance issues when there are a large number of users. Paginating the results will improve performance and reduce load on the server. See issue #567 for more background on this performance problem.
### How
- Modified the `UserController` to accept page and limit parameters.
- Updated the database query to include offset and limit clauses.
- Added unit tests for the pagination functionality.
- Updated API documentation to reflect the new query parameters.
### Related Issues
Closes #567, relates to #452
This PR description follows the "What, Why, and How" format, providing enough detail for the reviewer to understand the problem, the solution, and the approach without needing to dive into the code immediately.
3. Linking to Relevant Issues or Discussions
Context is crucial in collaborative software development. As developers work on different parts of the codebase, it’s easy for someone reviewing your PR to miss the bigger picture unless you provide them with enough context. That’s why linking to relevant issues, previous PRs, and discussions is so important.
Best Practices for Linking
Link to Related Issues: If your PR fixes or addresses a specific issue, make sure to reference that issue number. For example, "Closes #123" will automatically close the issue when the PR is merged.
Reference Previous PRs: If your PR builds on a previous PR or is part of a series of incremental changes, include references to those earlier PRs.
Include Links to External Discussions: Sometimes, the rationale behind a PR comes from conversations that happened outside of the codebase (e.g., on Slack, in a design document, or during a meeting). If those discussions provide critical context, link to them or summarize key points in the PR description.
Mention Relevant Documentation: If your PR affects public APIs or modifies functionality that users interact with, provide links to relevant documentation or update the docs within the PR.
Example:
### Related Issues
- Closes #567: Performance issues in user listing API.
- Relates to discussion in [Slack](https://company.slack.com/archives/XYZ123) where we debated several implementation strategies.
4. Best Practices for Managing Feedback and Revisions
Receiving and incorporating feedback is a critical part of the PR process. How you handle feedback can significantly influence how smoothly your PR gets merged. Managing feedback well also helps foster a positive, collaborative environment.
4.1. Acknowledge Feedback Promptly
Even if you can't immediately address feedback, acknowledge it as soon as possible. This shows that you're engaged and working toward resolving the comments. For example:
Reviewer:
I noticed that the validation logic could be simplified by using early returns instead of nested if-statements.
Your Response:
Good point! I will refactor that and push an update soon. Thanks!
4.2. Iterate Incrementally
Avoid rewriting large portions of your PR in response to feedback. Instead, make small, incremental changes that reviewers can follow. If you push multiple commits, the reviewer can focus on specific areas of concern rather than reviewing the entire PR again.
4.3. Use Commit Messages for Revisions
When making revisions based on feedback, make sure your commit messages reflect the changes. This provides a historical record of how the PR evolved during the review process. For example:
refactor: Simplify validation logic
Refactored the user login validation logic to use early returns
as per reviewer feedback. This reduces code complexity and improves readability.
4.4. Mark Resolved Comments
In GitHub and other platforms, you can "resolve" comments once you’ve addressed them. This helps keep the PR clean and allows the reviewer to focus on any remaining, unresolved comments.
4.5. Know When to Push Back
While feedback is valuable, there may be times when you disagree with a reviewer’s suggestion. In such cases, provide a respectful, well-reasoned explanation of your approach. For example:
Reviewer:
I think the new method you added should be moved to a helper class.
Your Response:
I considered that, but this method is specific to the business logic in this service. Moving it to a helper class might lead to code that's harder to maintain. I’d be happy to discuss this further if needed.
5. Additional Best Practices for Writing High-Quality PRs
5.1. Keep PRs Small and Focused
One of the most common mistakes developers make is creating PRs that are too large. A large PR with too many changes is difficult to review and increases the likelihood of introducing bugs. Wherever possible, break your work into smaller, focused PRs that solve one specific problem.
5.2. Add Screenshots or Visuals (if applicable)
If your PR includes UI changes, such as modifying a button or implementing a new page layout, include screenshots or GIFs to show the change in action. This allows reviewers to understand the impact of your changes without having to run the code.
Example:
### Screenshots
**Before:**
![before](url-to-image-before.png)
**After:**
![after](url-to-image-after.png)
5.3. Write Tests
If your changes affect critical functionality, ensure that you’ve written tests to cover them. Mention any new or updated tests in the PR description to show that you’ve considered edge cases and that your code is reliable.
Example:
### Tests
- Added unit tests for the pagination logic in `UserService`.
- Updated integration tests for user listing to include pagination parameters.
5.4. Avoid Force-Pushing During Review
If your PR is under review, avoid using git push --force
. Force-pushing changes the commit history and can confuse reviewers, making it harder to track what has been updated. Instead, add new commits as revisions, which makes it easier for reviewers to see what changed since their last review.
Conclusion
Writing a high-quality pull request is not just about submitting your code—it's about clear communication, context, and collaboration. By following best practices such as writing clear commit messages, structuring your PR with "What, Why, and How," linking to relevant issues, and handling feedback professionally, you can significantly improve the likelihood of your PR being merged smoothly.
Summary of Key Points:
Commit Messages: Keep them clear, concise, and contextual.
PR Description: Follow the "What, Why, and How" format for a structured and comprehensive overview.
Linking: Always provide references to related issues, PRs, or discussions.
Feedback Management: Respond promptly, revise incrementally, and maintain an open, constructive dialogue with reviewers.
By incorporating these practices into your workflow, you'll not only write better PRs but also contribute to a more efficient, collaborative, and maintainable development process.
Happy coding, and may your PRs always get merged!