Git-хуки
Git-хуки — скрипты, запускаемые автоматически в жизненном цикле Git для линтинга, тестирования и валидации. Пример pre-commit хука.
Что такое Git-хуки
Git-хуки — это скрипты, которые Git запускает автоматически при наступлении определённых событий: создании коммита, слиянии, пуше и других. Они позволяют встраивать пользовательские действия в жизненный цикл Git: запускать линтер перед каждым коммитом, проверять формат сообщения коммита или блокировать пуш при провале тестов. Именно с помощью хуков команды внедряют локальные проверки качества кода — ещё до того, как плохой код покинет машину разработчика.
На этой странице рассказывается, где хранятся хуки, в чём разница между клиентскими и серверными хуками, какие хуки наиболее полезны с рабочими примерами, как хук прерывает операцию, как его обойти и как делиться хуками в команде.
Где хранятся хуки
В каждом репозитории есть директория .git/hooks, содержащая примеры скриптов с суффиксом .sample. Чтобы активировать хук, добавьте исполняемый скрипт с точным именем хука и без расширения:
ls .git/hooks
# pre-commit.sample commit-msg.sample pre-push.sample ...Удалите суффикс .sample (или создайте файл заново) и сделайте его исполняемым:
chmod +x .git/hooks/pre-commitХук может быть написан на любом языке при условии, что файл является исполняемым и начинается с подходящей строки shebang (#!/bin/sh, #!/usr/bin/env python3, #!/usr/bin/env node и т. д.). Git важно лишь одно: файл должен называться точно так же, как известный хук, быть исполняемым и возвращать код завершения.
Клиентские и серверные хуки
- Клиентские хуки выполняются на вашей машине при локальных операциях — создании коммита и пуше. Они отлично подходят для линтинга и тестирования.
- Серверные хуки (например,
pre-receiveиpost-receive) запускаются на удалённом репозитории при получении пуша — полезны для централизованного применения политик.
Наиболее часто используются клиентские хуки:
| Хук | Срабатывает | Типичное применение |
|---|---|---|
pre-commit | До создания коммита | Линтинг и тестирование проиндексированных файлов; прерывание при ошибке. |
prepare-commit-msg | До открытия редактора сообщения | Вставка шаблона или номера задачи. |
commit-msg | После написания сообщения | Применение соглашения о формате сообщений. |
post-commit | После завершения коммита | Отправка уведомления; не влияет на коммит. |
pre-push | До отправки пуша | Запуск полного набора тестов в качестве финальной проверки. |
Как хук прерывает операцию
Весь механизм управления строится на коде завершения. Для хуков типа «pre-» (pre-commit, pre-push, commit-msg и др.):
- Завершение с кодом
0→ хук одобрил операцию, и Git продолжает выполнение. - Завершение с ненулевым кодом → Git отменяет операцию. Коммит не создаётся, пуш не отправляется.
Хуки типа «post-» (post-commit, post-merge и др.) выполняются после того, как действие уже завершено, поэтому их код завершения игнорируется — они не могут ничего отменить. Используйте их для уведомлений, но не для валидации.
Пример pre-commit хука
Этот хук pre-commit запускает линтер проекта и блокирует коммит при обнаружении проблем. Поскольку sh прерывает выполнение при сбое команды благодаря set -e, дополнительная проверка $? не нужна:
#!/bin/sh
set -e
echo "Running lint..."
npm run lintЕсли npm run lint завершается с ненулевым кодом, set -e передаёт этот код дальше и коммит прерывается. Если предпочтительнее пользовательское сообщение, проверьте результат явно:
#!/bin/sh
if ! npm run lint; then
echo "Lint failed — commit aborted. Fix the issues and try again."
exit 1
fiСохраните файл как .git/hooks/pre-commit и выполните chmod +x .git/hooks/pre-commit.
Пример commit-msg хука
Хук commit-msg получает один аргумент: путь к временному файлу с предлагаемым сообщением. Прочитайте этот файл, проверьте его и завершите с ненулевым кодом для отклонения. Данный пример применяет соглашение в стиле Conventional Commits:
#!/bin/sh
# $1 is the path to the file containing the commit message
message=$(head -n1 "$1")
pattern='^(feat|fix|docs|style|refactor|test|chore): .+'
if ! echo "$message" | grep -Eq "$pattern"; then
echo "Commit message must start with feat:, fix:, docs:, etc."
exit 1
fiОбход хука
Хук — это страховочная сетка, а не стена. Если вам действительно нужно пропустить хуки pre-commit и commit-msg для одной операции, используйте флаг --no-verify:
git commit --no-verify -m "WIP: skip checks"
git push --no-verifyИспользуйте это редко — обход линтера открывает путь некачественному коду в историю.
Общий доступ к хукам в команде
Поскольку директория .git/hooks не попадает в коммиты, хуки не передаются вместе с клоном. Команды решают это, храня хуки в отслеживаемой директории и направляя на неё Git:
git config core.hooksPath .githooksТеперь Git ищет хуки в отслеживаемой директории .githooks/ вместо .git/hooks. Зафиксируйте скрипты там, сделайте их исполняемыми, и каждый участник команды получит их после выполнения той же команды git config (или после того, как это сделает скрипт настройки). Подробнее о хранении настроек репозитория — в разделе Git config.
Такие инструменты, как Husky, автоматизируют именно это для JavaScript-проектов, подключая общие хуки во время установки. Для политик, которые нельзя позволить обойти с помощью --no-verify, применяйте серверные хуки или защиту веток на платформе хостинга — ведь клиентские хуки всегда остаются на машине разработчика.
Связанные темы
- git commit — команда, которую оборачивают хуки pre-commit и commit-msg.
- Подпись коммитов — подтверждение авторства, часто используется вместе с хуками.
- Git config — место хранения
core.hooksPathи других настроек. - Git alias — сокращения для команд, запускаемых хуками.