docs: i really like conventional commits
Created by brian on
A client developer recently introduced me to Conventional Commits. I was skeptical. It seemed like a chore that added friction to my workflow.
It took less than an hour to accept that I was mistaken. This is the way. The learning curve reminded me a lot of my first day working with Tailwind CSS. I had the docs open as a pinned tab for a while, but the syntax (feat, fix, refactor) quickly becomes muscle memory.
The structure forces me to pause and consider the intent of my code before committing. If I can't effectively describe a commit with a conventional message, I take it as a sign that I need to break it down into smaller commits. The result is significantly better historical documentation for my future self and the rest of the team.
The Wild West
I am a front-end developer at a digital agency, where I regularly work with client developers and contractors. Without strict standards, a project's git history can quickly end up looking more like the aftermath of a brawl at the Long Branch Saloon.
You have probably seen a log like this before. It is impossible to parse, impossible to search, and helpful to absolutely no one:
text* 8a9b0c Merge branch 'feature/login-fix' into develop |\ | * 7d6e5f wip | * 4g3h2i fixed it | * 1j0k9l styling updates | * 5n4m3o oops |/ * 3m2n1o updates
Insert confused-travolta.gif here.
Conventional Commits (CC) brings sanity to this chaos. But it is not just about strict rules; it is about flexibility. Here are a couple different ways to apply CC to a real-world scenario that I recently encountered.
Scenario 1: The Timeboxed Sweep
Imagine a Jira task (JIRA-123) that asks you to spend 4 hours tackling as many issues as possible from an accessibility audit. You are moving fast, touching a dozen files, fixing contrast ratios, adding alt tags, and adjusting focus states.
Your PR history might look like this:
text7d6e5f fix: adjust contrast on primary buttons 4g3h2i fix: add missing alt tags to hero images 1j0k9l style: update focus ring color 5n4m3o fix: correct tab order in footer
When it is time to merge, you squash that entire PR into a single, semantic commit. You scope it to the Jira ticket so the main branch history remains pristine:
texta1b2c3d fix(JIRA-123): resolve high priority accessibility audit issues b2c3d4e feat(JIRA-122): add avatar upload c3d4e5f chore(JIRA-121): update dependencies
Insert willem-dafoe-looking-up.gif here.
Scenario 2: The Curated List
Now, take that same accessibility audit, but imagine a Business Analyst has broken it down into specific, actionable tasks. You have JIRA-456 for navigation contrast and JIRA-457 for form labels.
In this scenario, squashing would actually destroy value. You want to preserve the granularity. You want to know that this specific commit fixed the nav, and that specific commit fixed the form.
Here, you would not squash. Instead, you ensure each commit message follows the standard, preserving the detailed history on the main branch:
texti7j8k9l fix(JIRA-457): add aria-labels to search input fields e4f5g6h fix(JIRA-456): increase contrast ratio on navigation links b2c3d4e feat(JIRA-454): add avatar upload
Insert citizen-kane-clapping.gif here.
Flexibility is key
This is the most important takeaway: Conventional Commits does not dictate your workflow.
It does not care if you squash or if you rebase. It does not care if you map to one Jira ticket or ten. It simply provides a schema for your metadata. Whether you choose the "Timeboxed Sweep" or the "Curated List" approach is entirely up to your judgment as a developer. The goal is simply to leave the campsite cleaner than you found it.
To enforce this standard, I now use Husky paired with @commitlint/config-conventional. This toolchain automatically rejects any message that doesn't follow the rules, ensuring the git log remains clean without manual oversight.
Beauty in simplicity
My favorite quote and guiding philosophy as a software engineer is:
Simplicity is the ultimate sophistication.
Convention Commits excels where others (like GitFlow) stumbled because it's beautifully simple, has a tiny learning curve, and is easy to enforce.
Last updated