Автоматизация версионирования: Conventional Commits и Keep a Changelog
Эта статья поможет вам навести порядок в истории разработки: от оформления коммитов до автоматической генерации журналов изменений (Changelog).
Conventional Commits - Соглашение о коммитах
Conventional Commits - спецификация для оформления сообщений git-коммитов. Она делает историю проекта понятной не только людям, но и программам.
Структура сообщения
По стандарту сообщение состоит из 3 частей:
- Заголовка
- Тела
- Футера.
<тип>[необязательная область]: <описание>
[необязательное тело]
[необязательный футер]Заголовок(обязательно) - первая строка, до 72 символов.
В ней указывается:
- Тип изменений - новый функционал, фикс бага и т.д.
- Область - необязательно, контекст изменений:
auth,api,profile-page… - Описание - краткий лог изменений, в повелительном наклонении(например, add, а не added, или в русском языке - совершенный вид добавить, а не добавил).
Далее будет приведена таблица основных типов изменений и как они влияют на версирование проекта.
| Тип | Что означает | Влияние на версию (SemVer) |
|---|---|---|
feat | Новая функциональность (Feature) | Minor (0.1.0 → 0.2.0) |
fix | Исправление ошибки | Patch (0.1.0 → 0.1.1) |
docs | Изменения только в документации | Обычно нет (или Patch) |
style | Правки форматирования, пробелы (не меняет логику) | Нет влияния |
refactor | Изменение кода, которое не правит баг и не добавляет фичу | Обычно нет |
perf | Изменения для улучшения производительности | Patch |
test | Добавление или изменение тестов | Нет влияния |
chore | Обновление зависимостей, рутинные задачи | Нет влияния |
Если нужно изменить major в версии (major.minor.patch), то к типу добавляется !. |
Тело (Body) — Необязательно
Это основной блок текста, который отделяется от заголовка пустой строкой. Используется для детального объяснения причин и сути изменений.
- Назначение: Описать «почему» сделано изменение и «как» оно работает (если это не очевидно). Здесь можно указать на контраст с предыдущим поведением кода.
- Форматирование: Обычно ограничивается шириной в 72 символа для удобного чтения в терминале.
- Стиль: Можно использовать маркированные списки и несколько абзацев. Важно сохранять фокус на технической ценности.
Футер (Footer) — Необязательно
Нижняя часть коммита, которая также отделяется пустой строкой от тела (или от заголовка, если тела нет). Используется для метаданных и связи с внешними инструментами.
- BREAKING CHANGE: Самый важный элемент футера. Начинается со слов
BREAKING CHANGE:(с двоеточием и пробелом), после чего идет описание того, что именно сломает совместимость. Это триггер для смены Major версии. - Связь с задачами (Refs): Здесь указываются ссылки на тикеты в Jira, GitHub Issues или другие задачи.
- Пример:
Fixes: #452,Closes: PROJECT-123.
- Пример:
- Формат: Обычно строится по принципу
Ключевое-слово: значение(например,Co-authored-by: Name <email>).
Пример правильного сообщения о коммите:
feat(api): добавить поддержку OAuth2 для авторизации <-- Заголовок
Мы переходим с базовой авторизации на OAuth2, так как это <-- Тело
безопаснее и позволяет интегрироваться с внешними сервисами.
Изменены эндпоинты /login и /refresh.
BREAKING CHANGE: старый метод AuthBasic больше не поддерживается. <-- Футер (Major)
Используйте заголовок Authorization: Bearer <token>.
Closes: #102, #105 <-- Футер (Ссылки)Инструменты для правильного заполнения
Для vscode:
- Conventional Commits (автор vivaxy)
- Как работает:
Добавляет иконку в панель Git или вызывается через
Ctrl+Shift+P. Он по очереди спрашивает: тип, область, описание, есть ли Breaking Change. - Плюс: Автоматически подставляет нужные префиксы и форматирует сообщение.
- Как работает:
Добавляет иконку в панель Git или вызывается через
- GitLens Это «комбайн» для Git. В нем нет прямого мастера Conventional Commits, но можно настроить Commit Templates (шаблоны), которые будут подставляться в поле ввода сообщения.
Для терминала:
Даже с расширениями можно случайно написать git commit -m "fix fast". Чтобы этого избежать, используют «контролеров».
- Commitlint Это линтер для сообщений. Он проверяет текст коммита на соответствие стандарту. Если ты забыл двоеточие или написал непонятный тип, он выдаст ошибку.
- Husky
- Инструмент для создания Git-хуков. Обычно его используют вместе с Commitlint.
- Сценарий: Ты жмешь Enter после коммита → Husky запускает Commitlint → Если сообщение плохое, коммит отменяется с подсказкой, что исправить.
Использование в проекте на nodejs:
npm install --save-dev @commitlint/config-conventional @commitlint/cli husky
# Создаст папку .husky, не забудьте добавить в gitignore и dockerignore
npx husky init Настройка Commitlint
Создать файл конфигурации .commitlintrc.json в корне проекта. Он скажет линтеру, что мы используем стандарт Conventional Commits.
{
"extends": ["@commitlint/config-conventional"]
}Создание хука (перехватчика)
Теперь нужно сказать Husky: «Перед тем как завершить коммит, проверь сообщение через commitlint».
Необходимо создать файл .husky/commit-msg и добавь туда команду проверки:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx --no -- commitlint --edit "$1"Использование в проекте на python:
pip install pre-commitЕсли используется uv просто пишем:
uv add --dev pre-commitСоздаем файл .pre-commit-config.yaml:
repos:
- repo: https://github.com/compilerla/conventional-pre-commit
rev: v3.1.0
hooks:
- id: conventional-pre-commit
stages: [commit-msg]
args: []Активируем хук:
pre-commit install --hook-type commit-msg
# или
uv tool run pre-commit install --hook-type commit-msgИтог:
Таким образом наши коммиты будут автоматически проверяться на корректность заполнения commit message.
Keep a Changelog
Хороший журнал изменений пишется для людей. В качестве стандарта здесь будет описан Keep a Changelog 1.1.0.
Основные правила:
- Свежие версии — сверху.
- Группировка изменений по категориям:
Added,Changed,Fixed,Removed. - Версии должны быть ссылками на сравнение (Diff).
Группы изменений (Секции)
Все изменения внутри версии делятся на 6 стандартных категорий:
Added— для новых функций.Changed— для изменений в существующей функциональности.Deprecated— для функций, которые скоро будут удалены.Removed— для функций, удаленных в этой версии.Fixed— для любых исправлений ошибок.Security— в случае исправления уязвимостей.
Пример корректного заполнения
Вот как выглядит идеально оформленный CHANGELOG.md по версии 1.1.0:
# Changelog
Все заметные изменения в этом проекте будут описаны в этом файле.
Формат основан на [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
и этот проект придерживается [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.1.0] - 2026-01-17
### Added
- Новый класс `UserManager` для обработки профилей пользователей.
- Метод `verify_email` в API аутентификации.
- Возможность экспорта отчетов в формате PDF.
### Changed
- Обновлена логика кэширования: теперь используется Redis вместо локальной памяти.
- Оптимизирован SQL-запрос в функции `get_stats`, что ускорило загрузку на 30%.
### Fixed
- Исправлена ошибка валидации пароля при регистрации (ранее пропускал пустые строки).
- Решена проблема с утечкой памяти в фоновом воркере.
## [1.0.1] - 2026-01-10
### Fixed
- Исправлен баг с отображением даты в футере сайта.
## [1.0.0] - 2026-01-01
### Added
- Первый стабильный релиз проекта.
- Базовая система авторизации (JWT).
- CRUD для работы с заметками.
[1.1.0]: https://github.com/user/project/compare/v1.0.1...v1.1.0
[1.0.1]: https://github.com/user/project/compare/v1.0.0...v1.0.1
[1.0.0]: https://github.com/user/project/releases/tag/v1.0.0
Автоматизация через git-cliff:
git-cliff — это генератор чейнджлогов на Rust.
Установка на nodejs
npm install -g @orhun/git-cliff
# или в проект
npm install --save-dev @orhun/git-cliffДобавьте в package.json
"scripts": { "changelog": "git-cliff -o CHANGELOG.md" }Установка на python
pip install git-cliff
# или в uv
uv add --dev git-cliff
Настройка шаблона (cliff.toml)
Этот конфиг строго следует стандарту Keep a Changelog и убирает лишние эмодзи и метаданные.
[changelog]
header = """
# Changelog
Все заметные изменения в этом проекте будут описаны в этом файле.
Формат основан на [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
и этот проект придерживается [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
"""
body = """
{% if version %}\
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
## [Unreleased]
{% endif %}\
{% for group, commits in commits | group_by(attribute="group") %}
### {{ group }}
{% for commit in commits %}
- {{ commit.message | upper_first }}\
{% if commit.body %}
{{ commit.body | indent(prefix=" ") }}\
{% endif %}
{% endfor %}
{% endfor %}
"""
footer = """
"""
trim = true
render_always = true
[git]
conventional_commits = true
trim_meta = true
filter_unconventional = true
sort_commits = "newest"
commit_parsers = [
{ message = "^Initial commit", group = "Added" },
{ message = "^feat", group = "Added" },
{ message = "^fix", group = "Fixed" },
{ message = "^doc", group = "Added" },
{ message = "^perf", group = "Changed" },
{ message = "^refactor", group = "Changed" },
{ message = "^style", group = "Changed" },
{ message = "^test", group = "Changed" },
{ message = "^chore", group = "Changed" },
{ message = "^revert", group = "Fixed" },
]Использование Добавьте скрипт в свой проект:
- В
package.json:"changelog": "git-cliff -o CHANGELOG.md" - В терминале (Python/uv):
uv run git-cliff -o CHANGELOG.md
Автоматическое управление версиями
Чтобы не менять версию в package.json или pyproject.toml вручную, используются инструменты, которые анализируют ваши коммиты и сами решают: поднять Patch, Minor или Major.
Для Node.js
Release-it — самый популярный инструмент в экосистеме JS.
Установка:
npm install --save-dev release-itНастройка (.release-it.json):
{
"hooks": {
"before:init": "npm test",
"after:bump": "npx git-cliff -o CHANGELOG.md && git add CHANGELOG.md",
"after:release": "echo Successfully released ${version}."
}
}Теперь при запуске npx release-it программа сама обновит версию, запустит git-cliff, создаст коммит и повесит тег.
Разбор конфига:
"before:init": "npm test"Это пре-проверка. Хук срабатывает в самом начале, еще до того, как инструмент что-либо изменит в проекте.- Что делает: Запускает вашу тестовую среду.
- Зачем это нужно: Если тесты упадут (команда вернет ненулевой код ошибки), процесс релиза немедленно прервется. Это страховка от того, чтобы вы случайно не выпустили в релиз сломанный код.
"after:bump": "npx git-cliff -o CHANGELOG.md && git add CHANGELOG.md"Это этап документирования. Хук срабатывает сразу после того, какrelease-itобновил версию вpackage.json(этот процесс называется bump), но до того, как будет создан Git-коммит релиза.- Что делает:
npx git-cliff -o CHANGELOG.md— вызывает генератор чейнджлогов. Он читает ваши коммиты и записывает изменения в файл согласно вашему шаблону.&& git add CHANGELOG.md— добавляет обновленный файл в индекс Git (staging area).
- Зачем это нужно: Благодаря этому обновленный
CHANGELOG.mdпопадет в тот же самый коммит, в котором изменилась версия вpackage.json. История будет выглядеть чистой и логичной.
- Что делает:
"after:release": "echo Successfully released ${version}."Это завершающий этап. Хук срабатывает, когда всё уже успешно завершено: версия поднята, тег создан, изменения отправлены в удаленный репозиторий (push).- Что делает: Просто выводит в консоль сообщение об успехе.
- Переменная
${version}: Это встроенная переменнаяrelease-it. Вместо нее подставится актуальный номер версии (например,2.0.0). - Зачем это нужно: Для уведомления пользователя или для интеграции с другими системами (например, отправка сообщения в Slack или Telegram через
curl).
Для Python
В Python (особенно с использованием uv) отлично подходит bump-my-version.
Установка:
uv add --dev bump-my-versionНастройка (pyproject.toml):
[tool.bumpversion]
current_version = "0.1.0"
parse = "(?P<major>\\d+)\\.(?P<minor>\\d+)\\.(?P<patch>\\d+)"
serialize = ["{major}.{minor}.{patch}"]
search = "version = \"{current_version}\""
replace = "version = \"{new_version}\""
files = ["pyproject.toml"]
commit = true
tag = true
# Аналог "after:bump" из nodejs
# Этот хук запустится ПОСЛЕ обновления версии в файлах, но ДО создания коммита
pre_commit_hooks = [
"git-cliff --tag v{new_version} -o CHANGELOG.md",
"git add CHANGELOG.md"
]Разбор конфига:
В bump-my-version (и обновленном bump2version) логика работы с хуками выглядит так:
pre_commit_hooks:
Выполняются сразу после того, как утилита изменила версию в pyproject.toml, но до выполнения команды git commit.
- git-cliff --tag v{new_version} -o CHANGELOG.md: Генерирует лог, подставляя вместо {new_version} ту версию, на которую вы переходите.
- git add CHANGELOG.md: Обязательный шаг. Если не добавить файл в индекс, bumpversion создаст коммит только с измененным pyproject.toml, а изменения в логе останутся “незакоммиченными”.
Команды для релиза:
# Для патча (0.1.0 -> 0.1.1)
uv run bump-my-version bump patch
# Для минорной версии (0.1.0 -> 0.2.0)
uv run bump-my-version bump minor
# Для майорной версии (1.0.0 -> 2.0.0)
uv run bump-my-version bump major