{
  "uid": "cogitave.learn.commits-and-versioning.conventional-commits-in-depth",
  "kind": "moduleUnit",
  "href": "/modules/commits-and-versioning/conventional-commits-in-depth/",
  "title": "Conventional Commits in depth",
  "summary": "",
  "type": null,
  "products": [],
  "roles": [],
  "levels": [],
  "subjects": [],
  "headings": [
    "The type carries the meaning",
    "The scope narrows the where",
    "Two ways to mark a break",
    "commitlint enforces the shape - twice"
  ],
  "source": "Conventional Commits 1.0.0 is a small, strict grammar. The\n[commits-versioning standard](../../../../standards/docs/standards/commits-versioning.md)\nstates it in one line - `<type>[scope][!]: <desc>` - and everything you write in\nCogitave follows it. This unit unpacks each part.\n\n## The type carries the meaning\n\nThe **type** is the first token, and it is not decoration - it is what a machine\nreads. The standard fixes the allowed set:\n\n- **`feat`** - a new feature. Drives a **MINOR** version bump.\n- **`fix`** - a bug fix. Drives a **PATCH** bump.\n- **`build`, `chore`, `ci`, `docs`, `style`, `refactor`, `perf`, `test`,\n  `revert`** - everything else. These do not, on their own, bump the version.\n\nTwo types therefore move the version and the rest do not. That is the whole\nreason to choose the type deliberately: calling a bug fix a `chore` hides it from\nthe changelog and skips the patch release; calling a docs tweak a `feat` ships a\nversion bump nobody needed.\n\n## The scope narrows the where\n\nThe optional **scope** in parentheses says *where* the change lands -\n`feat(parser):`, `fix(auth):`. It is a grouping aid for humans and changelog\ntools; it does not change the version math. Use it when a repo has clear\nsub-areas, and keep the same scope names across commits so the history stays\ngrep-able.\n\n## Two ways to mark a break\n\nA breaking change is the one that bumps the **MAJOR** version, so it has to be\nunmistakable. The standard gives two markers, and you may use either or both:\n\n- a **`!`** before the colon - `feat(api)!: drop the v1 field`;\n- a **`BREAKING CHANGE:`** footer at the bottom of the message body.\n\nEither one tells the release engine this is a major change. Never smuggle a\nbreaking change in under `fix` or `feat` without the marker - the version it\nproduces would understate the impact, and downstream consumers would upgrade\ninto a break with no warning.\n\n> [!TIP]\n> A commit body and footers are still just text under the header line. Put the\n> `BREAKING CHANGE:` footer on its own paragraph at the end so both humans and\n> the tooling find it.\n\n## commitlint enforces the shape - twice\n\nNone of this is honour-system. **commitlint** with\n`@commitlint/config-conventional` validates every message against the grammar\nabove, and it runs in **two** places per the standard: the local `commit-msg`\nhook (wired through lefthook) and again in **CI**, which checks the PR's commits\nand title. A message such as `updated stuff` has no type prefix, so it is\nrejected at the hook before it is ever pushed - and if it somehow reaches the PR,\nCI rejects it again. The convention holds because the machine checks it every\ntime, on the way in and again at the gate.\n",
  "partOf": "cogitave.learn.commits-and-versioning",
  "durationInMinutes": 8,
  "quiz": null
}