What are Stacked Commits?
Stacked commits, also known as stacked diffs, stacked changes, or patch stacks, are a way of delivering code where a deliverable is split into multiple units of change that build on top of each other, and each unit of change can be reviewed independently.
Imagine building a cake layer by layer, where each layer can be tasted by different taste testers. Similarly, with stacked commits, each unit of change can be tested and reviewed independently, making the review process faster and more efficient.
Where can Stacked Commits be Used?
Stacked commits shine when you're working on a sequential set of changes which build on top of each other. A few instances of when you might find yourself working on such a chain of changes are:
Adding or modifying functionality across multiple libraries
A large refactoring across multiple pieces of code
Building a new feature which needs end-to-end changes across the tech stack
Let's consider a specific example and examine it in detail: You're building a new feature in a full-stack web application and you have identified the following tasks:
Create the new database schema.
Add the new API endpoints in the API backend.
Add UI support for the new feature by making use of the newly added APIs.
The Regular Way
You create the work items for these tasks and you start developing them.
These tasks have a definite sequence to them: The DB schema needs to created first, then the API can be built, and finally the UI will be updated. However, you're someone who values velocity so you decide to work on these tasks concurrently (with varying degrees of progress) and raise pull requests (PRs) quickly as different reviewers will review different PRs.
You end up with a scattered workflow like this:
Each PR is tied to a branch in the regular development workflow and this means that you would need
N branches to raise
Moreover, working with multiple branches becomes trickier, and uglier, when you have branches which depend on in-progress branches (instead of the main branch). Branches can quickly diverge and you will find yourself playing catch up with your own changes. Another disadvantage is that the PRs would need to have their target branch set to something other than the main branch so that the diff shows up correctly.
With Stacked Commits
A single commit is the atomic unit of change when using stacked commits. You modify (or amend) the commit when making a related set of changes and you create a new commit when you're making a different set of changes.
You can now work on the sequence of changes and each point in the sequence can be freely updated. You can also easily carry over the changes from point to another as you're in the same commit chain. Above all, each commit can be independently sent out for faster and better-scope reviews.
Getting to Stacked Commits
Stacked commits sound nice but they are significantly different from the branch-based development most developers use (backed by Git). I have personally come from a branch-based model and I initially found the trunk-based model which I use at my current organization unwieldy and confusing. However, the trunk-based model facilitates features like stacked commits and I swear by it now.
Features can be built piece-by-piece in a clean manner: Each commit progresses towards feature completion and it can be tested and reviewed independently.
It encourages small commits: Small commits are encouraged because all related changes belong to a single commit so an implicit granularity forms. This has the benefit of better testing and reviews as the surface area is small.
Every change unit builds: You cannot have a commit which doesn't build as each commit is directly merged into the main branch.
Concurrent code reviews: Code reviews become faster as the commits can be reviewed independently of each other.
Code reviews need to be more careful: You know that you're looking at the whole picture when you're reviewing a PR but this is not true when reviewing stacked commits. You only have a view into a single commit in a potential chain of commits when the author uses stacked commits.
Changes need to be well-defined so that reviewers can review the changes in isolation.
Tooling support can be costly: Stacked commits are not easily supported by VCS's like Git.
Patching is a pain: Stacked commits work great when you're working on a chain you own but it becomes ugly when you're building your chain on top of another chain.
A special mention is needed for the tooling required to support efficient working with stacked commits:
Trunk-based development encourages small, frequent commits.
Code Review UI Features
diffbaseis the parent commit on which the current commit in the stack is based on. It is handy to show the
diffbaseof the commit being reviewed so that the reviewers have the full picture when they want.
Prevent submitting changes with
diffbase: You do not want to submit an intermediate commit in a chain of commits without first submitting the commits which came before it.
diffbase: You want to indicate the commit is ready to be submitted to the tree when the previous commit has been submitted.
Editing a particular commit: You want to be able to edit any particular commit in the commit stack easily.
Evolving changes: You want to be able to propagate changes made in a particular commit to all the commits which come after it in the stack.
Big Tech companies like Facebook and Google enjoy the benefits of stacked commits and recently Facebook has released Sapling which facilitates working with stacked commits.