3 min read

Writing Clear and Useful Git Commit Messages

The simple commit-message structure I adopted after vague messages made old changes difficult to understand.

  • Reliability

I used to write commit messages such as fix bug or update code. They felt good enough while the change was still fresh in my head.

A few months later, they were not useful at all. When I needed to understand an old change during debugging, the history could not tell me what had been fixed or why I had changed it.

That experience made me pay more attention to commit messages. This is not a rule that every repository must follow exactly. It is the structure that helps me—and the people I work with—understand changes later.

A Simple Structure

The format I commonly use is:

<type>(<optional scope>): <subject>

<optional body>

<optional footer>

For example:

fix(checkout): prevent duplicate cart items

Ignore another add request while the first request is still running.

Fixes: #123

The subject is enough for a small change. The body and footer are useful only when they preserve context that the subject cannot.

Choose a Type That Describes the Change

The types I see most often include:

Type Use
feat Add user-visible behavior
fix Correct broken behavior
docs Change documentation
refactor Restructure code without intentionally changing behavior
test Add or update tests
perf Improve performance
build or ci Change the build or delivery configuration
chore Perform maintenance that does not fit the other types

This list is not universal. A team can use fewer types, different names, or no prefixes at all. Consistency matters more than including every possible type.

Write a Useful Subject

I try to make the subject describe the result of the change:

Add user registration endpoint
Reject expired checkout sessions
Document local installation steps

Vague subjects leave the important part hidden:

update
fix issue
minor changes

Using the imperative form—Add, Fix, Remove—keeps subjects consistent. Around 50 characters is a useful readability target in many Git interfaces, but I do not remove important meaning just to meet an exact number.

Add a Body When the Reason Is Not Obvious

The diff shows how the code changed. A body is useful when the reason or effect would otherwise be lost:

fix(import): report a failed database restore

Check the mysql client exit status before marking the import complete.
The previous command treated a return to the shell as success.

I use the body to explain why the change was necessary, an important trade-off, or something a reviewer should verify. I do not repeat every line already visible in the diff.

Conventional Commits Is Optional

Conventional Commits defines a machine-readable version of this structure. It can help when a project uses commit messages for changelogs or release versions.

feat(auth): add password reset
fix(cart): prevent duplicate items
docs: clarify setup instructions

A breaking change can use ! or a BREAKING CHANGE: footer. That convention is useful only when the repository and its tooling agree on what it means. Adding a prefix does not make a vague or unrelated commit clearer by itself.

The Check I Use Before Committing

Before finalizing a message, I ask:

  1. Does the subject say what changed?
  2. Is the type appropriate for this repository?
  3. Does the body explain context that the diff cannot?
  4. Is an issue or breaking change worth mentioning?
  5. Will I understand this message several months from now?

Writing a clear message takes a little more effort than update code, but it saves time when I return to the history later. That is the main reason I keep using the convention.

References