Why you should keep your git commits small and meaningful

Published on: February 19, 2025

When you're using Git for version control, you're already doing something great for your codebase: maintaining a clear history of changes at every point in time. This helps you rewind to a stable state, track how your code has evolved, and experiment with new ideas without fully committing to them right away.

However, for many developers, Git is just another tool they have to use for work. They write a lot of code, make commits, and push their changes without giving much thought to how their commits are structured, how big their branches are, or whether their commit history is actually useful.

Why Commit Hygiene Matters

As projects grow in complexity and as you gain experience, you'll start seeing commits as more than just a step in pushing your work to GitHub. Instead, commits become checkpoints—snapshots of your project at specific moments. Ideally, every commit represents a logical stopping point where the project still compiles and functions correctly, even if a feature isn’t fully implemented. This way, you always have a reliable fallback when exploring new ideas or debugging issues.

Now, I’ll be honest—I’m not always perfect with my Git hygiene. Sometimes, I get deep into coding, and before I realize it, I should have committed ages ago. When working on something significant, I try to stage my work in logical steps so that I still have small, meaningful commits. If you don’t do this, the consequences can be frustrating—especially for your teammates.

The Pain of Messy Commits

Imagine you're debugging an issue, and you pinpoint that something broke between two commits. You start looking at the commit history and find something like:

  • wip (Work in Progress)
  • fixing things
  • more updates

None of these tell you what actually changed. Worse, if those commits introduce large, sweeping changes across the codebase, you’re left untangling a mess instead of getting helpful insights from Git’s history.

How Small Should Commits Be?

A good rule of thumb: your commits should be small but meaningful. A commit doesn’t need to represent a finished feature, but it should be a logical step forward. Typically, this means:

  • The project still builds (even if the feature is incomplete).
  • The commit has a clear purpose (e.g., “Refactor JSON parsing to use Decodable”).
  • If you’re adding a function, consider adding its corresponding test in the same commit.

For example, let’s say you’re refactoring JSON parsing to use Decodable and updating your networking client:

  1. Commit 1: Add the new function to the networking client.
  2. Commit 2: Add test scaffolding (empty test functions and necessary files).
  3. Commit 3: Write the actual test.
  4. Commit 4: Implement the feature.
  5. Commit 5: Rename a model or refactor unrelated code (instead of bundling this into Commit 4).

By structuring commits this way, you create a clear and understandable history. If a teammate needs to do something similar, they can look at your commits and follow your process step by step.

The Balance Between Clean Commits and Productivity

While good commit hygiene is important, don’t obsess over it. Some developers spend as much time massaging their Git history as they do writing actual code. Instead, strive for a balance: keep your commits clean and structured, but don’t let perfectionism slow you down.

You really don’t have to pick apart your changes just so you can have the cleanest commits ever. For example, if you’ve fixed a typo in a file that you were working on, you don’t have to make a separate commit for that if it means having to stage individual lines in a file.

On the other hand, if fixing that typo meant you also changed a handful of other files, you might want to put some extra work into splitting that commit up.

Commit Messages: Crafting a Meaningful Story

In addition to the size of your commits, your commit messages also matter. A good commit message should be concise but informative. Instead of vague messages like fix or updated code, consider something more descriptive, like:

  • Refactored JSON parsing to use Decodable
  • Fixed memory leak in caching logic
  • Added unit test for network error handling

By keeping your commit messages clear, you help yourself and others understand the progression of changes without having to dig into the code.

Rewriting Git History When Necessary

Sometimes, you may want to clean up your Git history before merging a branch. This is where tools like interactive rebase come in handy. Using git rebase -i HEAD~n, you can:

  • Squash multiple small commits into one.
  • Edit commit messages.
  • Reorder commits for better readability.

However, be cautious when rewriting history—once commits are pushed to a shared branch, rebasing can cause conflicts for your teammates.

Rebasing on the command line can be tricky but luckily most GUIs will have ways to perform interactive rebasing too. I personally use interactive rebasing a lot since I like rebasing my branches on main instead of merging main into my features. Merge commits aren’t that useful to have in my opinion and rebasing allows me to avoid them.

In Summary

In the end, it’s all about making sure that you end up having a paper trail that makes sense and that you have a paper trail that can actually be useful when you find yourself digging through history to see what you did and why.

The reality is, you won’t do this often. But when you do, you’ll feel glad that you took the time to keep your commits lean. By keeping your commits small, writing meaningful messages, and leveraging Git’s powerful tools, you ensure that your version control history remains a valuable resource rather than a tangled mess.

Categories

git

Subscribe to my newsletter