Back to Blog

Semantic Intent

Semantic Intent

Semantic Intent

Your manual CHANGELOG.md is a lie waiting to happen. If you’re still hand-typing release notes or debating in a Slack channel whether the last sprint warrants a "minor" or a "patch" bump, you’re burning engineering hours on a solved problem. The history of your project shouldn't live in your head; it should live in your Git metadata.

The disconnect usually happens because we treat commit messages like a scratchpad. "Fixed the thing" or "Update index.js" tells a coworker what you did in the moment, but it tells a machine absolutely nothing about the intent of that change. By adopting a standardized grammar for your commits, you turn your repository into a self-documenting engine that handles versioning and changelogs automatically.

The Grammar of Conventional Commits

Standardizing intent relies on a structured format. The industry favorite is Conventional Commits, which provides a lightweight set of rules for creating an explicit commit history.

The structure is simple:

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]

When you use this, you aren't just being tidy; you're providing a signal. A feat: type signals a MINER version bump (1.1.0). A fix: type signals a PATCH (1.0.1). A BREAKING CHANGE: footer (or a ! after the type) signals a MAJOR bump (2.0.0).

Real-world examples

Instead of a generic message, you get specific:

# A new feature (Minor bump)
git commit -m "feat(api): add support for OAuth2 providers"

# A bug fix (Patch bump)
git commit -m "fix(ui): prevent button overflow on mobile devices"

# A breaking change (Major bump)
git commit -m "feat(auth)!: remove support for legacy API keys"

The ! in that last example is the "Semantic Intent" in action. It’s a loud, clear signal to your CI/CD pipeline that the world is about to break for someone, and the version number needs to reflect that.

Why "Chore" and "Docs" Matter

I used to hate the chore: or test: prefixes. They felt like extra typing for no reason. But here’s the magic: because these types don't affect the production logic, a versioning engine can ignore them.

If you commit ten test: updates and five docs: tweaks, your automated system knows it doesn't need to trigger a new release. You’ve successfully filtered the noise out of your release cycle.

Automation: Making it Work

Once your team is writing commits with semantic intent, you can hook them into tools like semantic-release or standard-version. These tools parse your Git log since the last tag, look at the "highest" priority commit type, and do the heavy lifting for you.

Imagine a GitHub Action that triggers on a merge to main:

1. It analyzes the commits.
2. It sees a feat:.
3. It determines the next version should be 1.4.0.
4. It updates package.json.
5. It generates a CHANGELOG.md by grouping all feat and fix messages.
6. It tags the repo and publishes the release.

Zero human intervention. Zero "Oh wait, I forgot to update the version" commits.

The "Squash" Gotcha

There is a catch. If your team does "Squash and Merge," the individual commit messages in a feature branch disappear. If you have five fix: commits and one feat:, but your final PR title is WIP: working on stuff, your automation will break.

The fix: Your PR title must follow the convention. Most modern platforms (GitHub, GitLab) allow you to use the PR title as the final commit message when squashing. Make the PR title the "Source of Truth" for semantic intent.

Stop Guessing, Start Signalling

Standardizing commit grammar feels bureaucratic for about three days. Then, the first time you see a perfectly formatted changelog generated without you lifting a finger, you'll never go back.

Software is complex enough. Don't make the version number another thing you have to "remember." Let the grammar do the work.