Stacked PRs – Pros and Cons?
I've been doing a bit of reading about "stacked pull requests". The two major benefits that people seem to like are: it reduces the size of PRs which is a very good thing, it allows devs to keep working while things are in review (rather than waiting for it to be reviewed before continuing.
Have seen a bit of conversation on HN about stacked PRs, curious about people's experience with it? Pros and cons?
8 comments
[ 0.33 ms ] story [ 36.9 ms ] threadThe advantage is so nice. You can make a bunch of finer-grained PRs that have really good descriptions for what happened, what's changing. And it builds a big PR that has the top-down view. It creates a very understandable hierarchy of understanding. And it shows work over time.
Edit: apologies... maybe this is also Stacked PRs? I think of Stacked PRs as a series of PRs into main. But I see posts like this which show PRs into PRs, which is what I'm describing above. https://benjamincongdon.me/blog/2022/07/17/In-Praise-of-Stac...
It's local stacked PRs and you can jump between them to edit as the ideas evolve.
https://stacked-git.github.io/
But if the nearby code is evolving quickly from other people this can be a bad approach because of merge hell when the work is finally submitted.
You've covered the major pros at a high level, but I think the details matter. For example "smaller PR" is a rather high-level pro which is true. But it's not just that PRs are smaller, but that they can be ordered to build functionality as a story and justify each change. This is much like how the Linux Kernel wants patch series and not just a single big patch. I find this helps make reviewing easier and faster. It can also help clarify some people's thinking.
Similarly, "keep working" is a high level truth, but it has important organizational consequences. For example, if there is no rush to merge things it means the entire team doesn't need to be interrupted several times a day to merge something. It also mean it's OK to open a deep discussion on something in the MR. I find both these make the team as a whole more productive because they can take the time to think. For example, I push my team to only do reviews once a day so they don't need to context switch and it gives discussions time for well thought out replies instead of rushed single-sentence responses.
There are some cons which are by no means insurmountable, but aren't free to solve.
The biggest one is teaching everybody on the team how to use cascaded MRs in a technical sense. The details depend on how you implement them, but I prefer cascaded branches with full merge commits. Tooling can help, but if they don't understand the underlying mechanics there will undoubtedly be problems where people can't get the review to look like what they want.
Secondary to this is teaching what a good patch series looks like and how to use the VCS to create it. Each PR really needs to pass CI on its own, which requires ordering code changes in a particular way which is opposite the order they were mostly likely implemented. For example, while working on something you'll probably notice a bug or refactor which needs to be done, but you only notice it mid-way through the work. So you want to move the refactor/fix to before the main work in the series. There are different ways to do this with different trade-offs and developers need to understand how and when to use them.
Finally, the biggest problem I've seen with stacked PRs is difficulty bringing in changes from master or whatever the parent is. With a single PR this is an easy merge/rebase. With a long series of these it's a repetitive series of merges (my preference) or rebases. Doing this manually is annoying and writing automation for it requires formalizing branch (or whatever) parent-child relationships. This isn't terribly difficult, but ideally the command line and IDE and repository viewer and code review software all agree on it, which is a bunch of tedious work.
Suppose you have the stacked PRs in the following sequence: A, B, C, D, E, F
If you implement stacked PRs using branches in git, then they will be a series of branches. For example, A will be a child branch of master, and B a child of A. To bring new changes in from master all the way down to F requires at least three commands and a build per stack member:
Failure to do this for every PR in the stack tends to create confusing diffs in the code review system. For example, if you only merged the changes from master as far as C, then the code review system will probably try to show the diff between D and C:head which will contain the removal of a bunch of new master code. The code review really should be showing the diff between D and C:d_merge_base, but some code review tools don't support that and others need help, like the wrapper tool I mentioned previously.