
Good Git commit messages are more than a description of what you changed. They create a useful history of your project, helping you understand why a change was made months or even years later. In this article, we’ll look at practical ways to write cleaner, clearer commit messages and introduce conventions that can make your Git history easier to understand and maintain.
Why Commit Messages Matter
It is very easy to treat a Git commit as nothing more than a button you press after finishing some work.
You make a change, stage your files and type something like:
Updated stuff
Or perhaps:
Fixes
The problem is that these messages might make sense at the time, but they provide very little useful information later.
Imagine looking through the history of a project six months from now and finding commits called "Changes", "Update", "Fix", "More changes" and "Final changes". You know that something happened, but you have no idea what those changes actually involved.
A good commit message becomes part of the documentation for your project. It gives future developers, your colleagues and even your future self a quick explanation of what happened.
Git itself recommends starting a commit with a short summary, followed by a more detailed description when additional context is required.
Describe What Changed
The first rule of a good commit message is simple: describe the actual change.
Consider a commit containing a change to an application's authentication system.
A message such as:
Updated authentication
is technically true, but it is not particularly useful.
A better message would be:
Add refresh token support to authentication
Now we immediately know what was changed.
Another example might be:
Fix null reference when loading customer profile
This tells us considerably more than:
Fixed bug
The goal is to make the commit understandable without requiring somebody to open every changed file.
Explain Why When It Matters
Describing what changed is useful, but sometimes the most valuable information is why the change was necessary.
For example:
Increase API timeout to handle slow payment responses
tells us what happened.
A more detailed commit could explain the reason:
Increase API timeout for payment requests The payment provider can occasionally take more than 30 seconds to respond during periods of high traffic. The previous timeout caused valid payment requests to fail prematurely.
This becomes particularly valuable when somebody later considers changing the timeout back.
Without the explanation, they might assume the value was arbitrary. With the explanation, they understand the decision that was made.
Git's own development guidelines emphasise that useful commit messages should help explain the problem being solved and justify the chosen solution.
Keep the First Line Short
The first line of a commit is particularly important because it is commonly displayed in Git logs, GitHub, Visual Studio and other development tools.
Git recommends a short summary of no more than around 50 characters, although this should be treated as a guideline rather than an absolute rule.
For example:
Fix customer profile loading
is much easier to scan than:
Fixed an issue that was occurring when the customer profile page was being loaded and sometimes causing a null reference exception
If the change needs more explanation, put that information in the body of the commit.
The result is a history that remains easy to scan while still allowing detailed information to be recorded when necessary.
Use Imperative Language
A useful convention is to write the first line as an instruction or action.
For example:
Add customer validation
rather than:
Added customer validation
Similarly:
Fix login timeout
is preferable to:
Fixed login timeout
This style creates a consistent history where each commit describes an action.
You do not have to obsess over grammar, but consistency makes a surprisingly big difference when browsing a large repository.
Avoid Meaningless Messages
Some commit messages appear regularly in development projects:
Changes Update Fix Bug fix Stuff Testing More changes Final Final fix Really final fix
The problem is not that these messages are short. The problem is that they communicate almost nothing.
A short message can still be excellent.
For example:
Fix incorrect order total
contains only five words, but tells us exactly what the commit addressed.
The objective is not to write long commit messages. The objective is to write useful ones.
Keep Commits Focused
Good commit messages become much easier to write when the commit itself represents one logical change.
For example, suppose you have changed the login validation, updated the navigation menu, fixed a database query and reformatted several unrelated files.
You could commit everything together with:
Update application
But this creates a problem.
If you separate the work into logical commits, you might instead have:
Fix login validation Update navigation menu Optimise customer query Format service classes
Each commit now has a clear purpose.
GitHub also recommends keeping commits focused around small, related groups of changes because this makes the history easier to understand.
Use the Commit Body for Context
Not every commit needs a long description.
A simple change such as:
Fix spelling mistake in README
probably does not need anything else.
A more complicated change might benefit from a body.
For example:
Fix customer search timeout The customer search was timing out when the database contained a large number of records. The query was loading unnecessary columns before filtering the results. The query now applies the filter before retrieving the remaining customer information.
The first line gives us the summary.
The body explains the problem and the solution.
This is especially useful for changes that involve design decisions or behaviour that might otherwise be difficult to understand later.
Introducing Conventional Commits
If you want to take commit messages a step further, you can adopt the Conventional Commits convention.
Conventional Commits provides a lightweight structure for making commit messages both human-readable and machine-readable.
The basic format is:
type: description
For example:
feat: add customer export
or:
fix: prevent duplicate customer records
A scope can also be included:
fix(api): handle missing customer address
The convention commonly uses types such as feat for new functionality, fix for bug fixes, docs for documentation, refactor for code restructuring and test for testing changes.
The advantage is that somebody scanning the Git history can immediately see the nature of each change.
A Practical Conventional Commit
Consider a new feature being added to an ASP.NET Core application.
Instead of:
Added export functionality
you could write:
feat(customers): add CSV export
A bug fix might be:
fix(orders): prevent duplicate order submission
A documentation change could be:
docs: update installation instructions
And a refactoring could be:
refactor(auth): simplify token validation
These messages are short but provide considerably more information.
Conventional Commits can also be useful when projects use automation to generate changelogs or determine version changes from the commit history.
Breaking Changes
Some changes require more attention than others.
If a change breaks an existing API or requires consumers of your software to make changes, Conventional Commits provides a way of identifying it.
For example:
feat(api)!: remove legacy customer endpoint
The exclamation mark indicates a breaking change.
Alternatively, the commit body can contain a BREAKING CHANGE footer explaining what has changed.
This can be particularly useful for libraries and APIs where developers outside the immediate project may depend on the existing behaviour.
Commit Messages Are Part of Your Project History
One of the biggest advantages of good commit messages only becomes apparent over time.
Imagine investigating a problem in a project two years after the original code was written.
You discover that a particular piece of code looks unusual. You use Git to inspect its history and find:
fix(payments): prevent duplicate payment requests
You can immediately see that the unusual code was introduced deliberately to address a payment problem.
A poor message such as:
Changes
would leave you with very little useful information.
This is why commit messages should be considered part of the project's historical record.
Writing Better Commit Messages in Practice
Before committing, take a moment to look at the changes you are actually about to record.
Ask yourself what has changed and why it has changed.
If the answer can be expressed clearly in a single sentence, use that sentence as your commit message.
For example:
Fix incorrect VAT calculation
If the reason is important, add a body explaining it.
Fix incorrect VAT calculation VAT was being calculated before the discount was applied, resulting in an incorrect total for discounted products.
This takes only a few seconds but could save considerably more time in the future.
A Simple Formula
If you are struggling to write a commit message, a simple formula works well:
Action + What Changed + Where
For example:
Fix validation in customer registration
Or:
Add caching to product service
Or:
Update error handling in payment API
If somebody needs more information, explain the reason in the commit body.
The important thing is that somebody reading the Git history should be able to understand the purpose of the commit without opening the entire codebase.
Final Thoughts
Git makes it incredibly easy to create a history of every change made to a project, but the quality of that history depends heavily on the information we put into our commits.
A good commit message does not need to be complicated. It simply needs to be clear, concise and meaningful.
Describe what changed. Explain why when necessary. Keep commits focused and use a consistent style. If your project benefits from additional structure, consider adopting Conventional Commits.
After all, the person most likely to benefit from a good commit message might not be another developer.
It might be you, six months from now, trying to remember exactly why you wrote that piece of code in the first place.
Become a member
Get the latest news right in your inbox. It's free and you can unsubscribe at any time. We hate spam as much as we do, so we never spam!
Read next
Git Workflows for Solo Developers
Version control is essential for any developer, even when working alone. A clear Git workflow helps you organise changes, track features, and avoid breaking your main codebase. In this article, we explore simple and practical Git workflows that solo developers can adopt to keep projects maintainable, predictable, and easy to manage.
