Move faster with Stacking PRs 🚀
Tags: programming, tutorial, webdev, github
Published: 2023-10-12 00:15:37

Working with large pull requests can become difficult for both the original developer and the wider team. When working on a feature branch that's thousands of lines long, keeping track of all your changes and how they affect each other is no easy task. The same goes for the reviewer, it can be a nightmare sifting through large PRs, praying you don't miss the cause of the next prod outage.

Just split the large feature into smaller features, right? But what if multiple developers are working on the same large feature? If one devs work depends on another, must they wait for the other's PR to pass review before working on their task?

Stacking PRs seeks to resolve this problem, whilst also solving many more.

## What is Stacking

Stacked Pull Requests (PRs), a.k.a. dependent, incremental or chained PRs, are PRs that branch off from other PRs.

This workflow can be used in your personal projects or with a team of developers to help move faster and with more conviction.

## Benefits of Stacking

The idea behind stacking is to build small coherent units, in our case PRs, to make conceptualising these changes easier.

This helps the developer as well as the reviewer for a few reasons:
  - Atomising your changes like this results in simpler PRs, reducing the risk of the developer burning out
  - Simpler PRs also reduce review time, speeding up a Team's workflow
  - Less code means less rebase conflicts. Stacked PRs spend less time in the review process than 'traditional' PRs
  - If something goes wrong, and a revert is necessary, there are less cascading side effects because there's simply less code

It also helps multiple developers work code that depends on the same feature. The devs don't have to wait for a feature to be reviewed or merged, they can just **stack** on top of it.

## Drawbacks of Stacking

There aren't many drawbacks to stacking; however, it is worth noting that the act of splitting up a large feature can be quite time-consuming.

Knowing when a feature is *small* enough to be a stack is sometimes difficult to decide. As you use Stacking PRs more, you begin to get a feel of what should be its own PR.

Another drawback is that it isn't widely adopted yet, and can be confusing to other team members if you use Stacking PRs and they do not.

## Stacking Example

Let us consider a real-world example. An engineer, say Alice, is asked to migrate his company's React frontend to TypeScript. We can imagine this task requires 3 features:

- Initialising TypeScript
  - Install TS with your preferred package manager
  - Configuration (tsconfig, linting etc.)
- Migrate Components
- Migrate Pages

Alice begins by creating a branch called `ts-init` from `main`. She commits her changes and creates a **PR** and requests a review.

![stacking example #1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q902ze601eklhyyvhrst.png)

Now, Alice would like to begin migrating the components to TS. Traditionally, one might wait for the `ts-init` PR to be reviewed and merged to main before beginning a dependant feature, but with stacking, this is not the case.

Instead, Alice creates another branch called `components-migration` from `ts-init`. She commits her changes and creates a **PR** and requests a review as before.

![stacking example #2](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/abrsjlgx7ykc642mj64o.png)

Here's where it gets interesting. Another engineer, say Bob, is assigned to migrate the pages. To accomplish this, he can simply create a branch `pages-migration` from `ts-init`, and both Alice and Bob work on their respective changes simultaneously. 

![stacking example #3](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vgh90nk2uk4z939k7dj3.png)

If, however, `pages-migration` was dependent on changes in `components-migration`, then we could inform Bob to work on something else whilst Alice finishes migrating the components. There is still the benefit that Bob could work on migrating the pages while `components-migration` and even `ts-init` are still in review.

![stacking example #4](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gc4lwmh0m27ipxdzxh9b.png)

Finally, the engineers must safely merge these feature PRs with `main`. The order by which each branch is merged is solely dependent on the order of creation, that is to say `ts-init` must merge with `main` first, followed by `components-migration` and finally `pages-migration`.

![stacking example #5](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dbhhcd5ulktxi0fu39us.png)

To reduce clutter, you might prefer this feature to read as one merge with `main`, then you could merge `components-migration` with `ts-init`, then `components-pages` and finally merge `ts-init` with `main`.

![stacking example #6](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/astfsckstq2h62v034yr.png)

## How to stack an existing PR

There are a few different ways to convert an existing large PR into a stack of PRs, but I feel that this way is the easiest to conceptualise and track:

1. Unstage previous commits so that you can reassign them to different PRs. You can achieve this by:
  - checkout the current PR's feature branch
  - soft reset main
  - restore all staged commits
  
```console
$ git checkout large-feature-branch
$ git reset --soft main
$ git restore --staged .
```

2. You should rename the branch to indicate what your initial feature PR will be:

```console
$ git branch -M initial-feature
```

3. Proceed to commit your initial changes and open up a new PR
4. Create a branch from `initial-feauture` and repeat 3-4 until there are no changes left

You've now split up a large, review nightmare of a PR into small PRs that will benefit all involved!

## Conclusion

Overall, stacked PRs are a great way to break up large features into concise, ingestible PRs that will make your life easier as well as your peers'.

The process can be daunting at first, but the benefits make it all worthwhile. Though there are tools available to help with Stacking your PRs (such as [Graphite](https://graphite.dev/)) which are full of great features, I would recommend giving Stacking a go without tooling first. This will help you get a good grasp of the concept and begin to understand where the benefits come from.