Skip to content

Git Commit Guidelines

A clean Git history is a form of documentation. When every commit tells a clear, consistent story, git log becomes a powerful audit trail — one that any engineer can use to understand what changed, when, and why. This guide defines the commit message format used across all services in this monorepo.

All commit messages follow the Conventional Commits specification:

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

Every component plays a role:

ComponentRequired?Description
type✅ YesThe category of change (see table below)
scopeOptionalThe area of code affected
description✅ YesA short, imperative-mood summary
TypeWhen to Use
featA new feature visible to users or other services
fixA bug fix
perfA change that improves performance without altering behavior
refactorCode restructuring with no functional change
testAdding or updating tests
docsDocumentation-only changes
choreBuild system, dependency updates, tooling (no prod code change)
ciChanges to CI/CD pipeline configuration

The scope is optional but strongly encouraged. It helps engineers filter history for a specific module or feature area without grep.

Use the name of the affected module, controller, or feature — whichever is most meaningful:

feat(auth): add refresh token rotation
fix(orders): correct discount calculation for bundled items
refactor(users): extract permission check into separate service
docs(readme): update local setup instructions
chore(deps): bump TypeORM to 0.3.21

The description is the most important part. Follow these rules:

  1. Use the imperative mood — write as if completing the sentence “This commit will…”

    • add JWT-based authentication
    • added JWT-based authentication
    • adds JWT-based authentication
  2. Keep it under 72 characters — GitHub truncates longer subjects in the UI and git log --oneline

  3. Don’t end with a period

  4. Be specific — vague messages waste everyone’s time:

    • fix bug
    • update code
    • changes
    • fix(auth): resolve token expiration not being checked on refresh
Terminal window
feat(auth): add JWT-based stateful authentication
feat(orders): support discount codes in checkout flow
feat(notifications): send email on appointment confirmation
feat(iam): implement role-based permission assignment
Terminal window
fix(auth): resolve token expiration not enforced on refresh
fix(orders): correct total price when multiple discounts applied
fix(users): prevent duplicate email registration
fix(ws): reconnect WebSocket on authentication token refresh
Terminal window
refactor(users): extract permission validation into dedicated service
refactor(appointments): simplify availability conflict detection
test(orders): add unit tests for discount calculation edge cases
docs(architecture): add sequence diagram for auth flow
chore(deps): upgrade NestJS to v11 and TypeORM to 0.3.21
ci(github-actions): add lint check to PR workflow

For significant changes, add a body and optional footer after a blank line:

feat(iam): implement fine-grained resource-level permissions
Replace role-only authorization with a policy-based system that supports
contextual, resource-level permission checks. This is required for
compliance with the upcoming multi-tenant access control requirements.
Closes #142
Breaking-Change: RequirePermission decorator now requires explicit context

The body should explain why the change was made, not what it does — the diff shows the what.

❌ Bad CommitWhy It’s Bad✅ Better
fix bugNo scope, no description of what bugfix(auth): prevent login with expired session token
WIPMeaningless in shared historySquash before merging
small changesTells reviewers nothingrefactor(dto): simplify CreateOrderDTO field validation
URGENT FIXUrgency doesn’t belong in historyfix(orders): correct null check causing checkout crash
updateWhat was updated?docs(api): update response format for paginated endpoints

💡 Tip: If you’re struggling to write a short commit message, it’s often a sign the commit is doing too much. Consider splitting it into smaller, focused commits.

Before committing, verify:

  • Message follows type(scope): description format
  • Type is one of the approved types
  • Description uses imperative mood
  • Description is under 72 characters
  • No vague terms like “update”, “fix”, or “changes”
  • If it’s a breaking change, it’s noted in the footer