What are commit messages for?
Commits are developers' way to communicate and record the evolution of a project in a way that's convenient to both the end users and the contributors. As you likely know, commits are accompanied with messages. The impact of these messages (when used appropriately) is vast, and most of it boils down to answering the question "What changed?". Ideally, you should be able to re-build a similar project based solely on the commit history. Fortunately, Git does not enforce specific rules for these messages, so developers get the liberty to make up these rules in a way they see fit.
What are Conventional Commits?
A common example of such specifications is Conventional Commits. While the specifics of Conventional Commits are outside of the scope of this post, the main idea behind them is to divide commits into specific types and scopes with the purpose of standardizing them and developing automation tools that allow for less overhead during version control. Furthermore, Conventional Commits encourage the developer to make more granular contributions which results in a more detailed commit history. I will share some specific examples in the next section.
How do different teams approach writing commits?
Each team develops a Git etiquette unique to them. Some follow Conventional Commits, some have their own ruleset, others do not care. However, every team chooses how to phrase their commits, whether they know it or not.
Three common options are:
- Past tense + Active voice
"feat(profile): added cache invalidation"
- Imperative + Active voice
"feat(profile): add cache invalidation"
- Passive voice
"feat(profile): cache invalidation was added"
While each approach has its place, most developers gravitate toward the first two options; those are the ones we will focus on. Throughout my projects, I've bounced back and forth between these (seldom by choice). The trade-offs I observed were apparent and caused me quite the internal battle around this decision.
Past + Active
Writing in the past tense is something people naturally do. It feels like communicating "I did xyz" rather than "do xyz" which to some might feel backwards. While this may be useful in tight teams where people work on different scopes, main benefit of this approach to me is the way these commits read. Because they're in the past tense, the log is practically like a CHANGELOG. This lets developers automate the process of releasing an update with great quality changelogs, which eliminates the overhead and provides useful release notes. However, I came across many sources online saying that this is not conventional and is not how commits are usually treated. A popular rule of thumb is that a commit message should fit nicely into the sentence:
"When applied, this commit will _"
Furthermore, that's how Git's auto-generated commit messages are written. That being said, I found it generates less mental friction to write commits this way. But beware that following this style might mostly be valid if you plan on using your commits for the automated changelog. Otherwise, it's likely better to follow the conventional approach
Imperative + Active
Since writing commit messages in the Imperative mood is inline with how Git expects developers to commit it has become a widely accepted convention. This fact alone comes with several benefits; tools designed to work with commit messages are more likely to expect them to be imperative, developers are used to reading commits in this manner, and I've observed some beginners commit this way naturally. My issue is that I always automate releases using these messages. End users typically expect the CHANGELOG to read in a "What changed?" manner. Commit messages written in Imperative mood do not read that way. Because of this, I end up editing the release notes manually (though a pre-processor that automatically re-writes the messages before appending them to the changelog would help with this). It’s also worth noting that, when using agentic development systems (e.g., OpenCode, Claude Code), if you allow your agents to commit autonomously they tend to prefer this style unless prompted otherwise.
Further Resources
- Conventional Commits - the official specification and guidelines
- Semantic Versioning (SemVer) - rules for version numbers and compatibility
- Keep a Changelog - best‑practice format for human‑readable changelogs
- Commit‑lint - a configurable linter for enforcing Conventional Commits