Skip to content

Good Git commit messages

Hey there 👋

When using git, it’s tempting to commit all your changes at once with a vague message like “fixed stuff” or “updates”. But here’s the thing: your future self (and your teammates) will thank you for taking a few extra seconds to write clear, meaningful commit messages.

Why commit messages matter

The Git history is the complete record of all changes made to your repository. It’s not just a log — it’s a story of why decisions were made, what problems were solved, and how the codebase evolved.

Git log on carbon repository
This is a sample git history with nice commits. To get this output, run the git log command. For more, see git-log official documentation.

Good commit messages help you:

  • Understand changes quickly — Know exactly what a commit does without reading the code
  • Debug faster — Find when and why a bug was introduced
  • Review efficiently — Make code reviews smoother and more meaningful
  • Revert safely — Undo specific changes without affecting unrelated work

Keep commits small

Small, focused commits are easier to understand, review, and revert if needed. Instead of one massive commit with 20 file changes and a message saying “various fixes”, break it into logical chunks:

  • ✅ “Fix null pointer exception in user authentication”
  • ✅ “Add validation for email input field”
  • ✅ “Update dependencies to latest versions”

Each commit should represent one logical change. If you can’t describe your commit in a single sentence, it’s probably doing too much.

The anatomy of a good commit message

Structure your commit message like an email with a subject line and body.

The subject line

Keep it 50 characters or fewer and make it descriptive.

A list headed guidelines for a good summary line. It should describe what the commit does; it should sit on its own, with a blank line between it and the body; it should be 50 characters or fewer; it should be concise, like an email subject.

Good examples 🟢:

  • Fix race condition in payment processing
  • Add user avatar upload feature
  • Remove deprecated API endpoints

Bad examples 🛑:

  • fixed bug (too vague)
  • Update the entire authentication system to use OAuth 2.0 instead of custom tokens (too long)
  • stuff (useless)

If your change needs explanation, add a body after a blank line. Wrap lines at 72 characters or fewer and write in the imperative, the way Git itself does (“Fix bug”, not “Fixed bug”).

A list headed guidelines for a good commit body. It should explain why the change was made, expanding on the summary line; it should use the imperative, the way Git does, Fix bug and not Fixed bug; it should wrap at 72 characters, so it still reads well in git log in a terminal.

The body should answer:

  • What does this change do?
  • Why was this change necessary?
  • How does it solve the problem?

Example:

Fix memory leak in WebSocket connection handler

The connection handler wasn't properly closing connections when
clients disconnected unexpectedly. This caused memory usage to
grow over time in long-running services.

Add explicit cleanup in the disconnect handler and add tests
to verify connections are properly released.

Markdown in commit messages

Git stores the message as plain text, and most hosts show it that way. GitHub renders `code` in backticks and turns issue numbers, @mentions and URLs into links, but **bold**, _italics_ and - lists come through as the literal characters. GitLab still has an open feature request for Markdown in commit messages.

So stick to structure that also reads well in git log in a terminal:

  • `code` for technical terms
  • - or * bullets for multiple points, which look fine as plain text

Don’t go overboard, but a little structure makes longer commit messages much more readable.

Conventional commits

Many teams follow the Conventional Commits specification. It adds a standardized prefix to commit messages. The spec itself only defines feat and fix; the rest below are the common Angular-style extras from @commitlint/config-conventional:

  • feat: — New feature
  • fix: — Bug fix
  • docs: — Documentation changes
  • refactor: — Code refactoring
  • test: — Adding or updating tests
  • chore: — Maintenance tasks

Examples:

  • feat: add dark mode toggle to settings
  • fix: resolve CORS issue on API endpoints
  • docs: update installation instructions for Windows

This makes it easy to scan history and even auto-generate changelogs.

Summary

A commit message drawn as three stacked boxes: the summary line, marked 50 characters; a blank line; and the commit body, marked 72 characters per line, with two lines of text inside. One note points at the body: plain text, not Markdown, though backtick code and dash bullets read fine. Another points at where the first line stops: wrap every line at 72 characters.

Good commit messages are:

  • Clear — Describe what changed and why
  • Concise — Keep subject lines under 50 characters
  • Consistent — Follow a standard format
  • Complete — Include context in the body when needed

Your commit history is documentation that lives forever with your code. Make it count!

Further reading: This article was inspired by Tim Pope’s classic post on commit messages. Check it out for deeper insights into the reasoning behind these practices.

Thanks for reading! Now go write some beautiful commits ✨

Thanks for reading.

Follow the RSS feed · Say hi on LinkedIn

Human Agent