What Are Stacked Commits and Why Should You Use Them?
Date: 2025-08-01 | atomic-commits | build | create | creation-cycle | git | productivity | software-engineer | stacked-commits |
I've been using stacked / atomic commits for years - they're the default paradigm of version control at Instagram / Meta and I've found them to be extremely useful across orgs and projects.
I've also been playing around with AI agents lately and believe stacked commits are an excellent way to implement AI checkpointing.
In this post we're going to talk about what stacked commits are and why you should use them in your own workflows.
Traditional version control focuses on feature branches.
Before we can talk about what stacked / atomic commits are, we need to understand what the default version control paradigm is.
Today git is the leading version control technology for software. It uses commits to checkpoint work and branches to enable different working copies of the codebase to be worked on at the same time which can then be merged together later.
This led to the rise of "feature branches" as the primary paradigm for creating changes to the codebase.
- Create a working copy of the codebase - using a branch
- Make changes to support your new feature
- Merge that back into the codebase
This works but has a few challenges:
- Feature branches often include multiple logical changes in order to build the feature
- Higher chance of merge conflicts because changing several things at once - if anyone else has changed even one of those while you're working on your changes, you get a merge conflict
- More surface area of changes means harder and longer to review and more chance of a bug entering the system
Let's use an analogy where our codebase is a skyscraper. Let's say we want to add a pool to the roof - that's our feature. In order to do this we probably need to change multiple things (idk I'm not a pool expert):
- Add pool on roof
- Remove whatever is already on roof
- Add pumping system, may require changes to building plumbing to implement
A feature branch is like trying to do this all at once. We build all the pieces and try to install them all at the same time (you can do this in software, harder to do in real world). But if there's another change happening at the same time - could be with the roof or the plumbing or just happens to touch the same spots - then these changes would collide and we get a merge conflict, holding up our project and whatever other projects are in conflict.
Or perhaps you submit your big change for review and someone says hey that plumbing is not right, now you may need to change your whole feature possibly wasting hours or days of work. And while you're doing that more changes are getting made to the building leading to potentially more merge conflicts.
In some ways this style of building is akin to the waterfall approach - build everything upfront then try to launch the whole thing all at once when it's finished.
Stacked commits land a series of atomic commits as they're ready
Where traditional feature branches use branches as the unit of change, stacked commits use commits as the unit of change.
Stacked commits are a series of atomic commits. An atomic commit is a single logical change - not a "physical" one like a line of code or character but a logical one like a functional change to the system.
We still build our feature with a stack of commits but each commit is self contained and can be landed before the rest of the stack is complete.
An atomic commit could be:
- Adding a new API parameter and updating tests
- Fixing a bug (and adding tests)
- Refactoring the implementation of some function
But it is typically not all of these things together as these are usually distinct logical changes (though edge cases do exist so use your judgement).
The benefits of using atomic commits stem from the smaller surface area of change in each one:
- Easier and faster to review - instead of 6,000 lines, each commit may be a couple hundred at most
- Deeper, more meaningful reviews - no "lgtm!" on a 6,000 line PR simply because the reviewers' eyes were glazing over
- Faster feedback - Commits start merging sooner while you work on the rest of the stack, reducing chance of merge conflicts and getting early feedback
- More robust testing and feedback - you are testing and shipping one logical change at a time, not several layered changes so we can be more precise about testing and it's clearer to draw causation from logical change to unexpected side effect
One of the reasons stacked commits are preferred to feature branches at Meta is that there is so much code / so many systems, it's impossible for any one person to understand all of it. This means it's possible any small change might break everything - perhaps by increasing the cost of a hot path by ~2% or breaking 0.1% of traffic being sent from old clients. By splitting up each change, it's easier to tell WHAT small change broke so you can understand, revert, and fix it. If this was shipped together as part of a 6k loc change, we could still revert it (when in doubt, hit revert) but it may take longer to figure out what root cause is so we can prevent it from happening again.
Let's go back to our skyscraper analogy where we're trying to add a pool on the roof. Instead of building everything and trying to ship it at the end of the build cycle, we split up our build into phases and ship each one as it's ready:
- First we might improve the plumbing to support the pool
- Then we might move the stuff off the roof
- Then we might build the pool itself
- Then we might hook up the pool to the plumbing
We end up with the same feature overall but now our work is isolated to a single part of the building at one time. this allows us to launch in phases and limits the surface area of collisions with other work that may be happening at the same time.
Plus if we get review feedback that our approach is bad, we just have to scratch the part of the stack we've built so far / that's related to it - not the full feature cause we haven't built it yet!
In many ways this approach is less like waterfall and more like agile (lowercase a) - we are building milestones and shipping them to customers as soon as they're ready which means we get early feedback and can course correct with limited wasted cycles.
How to build features with stacked commits
If we squint, we see that stacked commits and feature branches look very similar. The difference is that stacked commits are made of atomic commits that are constructed to be independently deployable whereas a feature branch is made up of many commits that are each partial changesets meaning we can't deploy a complete change until the end of the branch.
Here's the process I use to build stacks of atomic commits:
- Plan the project
- Break it up into ordered tasks / milestones
- Build the feature in that order, putting each logical change in its own commit
(Note: parallelization is possible though it's typically best to start out with a linear changeset then split the parallel parts when they're next up for review / land.)
I find this task breakup typically takes the form of:
- Cleanup / refactor commits - Things I'm changing about the current system to accomodate my new feature
- Feature changes - Things I'm adding to build my feature
- Followups - Things that should be changed / I came across in my build but are not strictly blocking my feature (these can often be outside of your commit stack if they don't rely on your changeset to make sense)
By breaking it up this way you'll start to see natural patterns for breaking up features:
- Change the API first then migrate consumers in a different commit - often more deploy safe and may lead to more generalizable APIs vs custom fit for this particular feature
- Not mixing refactors and feature changes - refactors can introduce bugs, too! Would be a shame if your little null check broke prod and caused your feature to be reverted.
- Cleanup tasks like spelling, comments, and code style can be done in their own commits - Easy to review and land so they ship faster, they don't "hide" meaningful changes in a feature PR, and less likely to run into merge conflicts / block your meaningful changes because you ship them quickly
I will typically batch a small stack of atomic commits together to ensure it's taking the form of something that makes sense / I'm happy with then submit those for review before working on the next batch.
There's definitely a balance between commits that are too small for reviewers to understand the context / what you're building so they can't give good reviews and commits that are too large that mix logical concerns and are harder to review / have a higher likelihood of bugs. Finding that balance is an art but you'll start to build that muscle as you try it out.
Tools for stacked commits in git
In general you don't need any special tools to start stacking commits. In git, these stacked commits are represented by a series of branches that each contain a single commit.
That said it's not a first class citizen in git so may be a bit clunky. There are some tools that make this a lot nicer.
Graphite is my current choice. It is a CLI tool but also has a nice VS Code extension for those that like GUIs (I am a shameless Git GUI enjoyer). It's the closest to Meta's Smartlog (their internal stacked commit technology) I've found in the real world.
But there are several others I've heard of / taken a look at that people seem to like:
- git spice
- git town
- jujutsu
Pick one you like and try it out.
Next
I've found atomic commits make the software dev cycle much smoother and more deterministic. Each change gets its own commit and review so we always know what's landing and each change is thoroughly discussed and considered.
It does take a bit to get used to and feels a bit manual at first but I find it's a bit more work upfront for a smoother dev cycle overall.
If you liked this post you might also like:
- Stop Vibe Coding, Start Power Coding - How To Write Quality Software Faster With Agentic AI (Without Pissing Off Your Software Engineers)
- How to Checkpoint Code Projects with AI Agents - Save Your Work, Keep Projects on Track, and Reduce Rework
- I Vibe-Coded a C# Library with Claude Code - Here's 6 Things I Learned
Want more like this?
The best way to support my work is to like / comment / share for the algorithm and subscribe for future updates.