paulund

Commit Messages

Commit Messages

A well-written commit message is a gift to your future self and every developer who will read the history after you. It answers a single question that the diff cannot: why did this change happen?


The Conventional Commits Format

Conventional Commits is a lightweight specification that gives your commit history a consistent, machine-readable structure. The format is:

<type>(<scope>): <short description>

[optional body]

[optional footer(s)]

The type describes the nature of the change. The scope (optional) narrows it to the part of the codebase affected. The short description is a concise summary written in the imperative mood — as though you are giving an instruction.


Common Types

Type Meaning
feat A new feature
fix A bug fix
docs Changes to documentation only
style Formatting or whitespace changes that do not affect logic
refactor Code restructuring that does not add a feature or fix a bug
test Adding or updating tests
chore Maintenance tasks — dependency updates, build configuration, etc.
perf A change that improves performance
ci Changes to CI/CD configuration

Examples

feat(auth): add password reset flow

Users can now request a password reset email from the login page.
A signed token is embedded in the link and expires after one hour.

Closes #142
fix(cart): prevent duplicate line items on rapid add

The add-to-cart handler now checks for an existing line item before
inserting, which stops the race condition that produced duplicates
when users clicked the button quickly.

Fixes #198
refactor(payments): extract invoice generation into its own service

Moved invoice building out of the order controller and into
InvoiceService. No behavioural changes — this is groundwork for
the upcoming PDF export feature.
docs: clarify API versioning section in developer guide

Writing the Short Description

  • Keep it under 72 characters so it fits comfortably in git log --oneline and most code-hosting UIs.
  • Use the imperative mood: "Add feature", not "Added feature" or "Adds feature".
  • Do not end with a full stop.
  • Do not repeat the type in the description — feat: add login is correct; feat: added new login feature is redundant.

The Body

The body is optional but valuable for anything that is not immediately obvious from the description. Use it to explain why you made the change, not what you changed — the diff already shows that. Separate the body from the short description with a blank line.


Footers

Footers follow the body after another blank line. They are key-value pairs that tools and humans can parse:

  • Closes #123 or Fixes #456 — links the commit to an issue tracker ticket.
  • BREAKING CHANGE: <description> — flags that this commit introduces a breaking change. Many tools use this to trigger a major version bump automatically.
  • Reviewed-by: Name <email> — records who reviewed the change.
  • Co-authored-by: Name <email> — credits a collaborator.

Breaking Changes

Mark any commit that alters the public contract of your code with a BREAKING CHANGE footer, or append an exclamation mark after the type:

feat!: drop support for Node.js 16

BREAKING CHANGE: Node.js 16 reached end of life in September 2023.
The minimum supported version is now 18. Remove any CI jobs that
test against 16.

This convention lets changelog generators and semantic versioning tools identify breaking changes automatically.


Best Practices

  • Commit early, commit often. Small, focused commits are easier to review, bisect, and revert than large ones.
  • One logical change per commit. If you refactored a module and fixed a bug in the same session, that is two commits.
  • Review your own diff before committing. Run git diff --staged and read through it as though you were a reviewer. Catch typos and accidental changes before they are baked into history.
  • Do not commit commented-out code or debug statements. These clutter the history and confuse future readers.