commitlint: стандарт коммитов

commitlint — инструмент, проверяющий сообщения коммитов на соответствие Conventional Commits или другому заданному стандарту.

Зачем нужно

История Git с сообщениями «fix», «wip», «правки» бесполезна при ревью и диагностике. Conventional Commits (feat:, fix:, docs:) структурирует историю и позволяет автоматически генерировать CHANGELOG и версии (semver) через инструменты вроде semantic-release. commitlint принудительно применяет этот стандарт в команде.

Где используется

  • Командные проекты с обязательным стилем коммитов
  • CI/CD пайплайны с автоматическим версионированием
  • Open source репозитории
  • В паре с Husky (хук commit-msg)

Conventional Commits

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

[optional body]

[optional footer]

Примеры:
feat(auth): add JWT refresh token support
fix(api): handle 429 Too Many Requests gracefully
docs(readme): update installation instructions
refactor(user): extract validation to separate module
test(auth): add integration tests for login flow
chore(deps): update eslint to v9
build(docker): optimize production Dockerfile

Типы коммитов

feat     — новая функциональность (→ MINOR в semver)
fix      — исправление бага (→ PATCH в semver)
docs     — изменения документации
style    — форматирование (не логика)
refactor — рефакторинг без изменения функционала
perf     — оптимизация производительности
test     — добавление/изменение тестов
build    — изменения системы сборки (webpack, docker)
ci       — изменения CI/CD конфигурации
chore    — прочие изменения (зависимости, инструменты)
revert   — отмена предыдущего коммита

BREAKING CHANGE: в footer → MAJOR в semver

Установка и настройка

# Установка
npm install --save-dev @commitlint/cli @commitlint/config-conventional

# Конфигурация
echo "export default { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js
// commitlint.config.js — кастомизация
export default {
  extends: ['@commitlint/config-conventional'],
  rules: {
    // Разрешить только определённые типы
    'type-enum': [2, 'always', [
      'feat', 'fix', 'docs', 'style', 'refactor',
      'perf', 'test', 'build', 'ci', 'chore', 'revert'
    ]],
    // Максимальная длина заголовка
    'header-max-length': [2, 'always', 100],
    // scope в lowercase
    'scope-case': [2, 'always', 'lower-case'],
    // Не обязательный scope
    'scope-empty': [0],
  },
};

Интеграция с Husky

# Создаём commit-msg хук
echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg
chmod +x .husky/commit-msg

Ручная проверка

# Проверить последний коммит
npx commitlint --from HEAD~1 --to HEAD

# Проверить конкретное сообщение
echo "fix: correct typo in README" | npx commitlint

# Проверить с подробностями
echo "bad commit message" | npx commitlint --verbose

Частые ошибки

  • Нет scope у feat/fix — можно, но лучше добавлять (feat(auth):)
  • Заглавная буква в description — fix: Fixed bugfix: fix bug
  • Точка в конце description — fix: fix bug. нарушает стандарт
  • Слишком длинное описание в одну строку — переносите в body
  • Merge commit не соответствует стандарту — commitlint можно настроить игнорировать их

Связанные темы

Ресурсы