Atomic Object’s blog on everything we find fascinating.

Why I Git Commit Too Much

I recently joined a new project, and one of my teammates asked me, “Why do you commit so much?” I decided to write this post to explain my reasoning to him and anyone else who might come across my work in the future.

Small commits can be your best friend.

Just like functions, small commits focus on one thing: a single change. This forces our commit messages to be more descriptive (sorry guys, “fixed some stuff” is not going to cut it anymore).

Let’s take a look at an example:

git commit -am "Updated 'Contact us' to 'Need Help? Contact Us!'"

In this case, you could just look at the changes made in the commit, but why look at the code when the description is right there in front of you? Small commits make it extremely easy to find a specific change that went in, especially when traversing a list. They also make it simple to see how the project was built, piece by piece.

1. They simplify code review.

Small commits make code review much easier. They let you review the changes one at a time and share the author’s mindset. The commits tell a story as if the author were explaining the changes in person.

2. They help you share knowledge.

Recently, I learned that adding a line break after a return statement in JavaScript is the same thing as returning nothing (if you’re curious, see this Stack Overflow answer for an explanation). I removed the line break and committed the result:

Thanks to small commits, I was able to share this knowledge with my teammates, knowing it would be saved forever. If there’s one thing I’ve learned as a programmer, it’s that there is a reason for everything. Sometimes, the reasoning isn’t clear and a code comment doesn’t make sense (can you imagine every JavaScript function return having a comment saying “Line breaks will not actually return this data”). Small commits help fill this gap.

3. They can help fix your mistakes.

No developer is perfect. Sometimes, we head down the wrong path and realize something we tried just isn’t working out. Perhaps we tried to bold some text by adding a CSS class and tweaking some properties, but the results didn’t look that great. Now what?

We could manually undo the change, but it’s easy to miss something (for example, you might remove the CSS class from the HTML element but forget to remove the definition in the CSS file). git revert is an extremely easy way to undo a change without having to remember the initial state.

On a similar note, every one of us has written a bug, and even fixed a bug while introducing three more. Usually, we are able to find the root issue through using breakpoints and reanalyzing the problematic logic. However, there are times when the problematic logic just cannot be discovered, no matter what debugging steps we take.

git bisect is here to save the day! It first asks to provide a “good” commit (one that doesn’t experience the bug in question) and a “bad” commit (usually, it’s the latest commit). It then executes a binary search, testing various commits as “good” or “bad”.

It’s extremely important that every commit is buildable and the tests all pass. Otherwise, it will be impossible to verify whether a commit is “good” or “bad”. In the event that a broken commit sneaked in (from a teammate, of course, because we’re good boys and girls), git bisect skip can be used to skip over it (just cross your fingers that this commit is not the cause of the bug). At the end, git bisect skip will return the commit that introduced the bug. The problematic piece of code should be completely obvious and a fix should should already be cooking up.

If I had a penny for every time I blanked out on my previous day’s work during standup, I would be a millionaire. I once tried making a list of everything I worked on throughout the day, but it was tedious—and redundant, since my small commits shared the same information. Sure, no one wants to be that guy who has a laundry list of things he worked on, but skimming through the commit history is a great refresher (pro tip: try picking the top three things out of the list).

5. They let me cherry-pick changes.

Consider this scenario: while working on a separate task, Joe Bob added some new strings to the translations file that was just received. He also started incorporating these into his views, but he still has failing tests. Susan just started her task and realized that she needs some of these strings. It wouldn’t make sense to merge Joe Bob’s branch into hers, since it’s still a work in progress. Susan could just redefine these translations herself, but she fears the dreaded merge conflict. Since Joe Bob uses small commits, Susan is able to cherry-pick the commit that Joe Bob introduced the translations by running:

git cherry-pick some-hash

Summing Up

It’s okay to go down the wrong path, then revert your changes. No one cares about stupid little mistakes—if anything, it shows you care about bettering the project and ultimately yourself. If you’re contributing to an open source library, it’s usually better to have one commit per feature or fix. To get the best of both worlds, you can squash all of your tiny commits into one before you publish your changes. And for anyone curious, I’ve been on projects with well over 20,000 commits and experienced no slowness with git.

Thanks for those great additions, Todd! I actually use GitHub’s GUI for committing. I find myself committing individual lines quite a bit (as opposed to entire files) and the GUI makes it effortless. For everything else, I use the terminal (fetching, merging, pushing, etc).