How to Write Good Commit Messages (With Examples)
โFixed stuff.โ โWIP.โ โasdf.โ Scroll through almost any Git history and you will find messages that made sense for ten seconds. Months later, when you are hunting down the change that broke checkout, they tell you nothing. A good commit message takes thirty seconds to write and saves hours of archaeology. This guide covers the conventions experienced teams follow, with examples you can copy into your own workflow.
The shape of a great message
A commit message has a subject line, a blank line and an optional body. The widely used โ50/72โ guideline says:
- Keep the subject to about 50 characters so it fits in one-line logs and tool interfaces.
- Leave the second line blank; many tools rely on it to separate subject from body.
- Wrap the body at about 72 characters so it reads well in a terminal.
The body is where you explain why the change was needed and what alternatives you rejected. The diff already shows what changed.
Write the subject in the imperative
Git itself writes messages like โMerge branch โฆโ and โRevert โฆโ, so the convention is to phrase subjects as commands: โAdd search filtersโ, not โAdded search filtersโ or โAdds search filtersโ. A handy test: the subject should complete the sentence โIf applied, this commit will โฆโ.
Some before-and-after examples:
- โfixed bugโ โ โFix crash when cart is emptyโ
- โchangesโ โ โRename user service to account serviceโ
- โupdateโ โ โBump image library to patch memory leakโ
Conventional Commits in a nutshell
Conventional Commits adds a small, machine-readable structure: type(scope): description. For example, fix(auth): handle expired refresh tokens. Common types include:
featโ a new feature (maps to a minor version bump)fixโ a bug fix (maps to a patch bump)docs,style,refactor,perf,test,build,ciandchoreโ everything else
A breaking change is marked with an exclamation mark, as in feat(api)!: remove v1 endpoints, or a BREAKING CHANGE: footer, and triggers a major bump. Release tools can then generate changelogs and version numbers straight from the history.
How to use the generator for demos and tooling
When you build a demo repository, test a commit-lint rule or record a tutorial, you need plausible history fast. The generator above helps:
- Leave Include scope on for messages like
feat(cli): add search filters, or switch it off for the shortertype: descriptionform. - Generate up to 50 messages per batch, mixing types such as feat, test, refactor, style and perf with scopes like ui, auth, docs and deps.
- Feed them into a script that creates empty commits, or paste them into your changelog generatorโs test fixtures.
- Use the batch to check that your lint rules accept valid messages and your changelog groups them correctly.
For real work, always describe what actually changed โ generic messages belong in sample data only.
Small habits that keep history clean
- One logical change per commit. If the subject needs the word โandโ, consider splitting it.
- Reference the issue in the body or footer so readers can find the discussion.
- Tidy up before you share. Squash โfix typoโ commits into the change they belong to before opening a pull request.
- Read your log. Run
git log --onelinenow and then; if it does not tell a story, adjust your habits.
A full example with body
Here is what a complete message can look like:
fix(checkout): prevent double charge on slow networks
After a blank line, the body might say: โThe pay button stayed active while the request was pending, so impatient users could submit twice. Disable the button until the response arrives and make the server reject duplicate order tokens.โ A footer can then list the related issue number.
In five lines, a future reader learns the symptom, the cause and both parts of the fix โ without opening the diff.
Pro tips
- Write the message before you commit by asking โwhy would a teammate need this change?โ.
- Avoid ending the subject line with a period.
- Use the body to record decisions that are not obvious from the code.
- Add a commit-msg hook or lint step so the convention is checked automatically.
Frequently asked questions
Can I edit a commit message after committing?
Yes. git commit –amend changes the most recent message. Avoid rewriting commits that others have already pulled, as it changes their history.
Should commit subjects start with a capital letter?
Plain-style messages traditionally do, while Conventional Commits descriptions usually start lowercase after the type. Follow whichever style your project already uses.
How long can a commit message body be?
As long as it needs to be. A few short paragraphs explaining the reasoning are far more useful than a single vague line.