Many software development methodologies highlight the importance of writing simple, concise and well organized code. While a lot of thought has been put into coding practices, there hasn't been much attention put towards the way in which we present code for review.
Developers might post one big review request (or pull request) that encompasses an entire feature for review. This approach can be problematic for several reasons:
-
Large review requests can be overwhelming for reviewers, leading to slower review times and more waiting on the review requester's end.
-
Having a bunch of changes crammed into one high-level review request puts a heavy cognitive load on the reviewer. They have to understand a substantial amount of new information at once, which can lead to missed issues and lower quality reviews.
A more effective approach is to use Stacked Changes (or Stacked Diffs), a methodology that breaks down complex changes into a series of small, dependent units. Instead of posting one large change for review, you post multiple small ones that stack on top of each other as you progress through your project.
Each change, no matter how minor, has its own review request with a clear description, testing done, and purpose. This makes it easy for others to understand and digest your project, and lets you keep working while waiting for reviews.
Other benefits of stacking include:
- Easier to review: Reviewers are looking at manageable pieces of code, making it easier to spot issues and provide meaningful feedback.
- Faster reviews: You post a change as soon as its ready and start working on the next, which means no time being blocked while waiting for reviews and no need to context switch to another project while waiting.
- Helps you write better code: Stacking forces you to organize your code into clear and distinct pieces, ensuring that each change is logical and self-contained.
- Reduces integration problems: Incremental changes are less likely to introduce significant conflicts or integration issues, making it easier to maintain a stable codebase.
- Improves traceability: Each change is documented and reviewed separately, providing a clear history of what was changed and why, and who reviewed it, which is invaluable for debugging and future maintenance.
Posting and Reviewing Stacked Changes with Review Board
When working on Review Board here at Beanbag, we prefer developing in Stacked Changes. Here's a walk-through of our typical workflow using Git.
1. Create a branch for the first change in the stack
It's best to use one branch to represent one change in the stack. Each branch will have its own review request. We also like to have only one commit per branch to keep things extra simple. But, you're free to create as many commits as you want in one branch, and they will all be shown in the single review request.
Let's create the branch off of main
, make some changes, and commit them.
$ git checkout -b my-branch-1 main
$ <make changes>
$ git commit -a
Your tree now looks like this:
o 81abb90 [my-branch-1]
|
o 81a0a95 [main] [origin/main]
|
.
2. Post the first change for review
We want to post the change for review as soon as its ready, so that it has ample time to be reviewed while you start working on your next change. It's as simple as:
$ rbt post
Review request #1001 posted.
https://reviewboard.example.com/r/1001/
https://reviewboard.example.com/r/1001/diff/
This will create a review request showing the diff between my-branch-1
and main
.
3. Create subsequent branches in the stack
Let's create a branch for your next change, which will be stacked on top of the first change. And this time, you decide to have two commits in the branch.
$ git checkout -b my-branch-2
$ <make changes>
$ git commit -a
$ <make other changes>
$ git commit -a
Now there are two changes in the stack and your tree looks like this:
o 167ba59 [my-branch-2]
|
o a987ee1
|
o 81abb90 [my-branch-1]
|
o 81a0a95 [main] [origin/main]
|
.
You can continue stacking branches like this as needed, always creating the new branch off of the last one.
4. Post stacked changes for review
It's time to post the second change in the stack for review:
$ rbt post --depends-on 1001 my-branch-1..HEAD
Review request #1002 posted.
https://reviewboard.example.com/r/1002/
https://reviewboard.example.com/r/1002/diff/
Passing my-branch-1..HEAD
, or more generally [previous-branch-in-stack]..HEAD
, ensures that only the diff between the previous change in the stack and the current change gets posted to the review request. If we didn't include this, the diff would represent all of the changes between main
and my-branch-2
.
If there's only one commit in your branch, you can run rbt post HEAD
to achieve the same thing. Or if we didn't have my-branch-2
currently checked out, we could have run rbt post my-branch-1..my-branch-2
.
Passing --depends-on 1001
marks this review request as dependent on change 1001
, which was the first one in the stack. When your teammates go to review this change, they'll see that they should review that change first. They'll also be able to see whether that change has been completed already.
Likewise, on the review request for the first change, they'll see that it blocks the second change, meaning that when it comes time to land the changes and push them to main
, this one should land before the second one.
5. Address feedback from reviews
By now you might have some reviews on your first change. Let's make some changes to the commit on my-branch-1
based on review feedback, and post a new diff to the review request:
$ git checkout my-branch-1
$ <address feedback>
$ git commit -a --amend
$ rbt post -u -p -m "Fixed a broken link."
Review request #1001 posted.
https://reviewboard.example.com/r/1001/
https://reviewboard.example.com/r/1001/diff/
-u
updates the existing review request (or you could pass -r 1001
)
-p
publishes the review request
-m
fills out the change description for the update
Instead of amending the original commit, you could also have created any number of new commits.
Sometimes, the requested changes can be quite complex and could cause a lot of merge headaches when updating the next branches in the stack. In that case, its easier to create a new branch at the end of the stack and make your changes starting from there. In your review request description and replies to reviews, you can link to the review request of the new branch. This helps keep a history of how a project evolves, as new requirements and conditions are discovered.
6. Rebase and update stacked changes
We've made updates to the first change in the stack, so now we have to pull these updates into the rest of the changes in the stack. Let's rebase my-branch-2
onto my-branch-1
:
$ git checkout my-branch-2
$ git rebase my-branch-1
While rebasing you may need to deal with some merge conflicts. With Stacked Diffs, you tend to rebase more frequently, but since the changes are small and focused, the merge conflicts are easier to manage compared to rebasing a large branch with a lot of different moving parts in it.
If you have more branches in the stack, you'll have to checkout each branch and repeat the process of rebasing onto the previous one. This can be tedious, so we created a handy script for a git rebase-chain
command that lets you rebase a whole stack of branches in one command. For example, if we had some updates in main
that we wanted to pull into our stack, you can run:
$ git rebase-chain main my-branch-1 my-branch-2
As of Git 2.38, you can also use the --update-refs
option to rebase the whole stack. For example, if we now have 5 stacked branches, and you want to pull the update from my-branch-1
into the 4 other branches, you just need to checkout the last branch in the stack and run the rebase:
$ git checkout my-branch-5
$ git rebase my-branch-1 --update-refs
7. Land your changes
After a few iterations of reviews and updates, you finally get your Ship Its and are ready to land your stack:
$ git checkout main
$ rbt land --dest=main my-branch-1
$ rbt land --dest=main my-branch-2
$ git push
Each branch will be verified for approval before their commits are merged onto main
. The old branches will be deleted after they've landed. rbt land
has a lot of options you can play with.
And that's the workflow for developing in Stacked Changes using Review Board!
If you're not a Git user, Review Board integrates with many other version control systems, including Perforce, Mercurial, Azure DevOps, and Cliosoft SOS. Check out our workflow guides to see how you can follow a similar workflow using your version control system of choice.
TL;DR
Using Stacked Changes with Review Board offers a structured and efficient way to manage code reviews, particularly for complex projects.
By breaking down large changes into smaller, manageable pieces, the review process becomes more streamlined and effective. This makes it easier for you to work through your project and for reviewers to understand your code and provide feedback. Whether you're using Git or another version control system, you can post Stacked Changes to Review Board and easily see the relation between changes in a stack.
In the future we plan on improving our support for Stacked Changes, such as automatically assigning the dependent and blocking review requests when posting a change, and some more intuitive UI for following a stack during review.
Stay up to date on our latest changes through our mailing lists.
If you like to work in Stacked Changes and have ideas for features you want or better ways to support your workflow, let us know by sending us an email or hopping in to our Discord server.