DEV Community

Cover image for Breaking a long PR into multiple smaller PRs
Jyothi Swaroop
Jyothi Swaroop

Posted on

Breaking a long PR into multiple smaller PRs

Breaking a Long PR into Multiple Smaller PRs: A Practical Guide

Introduction and a bit of context

Recently, I was assigned a task to make some UI changes in our project. One of the subtasks was to update the z-index stacking context in our codebase. Basically, we were using too many variables for stacking contexts, and the logic could be simplified. Fairly simple, right?

The only thing is, this would mean making changes throughout the codebase. Any component using fixed z-index values (like z-50) would have to be updated (for example, with z-dialog, z-overlay). So, a lot of small changes in many files. This resulted in a total of 34 files changed.

Still, fairly manageable for someone to review my pull request. And this is where things started to get messy.

While I went on with my work to make the other UI fixes, I noticed the same problems in a lot of other files as well. And, instead of creating a separate branch off main and implementing the changes there, I made the changes in the same branch itself. A classic rookie mistake. This included moving and deleting quite a few files. Now, in fairness, I made this decision because the succeeding changes depended on the previous ones. While this reasoning made sense at the time, it ultimately made the PR harder to review—which is exactly what this post is about fixing!

When I was finally done with all my changes, I noticed the number of files changed: 74. And 977 lines added and 2814 lines removed!

An image showing 74 files changed and 977 lines updated

The Problem

Usually, leads always advise juniors to raise smaller PRs because:

  • It's simpler to review
  • Easier to revert commits if there are merge conflicts or something needs to be changed/updated
  • Smaller PRs get merged faster, reducing the chances of conflicts

Another rookie mistake I made was not making logical commits. Every task that you work on can be broken down into further sub-tasks. Each commit in the feature should ideally represent each sub-task so that later on it's easier to revert, or, as we'll see, easier to cherry-pick.

The Solution

The solution is simple: Break the pull request into smaller, logical, understandable PRs.

Each commit/sub-task I was talking about? We can create a new branch from main, and then group commits and push them into this branch. Again, we can create another branch from main, take the next group of commits, and then push them. Let's dig a little deeper.

I had 9 commits in the long-pr branch. Say, I figured out that commits #1, #2 need to be in a separate PR, #3, #4 in a separate PR, #5, #6, #7, #8 in a separate PR, and #9 in a separate PR.

Now the question is: will I create these 4 PRs with the base branch as main? What if commits #3, #4, which I decided to put in a separate branch, depended on the code changes introduced in commits #1 and #2?

Understand the problem? There are potentially two roads you can take:

Scenario 1: Independent Commits

If it so happens that your commits are independent of each other, then it's simple: you follow the above steps. Life is good. You create 4 separate branches, and raise PRs to the main branch.

Steps:

  1. Create branch branch-1 from main and cherry-pick commits #1, #2
  2. Create branch branch-2 from main and cherry-pick commits #3, #4
  3. Create branch branch-3 from main and cherry-pick commits #5, #6, #7, #8
  4. Create branch branch-4 from main and cherry-pick commit #9
  5. Raise all 4 PRs to main - they can be merged in any order!

Scenario 2: Dependent Commits (My Case)

Since my commits were dependent on each other, I had two approaches:

Approach 1: Sequential Merging (Safer but Slower)

Create the first PR consisting of the first two commits. Tell my lead to merge it. Once they do that, GitHub will automatically update the diff to show only the changes not yet in main.

