Let’s say I’m making a pot of tortilla soup. I’ve made tortilla soup before and it has always turned out good. This is a low-risk operation.
But for some reason, this time, I decide to get experimental (high risk). I add some cayenne pepper to the soup. Unfortunately, this makes the soup too spicy, and no one in my family except me will eat it. The soup is now basically garbage and I have to throw it out.
What just happened was bad. I mixed a high-risk operation (cayenne) into a low-risk operation (tortilla soup). Since cayenne is impossible to remove from soup, I’ve turned the entire operation into a high-risk operation. And, due to my poor choices, the whole operation got ruined.
Now let’s say I’m making a different kind of soup, an experimental one. Let’s say I’m making another Mexican soup, pozole. I’ve never even eaten pozole before. In fact, I’m not even sure what pozole is. Who knows if my family will like it. This is a high-risk operation.
On the day I make pozole, I happen to have some homemade bread around. A lot of work went into making the bread. Unlike the pozole, the bread is a low-risk operation. In fact, it’s a no-risk operation because the bread is already made.
Since I know that bread usually goes good with soup, I decide to cut up the loaf of bread and serve it in bowls with the soup.
Unfortunately, when I serve the pozole for dinner, it’s discovered that my pozole is not good. No one, including me, eats very much. What’s more, I’ve wasted a whole loaf of homemade bread in addition to wasting the pozole ingredients.
In this case I mixed a low-risk operation (the bread) into a high-risk operation (the pozole). Now not only do I have to throw out the pozole but I have to throw out the bread with it.
What atomic commits are
The literal meaning of “atomic” is “cannot be cut”, from Greek. (The “a” part means “not” and the “tomic” part comes from a word that means “cut”.)
A commit that’s atomic is a commit that’s only “about” one thing. The commit can’t be cut into smaller logical pieces.
But obviously, unless you’re committing a one-character change, pretty much any commit could conceivably be cut into smaller pieces. So if it’s not clear to you what constitutes an atomic commit, it may help to realize that atomicity is subjective. In a moment we’ll come back to how to decide what constitutes an atomic commit. First let’s talk about why atomic commits are helpful.
Why atomic commits are helpful
One of my programming principles is “keep everything working all the time”. It’s much easier to keep everything in a working state all the time then to allow things to slip into chaos and then try to recover.
But slipping into chaos once in a while is unavoidable. When that happens, the easiest way to get back to “order” usually isn’t to solve the problem, but rather to just blow away the bad work and revert back to your last known good state.
If your commits are non-atomic, then reverting back to your last known good state can be problematic. You’ll be forced to throw the baby out with the bathwater.
If you make my “tortilla soup mistake” and mix a small high-risk change in with a large low-risk change, then you’ll end up reverting a large amount of good work just because of a small amount of bad work. (You might be able to escape this problem if the two changes are sufficiently separate from each other but that’s often not the case.)
If you make my “pozole mistake” and mix a low-risk change in with a high-risk change, then you’ll have to revert the good change along with the bad one as well.
How to decide what constitutes an atomic commit
If atomicity is subjective, how do you decide what’s atomic?
Here’s the heuristic I use to decide what to put in my commits: the smallest thing that can be considered complete.
Sometimes when I code in front of people, they’re astonished by how frequently I make commits. But I figure since it’s super cheap to make a commit, why not turn the “commit frequency dial” up to the max?
- An atomic commit is a commit that’s only “about” one thing.
- Atomicity is subjective.
- It’s easier to keep everything working all the time than to allow things to slip into a state of chaos and then try to recover.
- When things do slip into a state of chaos, it’s usually cheaper to just revert to the last known working state and start over than to try to fix the actual problem.
- Atomic commits ensure that, when you do have to revert, you don’t have to throw out the baby with the bathwater.