Every time I work on code with someone I haven’t worked with before, I end up having the same conversation. It usually starts when I push my first pull request and they see something like +20/-40 in a single file using 11 commits. When I tell people that I tend to use small commits they usually nod and confirm that they appreciate it. It’s only after they notice just how small those commits are that the eyebrows start moving upwards.

Every Little Thing

When I talk about small commits, I really mean small. Imagine a piece of code with a feature flag that switches behaviour.

const someFeatureIsEnabled = await getFeatureFlag('some-feature-flag');

if (someFeatureIsEnabled) {
    // do something
} else {
    // do another thing
}

When that feature flag is fully rolled out, it would be straightforward to push a commit like “Remove fully rolled-out feature flag ‘some-feature-flag'” with this as the resulting code:

// do something

This works fine for the example here but becomes much harder to review as the if and else branches get bigger.

The Long And Winding Road

Here’s how I often approach it.

Commit: Feature flag is fully rolled out and will always be true
const someFeatureIsEnabled = true;

if (someFeatureIsEnabled) {
    // do something
} else {
    // do another thing
}
Commit: Inline someFeatureIsEnabled
if (true) {
    // do something

} else {
    // do another thing

}
Commit: Remove else branch for conditional that is always true
if (true) {
    // do something
}
Commit: Remove conditional that is always true
// do something

This may look excessive at first glance, but it’s a good habit to create. In this specific example, everything is pretty straightforward and there are no side effects. However, as the code you’re dealing with is more complex, having built the habit of approaching a problem like this incrementally helps in several ways.

Getting Better

I usually tell people that having smaller, incremental steps can help with reviewing (more on that in a bit), but there are several other benefits that are often overlooked. First of all, the quality of the end result will be higher.

Putting small stops in place to reflect on the change I just made helps me think about the potential side-effects of that change. For instance, while creating the commit that removes the “else” branch in the example above, I just reserved myself a dedicated moment to check if there were parts of that code that called other parts which might be unused right now. Having that deliberate stop in place helps me gather my thoughts.

Describing the change in a commit takes a few seconds, but you would be amazed what innovative ideas your brain comes up with within just a few seconds of relaxation, of taking a step back and reflecting on the change you are applying.

Here, There, and Everywhere

As I’m usually very chaotic in planning my work, there’s another big benefit. Creating a quicksave every minute not only helps me scope and plan the next step, but also helps me reorient when I got distracted by something else.

I often look back at the last couple of commits because there was an email coming in, one of the kids screamed for attention, or perhaps a co-worker asked me for help. This meticulous and almost obsessively compulsive process helps me create (and restore) focus on a problem.

Being For The Benefit Of Mr. Reviewer

Last but not least, if you’re working with pull request reviews there’s another big upside. I’m sure you’ve all had your fair share of pull requests to review where there are 400+ lines of code changes in two commits — and the second commit fixes a minor typo.

Both GitHub and GitLab have pull requests that allow you to review commit-by-commit. You simply open the first commit in a pull request and click “next.” If you start reviewing every commit by reading the description at the top and then look at the actual changes, you can blaze through a big refactor in no time.

Keeping the cognitive load low in a review is essential to increase the quality of the review. Additionally, it allows automatic refactors (e.g. variable rename, code style fixes) to be described as automatic. This way, the reviewer can focus on the important commits and ignore most of what was changed automatically.

So, when was the last time you created a separate commit to rename a variable?