Прекоммит-хуки в git

Помимо стандартов оформления кода, хорошей практикой является использование стандартных commit-сообщений в системе контроля версий (слава богу использование последних уже даже не обсуждается). Стандартные сообщения хороши как минимум по двум причинам:

  1. позволяют тебе легко ориентироваться в истории проекта
  2. являются первым шагом к качественной автоматизации процесса сборки/выкладки релизов

В каждой уважающей себя CVS есть механизм хуков (ловушек). А поскольку мы используем git, расскажу как эта задача решается там.

Хуки можно реализовать как на стороне клиента, так и на стороне сервера. У серверного решения есть существенный плюс - хуки будут работать для всех (на клиенте их можно игнорировать). Но есть и существенный недостаток - хук сработает только когда изменения будут запушены в “основной” репозиторий. До этого можно спокойно коммитить с какими хочешь сообщениями, потом придётся всё исправлять. Т.е. получается относительно долгая обратная связь, а я такие не люблю =).

Гораздо лучше, когда все проблемы можно исправить “на лету”, поэтому наш выбор - клиентские хуки. Хук представляет собой исполняем файл, который находится в папке .git/hooks:

$ls -1 .git/hooks/
applypatch-msg.sample
commit-msg.sample
post-update.sample
pre-applypatch.sample
pre-commit.sample
pre-rebase.sample
prepare-commit-msg.sample
update.sample

Как видишь, здесь есть примеры на все случаи жизни, а нашу задачу решает хук commit-msg. Работает он очень просто: получает на вход commit-сообщение (ну кто бы мог подумать?), и если он (хук) вернёт не 0, то коммит не состоится.

Теперь немного shell-магии. Берём первую строчку сообщения, для этого воспользуемся командой head:

var=`head -n 1 $1`

Будем проверять что сообщение начинается с одного из ключевых слов - add, fix или rft (refactoring). Проверять будем regexp-ом:

regex="(add|fix|rft) .+"

Ну и надо написать что-нибудь, чтобы объяснить горе-коммитеру, как надо писать сообщения:

message="[POLICY] Commit need to be '[add|fix|rft] message'"

Собрав всё это вместе получим:

#!/bin/sh

regex="(add|fix|rft) .+"
var=`head -n 1 $1`
message="[POLICY] Commit need to be '[add|fix|rft] message'"

if ! [[ "$var" =~ $regex ]]
then
  echo $message
  exit 1
fi

К сожалению, клиентские хуки придётся настраивать у каждого клиента, однако этот процесс можно частично автоматизоровать. Для этого кладём наши хуки в отдельный репозиторий, и при первичной настройке нужно будет сделать клон этого репозитория и прописать симлинки. При обновлении хуков, достаточно будет просто обновить локальный репо с хуками.

git clone our-pretty-hooks
ln our-pretty-hooks/commit-msg our-project-repo/.git/hooks/commit-msg

Кстати, никто не мешает продублировать хуки и на сервере, но лично мне кажется, что использование подобных практик должно быть добровольным.

comments powered by Disqus