Steps:

  1. Create branch branch-1 from main, cherry-pick commits #1, #2, and raise PR to main
  2. Wait for branch-1 to be merged into main
  3. Create branch branch-2 from main (which now has commits #1, #2), cherry-pick commits #3, #4, and raise PR to main
  4. Wait for branch-2 to be merged
  5. Continue this process until all commits are merged

Pro Tip: You can actually simplify this even further! Instead of creating new branches for every group of commits, use your original long-pr branch strategically:

  1. Create branch branch-1 from main, cherry-pick commits #1, #2, raise PR and get it merged
  2. Now, if you look at the long-prmain diff on GitHub, it will automatically exclude commits #1, #2 and only show commits #3-#9!
  3. Create branch branch-2 from main, cherry-pick commits #3,#4, raise PR and get it merged
  4. The long-prmain diff now shows only commits #5-#9
  5. Create branch branch-3 from main, cherry-pick commits #5, #6, #7, #8, raise PR and get it merged
  6. The long-prmain diff now shows only commit #9!
  7. Now you can directly merge the long-pr branch to main - no need to create a 4th branch! You can follow this approach until you or your lead feels the long-pr branch is small enough now to be reviewed on its own.

This works because GitHub is smart enough to recognize that commits #1-#8 (though still in your long-pr branch) are already in main and won't show them in the diff. Your long-pr branch isn't "long" anymore - it only contains the changes not yet in main!

Pros: Simple, less chance of mistakes, can reuse your original branch

Cons: You have to wait for each PR to be reviewed and merged before proceeding

Approach 2: Stacked PRs (Faster but Requires Careful Management)

You can create all branches upfront without waiting for your lead. This is known as stacking PRs. The advantage is that you don't have to wait - you can send them all your PRs at once for review.

Steps for Creating Stacked PRs:

  1. Create the first branch:
   git checkout main
   git checkout -b branch-1
   git cherry-pick <commit-1> <commit-2>
   git push origin branch-1
Enter fullscreen mode Exit fullscreen mode
  1. Create the second branch from the first:
   git checkout branch-1
   git checkout -b branch-2
   git cherry-pick <commit-3> <commit-4>
   git push origin branch-2
Enter fullscreen mode Exit fullscreen mode
  1. Create the third branch from the second:
   git checkout branch-2
   git checkout -b branch-3
   git cherry-pick <commit-5> <commit-6> <commit-7> <commit-8>
   git push origin branch-3
Enter fullscreen mode Exit fullscreen mode
  1. Create the fourth branch from the third:
   git checkout branch-3
   git checkout -b branch-4
   git cherry-pick <commit-9>
   git push origin branch-4
Enter fullscreen mode Exit fullscreen mode

Creating the Pull Requests:

  • PR1: branch-1main
  • PR2: branch-2branch-1 (base is branch-1, not main!)
  • PR3: branch-3branch-2 (base is branch-2, not main!)
  • PR4: branch-4branch-3 (base is branch-3, not main!)

This way, each PR only shows the diff for its specific commits, making them easy to review.

Merging Stacked PRs (CRITICAL STEPS):

Here's the correct way to merge stacked PRs:

  1. First, get PR1 reviewed and merged into main

  2. Then, for PR2:

    • Go to PR2 on GitHub
    • Click "Edit" next to the base branch
    • Change the base from branch-1 to main
    • GitHub will automatically update the diff to show only commits 3,4
    • Get it reviewed and merge into main
  3. Then, for PR3:

    • Change the base from branch-2 to main
    • Get it reviewed and merge into main
  4. Finally, for PR4:

    • Change the base from branch-3 to main
    • Get it reviewed and merge into main

Important: You must merge them in order. If you try to merge out of order, you'll get duplicate commits or conflicts.

Why this works:

  • Each PR contains only its relevant changes when reviewed
  • By changing the base branch after each merge, GitHub automatically removes the already-merged commits from the diff
  • All changes eventually land in main separately, maintaining clean history
  • Your team can review all PRs in parallel, but they merge sequentially

Alternative Stacked PR Approach (All from Main)

Some teams prefer a slightly different approach:

  1. Create all branches from main:

    • pr1 from main (commits #1, #2)
    • pr2 from main (commits #1, #2, #3, #4)
    • pr3 from main (commits #1, #2, #3, #4,#5, #6, #7, #8)
    • pr4 from main (commits #1, #2, #3, #4, #5, #6, #7, #8, #9)
  2. Raise all PRs to main

  3. Merge them sequentially: pr1→main, then pr2→main, etc.

This approach is simpler but requires more rebasing as you go.

Pro Tips

  1. Communicate with your team: Let your reviewers know these PRs are stacked and should be merged in order.

  2. Keep the stack shallow: Try to limit stacks to 3-4 PRs max. Beyond that, it gets hard to manage.

  3. Make logical commits from the start: This makes splitting PRs much easier. Each commit should represent one logical change.

Conclusion

Breaking a large PR into smaller ones might seem like extra work, but it pays dividends in:

  • Faster review cycles
  • Easier debugging when something goes wrong
  • Better collaboration with your team
  • Cleaner git history

The next time you find yourself with a 74-file PR, remember: it's never too late to split it up. Your reviewers (and your future self) will thank you!


Have you dealt with massive PRs before? What strategies worked for you? Let me know in the comments!

Top comments (0)