Navigating the Stack: How to Describe Stacked PRs Effectively
As engineers, we're constantly striving for faster, more reliable code delivery. One powerful technique in our arsenal is the use of "stacked PRs" (sometimes called "stacked branches" or "stacked diffs"). Instead of one giant, monolithic pull request for a new feature, you break it down into a series of smaller, dependent PRs, each building on the previous one.
This approach offers significant advantages: quicker review cycles, easier debugging, isolated changes, and a cleaner main branch. However, it also introduces a unique challenge: how do you effectively describe each individual PR within a stack so that reviewers understand its context, its specific changes, and its role in the larger feature?
What Exactly Are Stacked PRs?
Imagine you're building a complex new feature. Instead of creating a single branch feature/my-big-feature and dumping all your changes into one massive PR, you create a series of smaller, interconnected branches.
For example, if you're implementing a new user notification system, your stack might look like this:
feature/notification-db-schema: Adds the necessary tables and columns to the database.feature/notification-service-core: Implements the core logic for sending notifications, relying on the new database schema.feature/notification-api-endpoints: Exposes API endpoints for interacting with the notification service, relying on the core service.feature/notification-ui-integration: Integrates the new API endpoints into the frontend UI, relying on the API.
Each subsequent branch is based on the previous branch in the stack, not directly on main. When you open a pull request for feature/notification-service-core, its base branch isn't main; it's feature/notification-db-schema.
This methodology allows you to get small, focused changes reviewed and merged incrementally. If feature/notification-db-schema is approved and merged into main, you can then rebase feature/notification-service-core onto main before it's reviewed, keeping your stack clean and up-to-date.
The Unique Challenge of Describing Stacked PRs
While the benefits of stacked PRs are clear, the description process can become surprisingly complex:
- Context is key: Each PR needs to be understood both in isolation and as part of the larger feature.
- Dependency clarity: Reviewers need to know what a PR depends on and what will depend on it.
- Avoiding redundancy: You don't want to re-explain the entire feature in every PR description.
- Maintaining focus: The description for
feature/notification-service-coreshould focus only on the service logic, not the database changes (which are in the base branch) or the API changes (which are yet to come). - Manual overhead: Crafting detailed, accurate descriptions for multiple interdependent PRs can be a tedious, time-consuming task.
Poorly described stacked PRs lead to frustrated reviewers, slower feedback loops, and an increased risk of missed issues.
Best Practices for Describing Individual Stacked PRs
The core principle for describing any PR, especially a stacked one, is to provide just enough information for a reviewer to understand the specific changes in that PR and why they exist.
1. Focus on the Immediate Change
Your PR description should primarily address what this particular diff is doing. If PR #2 in your stack adds an API endpoint, its description shouldn't detail the database migration that happened in PR #1. That's already part of its base branch.
- Summary: A concise, single-sentence summary of the PR's purpose.
- Detailed Explanation: Elaborate on what was changed, why it was changed, and how it achieves its goal.
- Technical Details: Mention any specific algorithms, data structures, or external services involved.
2. Contextualize Within the Stack
While focusing on the immediate change, it's crucial to provide enough context about where this PR fits into the larger feature.
- Parent PR: Clearly state which PR this one builds upon.
- Child PRs (if known): Briefly mention what subsequent PRs will build upon this one, if applicable.
- Overall Goal: A brief reminder of the overarching feature this stack is contributing to.
3. Dependency Clarity
Explicitly call out dependencies. This helps reviewers understand the complete picture and anticipate future changes.
- "This PR depends on #123 (Add user table)."
- "PR #456 (Frontend component) will build upon the API endpoint introduced here."
Example 1: Creating and Describing a Stack
Let's say you're building an EmailService to send welcome emails.
- Start from
main:bash git checkout main git pull origin main - PR 1:
feature/email-service-interface- Adds an
IEmailServiceinterface and a basicEmailServiceclass with aSendWelcomeEmailmethod signature. ```bash git checkout -b feature/email-service-interface
... make changes ...
git commit -m "feat: Add IEmailService interface and basic EmailService" git push origin feature/email-service-interface
`` * **Pull Request Description forfeature/email-service-interface:** * **Summary:** Introduces coreIEmailService` interface and a - Adds an