Для повідомлень комітів є два хуки:
prepare-commit-msg- викликається до відкриття редактора; може підготувати чи доповнити текст;commit-msg- викликається після введення повідомлення; може перевірити його і заборонити коміт.
Обидва отримують шлях до файла з повідомленням першим аргументом.
Перевірка Conventional Commits у commit-msg:
#!/bin/sh
pattern='^(feat|fix|docs|refactor|test|chore|perf|ci|build)(\([a-z0-9-]+\))?!?: .{1,72}$'
if ! head -1 "$1" | grep -qE "$pattern"; then
echo "Повідомлення не відповідає Conventional Commits:"
echo " feat(vacancies): add CSV export"
exit 1
fi
Номер задачі з назви гілки в prepare-commit-msg:
#!/bin/sh
# гілка feature/ABC-123-csv-export -> префікс [ABC-123]
case "$2" in merge|squash|commit) exit 0 ;; esac # не чіпати merge, squash і --amend
ticket=$(git branch --show-current | grep -oE '[A-Z]+-[0-9]+')
[ -n "$ticket" ] && ! grep -q "$ticket" "$1" && sed -i.bak "1s/^/[$ticket] /" "$1" && rm -f "$1.bak"
Другий аргумент - джерело повідомлення (message при -m, merge, squash, commit при --amend чи -c), щоб не дописувати префікс у службові повідомлення.
Готові інструменти:
- commitlint (Node) - правила для Conventional Commits, часто разом з Husky;
- CaptainHook має вбудовані дії для перевірки повідомлень (довжина рядків, регулярні вирази, загальноприйняті правила оформлення повідомлень);
- GrumPHP - задача
git_commit_message.
Чому перевірка потрібна і в CI: хук локальний, і git commit --no-verify його пропускає. Якщо від формату залежать змінлог і версіонування, перевіряйте повідомлення ще й у CI - або заголовок PR, якщо зливаєте через squash: тоді саме він стає повідомленням коміту в main.