Git Hooks Предкоммит, предпуш и предотвращение плохого кода на пороге
Скрипты предварительного выполнения (pre-commit, commit-msg и pre-push) — это скрипты на языке shell, которые выполняются до того, как git записывает коммит или отправляет пуш. Вот как их можно настроить, чтобы обнаруживать ошибки проверки кода, плохие сообщения коммитов и утечки секретов — с реальными примерами, которые вы можете вставить сегодня.
Git включает в себя хуки — скрипты на шелле, которые запускаются в определённые моменты вашего рабочего процесса. Большинство репозиториев имеют их, но они лежат в состоянии ожидания в .git/hooks/ как .sample файлах. Большинство разработчиков игнорируют их, пока не возникнет повреждённый коммит или утечка ключа API, и они пожелают, чтобы не игнорировали их.
Это касается трёх хуков, которые стоит настроить на каждом проекте: pre-commit, commit-msgи pre-push. Каждый из них ловит определённый класс ошибок. Каждый из них — это скрипт на шелле, который вы можете вставить и использовать прямо сейчас.
Где находятся хуки
Каждый репозиторий Git имеет каталог .git/hooks/ . Выполните команду ls .git/hooks/ и вы увидите образцы файлов. Git игнорирует всё, что имеет суффикс .sample . Чтобы активировать хук, удалите суффикс и сделайте его исполняемым:
cp .git/hooks/pre-commit.sample .git/hooks/pre-commit
chmod +x .git/hooks/pre-commit
Соглашение простое: выход 0 и Git продолжает работу. Выход с ненулевым значением и Git останавливается, выводя то, что вы написали в stderr.
pre-commit: ваш наиболее ценный хук
Pre-commit запускается после того, как вы вводите git commit но до того, как объект коммита будет записан. Он не может видеть сообщение коммита — оно ещё не было записано. Что он можете делает — проверяет подготовленные файлы и отказывается, если что-то выглядит неправильно.
Ключевая деталь: используйте git diff --cached --name-only чтобы получить только файлы, которые вы действительно подготовили. Проверка всего проекта на каждом коммите является медленной и выявляет проблемы, которые вы не внесли.
Пример проверки (ESLint)
#!/bin/sh
# Lint only staged JS files
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep '\.js$')
if [ -z "$STAGED_FILES" ]; then
exit 0
fi
echo "Running ESLint on staged files..."
echo "$STAGED_FILES" | xargs ./node_modules/.bin/eslint
if [ $? -ne 0 ]; then
echo "ESLint failed. Fix errors before committing."
exit 1
fi
exit 0
The --diff-filter=ACM флаг пропускает удалённые файлы — нет смысла пытаться проверять что-то, что вы только удалили.
Пример сканирования секретов
Простой скан-паттерн, который выявляет очевидные ошибки — встроенные ключи API, пароли в конфигурационных файлах, которые были случайно включены в коммит:
#!/bin/sh
# Block commits with obvious secrets
PATTERNS="(AWS_SECRET|api_key\s*=|password\s*=|PRIVATE KEY)"
if git diff --cached | grep -qiP "$PATTERNS"; then
echo "Potential secret detected in staged changes. Aborting commit."
exit 1
fi
exit 0
Для проектов, выходящих за рамки простых примеров, используйте специализированный сканер. detect-secrets от Yelp отлично подходит в качестве хука pre-commit — он сохраняет базовый файл, чтобы старые отмеченные строки не блокировали каждый коммит. trufflehog лучше подходит для сканирования истории после того, как она была создана или для выполнения в CI.
commit-msg: обеспечивает формат сообщения
Этот хук получает один аргумент: путь к временному файлу, содержащему ваше черновое сообщение коммита. Прочитайте его, проверьте, и выйдите с кодом 1, чтобы отклонить. Файл доступен для записи — вы можете нормализовать сообщение вместо того, чтобы отклонять его, хотя это удивляет людей в первый раз.
Обеспечение Conventional Commits формата — наиболее распространённое применение. Преимущество — автоматически генерируемые журналы изменений, понятный git log вывод и CI-пайплайны, которые могут анализировать типы коммитов и определять, что нужно выпускать:
#!/bin/sh
COMMIT_MSG_FILE=$1
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
# type(scope): description — scope is optional
PATTERN="^(feat|fix|chore|docs|style|refactor|test|perf|ci|build|revert)(\(.+\))?: .{1,72}"
if ! echo "$COMMIT_MSG" | grep -qP "$PATTERN"; then
echo ""
echo "Invalid commit message. Use Conventional Commits format:"
echo " type(scope): short description"
echo ""
echo "Valid types: feat, fix, chore, docs, style, refactor, test, perf, ci, build, revert"
echo "Example: feat(auth): add OAuth2 login flow"
echo ""
echo "Your message: $COMMIT_MSG"
exit 1
fi
exit 0
Это не поймёт корректно оформленное сообщение, которое всё равно несущественно, например fix: fix things. Это проблема культуры, а не инструментальной.
pre-push: последняя дверь перед origin
Pre-push запускается после того, как вызывается git push но до того, как данные отправляются на удалённый репозиторий. Он получает имя удалённого репозитория и URL через stdin. Здесь должны быть тесты — не линтер (который работает в pre-commit), а реальные тесты, которые проверяют поведение.
#!/bin/sh
echo "Running tests before push..."
npm test
if [ $? -ne 0 ]; then
echo "Tests failed. Push aborted."
exit 1
fi
exit 0
Одна жёсткая правда: если ваша тестовая среда занимает более 60–90 секунд, люди будут использовать --no-verify. Выполняйте только быстрые единичные тесты здесь. Интеграционные и E2E-тесты должны быть в CI, где медленные тесты допустимы. Хук, который слишком медленный, чтобы пропускать, хуже, чем отсутствие хука.
Пропуск хуков — и когда это допустимо
git commit --no-verify
git push --no-verify
Оба флага существуют для определённой цели. Хук, который блокирует горячую фиксацию, — это то, что может вызвать неприятие всего команды к хукам Git. Используйте --no-verify в случае, если есть законное обоснование: хук не работает с несвязанными файлами или в экстренной ситуации, где исправление имеет большее значение, чем проверка.
Если вы часто используете этот флаг, хуки требуют настройки. Наиболее распространённые причины: слишком медленная работа, сбой на файлах, которые не были изменены, или ложные срабатывания паттернов, которые вы ещё не устраняли.
Общие хуки в команде
.git/hooks/ находятся локально в каждом клоне — они намеренно не коммитируются в репозиторий. Две стратегии, чтобы хуки стали частью команды:
Вариант 1: core.hooksPath
Храните хуки в каталоге, который коммитируется (например, .githooks/), затем укажите Git на него:
git config core.hooksPath .githooks
Чтобы автоматизировать это для новых клонов, добавьте скрипт prepare в package.json — npm запускает его автоматически при npm install:
{
"scripts": {
"prepare": "git config core.hooksPath .githooks"
}
}
Сделайте скрипты исполняемыми, коммитируйте их, и каждый, кто клонирует и запускает npm install получит хуки, настроенные автоматически.
Вариант 2: Husky
Husky является стандартным выбором для проектов на JavaScript/Node. Он автоматически устанавливает хуки и создаёт для каждого хука отдельный файл в core.hooksPath Затем добавляйте хуки как простые скрипты на шелле: .husky/:
npx husky init
Husky 9 (выпущена в начале 2024 года) полностью убрала конфигурацию на JSON в пользу простых скриптов на шелле. Проще, чем в версиях v4/v8, для новых настроек, но миграция из Husky 4 — это разрушительное изменение, которое официальный гайд по миграции недооценивает — старый
echo "npm test" > .husky/pre-push
chmod +x .husky/pre-push
формат больше не работает вообще. Если вы обновляете существующий репозиторий, выделите время на это. .huskyrc Нестандартные репозитории на JavaScript лучше всего подойдут под подход
. Нет необходимости включать зависимость на Node только для управления хуками. core.hooksPath Проверяйте разницу перед запуском хука
показывает изменения, подготовленные к коммиту, в терминале. Когда вы сравниваете две версии конфигурационного файла или проверяете, что рефакторинг действительно изменил в нескольких редакциях, визуальная разница быстрее сканируется.
git diff --cached IO Tools’ Text Diff позволяет вставить две версии и увидеть, что изменилось — полезно, когда вы хотите проверить, что входит в коммит, до запуска хуков. Хуки Git — один из немногих инструментов автоматизации, которые полностью вписываются в ваш существующий рабочий процесс — без необходимости в аккаунте CI, без дополнительных сервисов, без затрат. Хук pre-commit, который отклоняет ошибку проверки, надёжен так же, как скрипт, который вы написали. Это особенность: вы можете прочитать, отладить и изменить его за минуту. Настройте три хука выше и вы закроете наиболее распространённый разрыв между «работает локально» и «работает на main».
Git Hooks: Pre-commit, Pre-push, и остановка плохого кода на пороге 2
Установите наши расширения
Добавьте инструменты ввода-вывода в свой любимый браузер для мгновенного доступа и более быстрого поиска
恵 Табло результатов прибыло!
Табло результатов — это интересный способ следить за вашими играми, все данные хранятся в вашем браузере. Скоро появятся новые функции!
Подписаться на новости
все Новые поступления
всеОбновлять: Наш последний инструмент был добавлен 16 Июня 2026
