Git-hooks без боли: расследуем Husky + lint-staged

Воскресенье. 10:02. Твой коллега Лёша делает «быстрый» хот-фикс, жмёт git commit -m "hotfix" — и получает стену ошибок ESLint. Паника: «Почему линтер рушит мой рабочий день?»
Разберёмся, что происходит, настроим Husky v9 и lint-staged 15, чтобы — вместо фрустрации — автоматом править код до коммита и пуша, и при этом не тормозить работу новичков.


1. Что такое Git-hook и зачем он нужен

Git-hook — это скрипт, который Git запускает в определённый момент жизненного цикла (pre-commit, pre-push, post-merge и т. д.).
Преимущества:

  • ловит опечатки до CI;
  • держит репозиторий «чистым» — ни одного кривого форматирования;
  • экономит время ревьюеров (фокус на логике, а не на пробелах).

2. Почему Husky v9 считается стандартом-2025

  • Лёгкий — всего ≈ 2 kB, без зависимостей;
  • Кросс-платформенный — Windows, macOS, Linux;
  • Использует core.hooksPath, не трогая системные файлы;
  • Поддерживает все 13 клиентских Git-хуков из коробки.

Важно: Husky v9 перешёл на «zero-install» — он работает, даже если у коллеги нет npm i в глобальном кэше.


3. lint-staged: ленимся правильно

lint-staged запускает задачи только для файлов, добавленных в индекс, а значит:

  • линтеры обрабатывают десяток файлов, а не весь проект;
  • проверки занимают секунды, не минуты;
  • отпадает соблазн отключать линтер «пока что».

4. Пошаговая установка (Node ≥ 18, Git ≥ 2.40)

4.1 Инициализация Husky

# 1) ставим пакеты
pnpm add -D husky@^9 lint-staged@^15

# 2) активируем Husky
npx husky install
# → создаётся папка .husky и настраивается core.hooksPath

Добавь строку в package.json, чтобы у новичков Husky включался сам:

{
"scripts": {
"prepare": "husky install"
}
}

4.2 Создаём pre-commit-hook

npx husky add .husky/pre-commit "pnpm lint-staged"

В файле .husky/pre-commit уже прописана команда; права (chmod +x) выставлены автоматически.

4.3 Конфиг lint-staged

lint-staged.config.js (TypeScript-тайпинги появились в v15) — удобно для автодополнения.

/** @type {import('lint-staged').Configuration} */
export default {
// Форматируем всё Prettier
"*.{js,ts,jsx,tsx,json,md}": ["prettier --write"],
// Лечим + проверяем только изменённые TS/JS
"*.{js,ts,jsx,tsx}": ["eslint --fix", "eslint"],
};

5. Что делать, если hook «долго думает»

  1. Проверь фильтры — убедись, что не указал "*" без исключений (раньше так ошибались и гоняли линтер по всему проекту).
  2. Отладка — запускай HUSKY=0 git commit ..., чтобы временно отключить хуки.
  3. Перенеси тяжёлые тесты на pre-push или CI: быстро сохранять работу важнее, чем гонять Jest в pre-commit.

6. Расширяем строгость: pre-push + тесты

# добавим второй хук
npx husky add .husky/pre-push "pnpm dlx vitest run"

Теперь:

  • pre-commit = форматирование + линтер (быстро);
  • pre-push = юнит-тесты (могут идти дольше);
  • CI проверяет e2e — полный цикл.

7. Полезные инструменты рядом

ЗадачаИнструментКоротко
Просмотреть, что именно запускает Hookgit config core.hooksPathПуть к .husky
Вручную запустить Hooknpm run lint-staged -- --debugЛог вызовов
GUI-диагностика Git-хуковlefthookАльтернатива Husky
Hook-агрегация под любой языкpre-commit (Python)Аналог Husky без Node

8. Итоги

  • 5 минут настройки → команда коммитит идеально отформатированный код.
  • Проверки быстрые (только staged-файлы).
  • Настройка прозрачна — никаких скрытых bash-скриптов.

В следующий раз, когда Лёша попробует закоммитить «горячий фикс», Husky вежливо поправит файлы, и тревога превратится в зелёный тик. Преступление плохого кода предотвращено до того, как попало в репозиторий.

Оставить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *