Линтеры в Git: как не тормозить разработку и CI
Запускать линтер на всём репозитории перед каждым коммитом — простой способ замедлить команду. Разберём, как запускать проверку только для изменённых файлов, что оставить локальным хукам, а что перенести в CI.

Запускать линтер на всём репозитории перед каждым коммитом — простой способ превратить проверку в пятиминутную паузу. Практичнее разделить её на два слоя: локальный Git-хук проверяет только подготовленные файлы, а CI повторяет строгую проверку всего проекта. Ниже — схема для Git 2.40+, Node.js 20+, ESLint 9.x и lint-staged 15.x.
Почему один линтер перед коммитом не решает задачу
Команда вроде npx eslint . на локальной машине проверяет весь проект, включая файлы, которые вы не меняли. На небольшом репозитории это почти незаметно. В монорепозитории или проекте с несколькими тысячами файлов задержка быстро становится причиной отключить хук.
Обратная крайность опаснее: запускать линтер только локально. Хук можно обойти параметром git commit --no-verify, а новый разработчик может вообще не установить его. Поэтому локальная проверка должна ускорять обратную связь, но не быть единственным барьером.
Локальный хук экономит время разработчика, CI защищает ветку. Эти задачи не стоит смешивать.
* Staged-файлы — файлы, добавленные в индекс Git командой git add и подготовленные к ближайшему коммиту. Именно их должен проверять pre-commit-хук, иначе линтер может анализировать незакоммиченные изменения, которые не попадут в текущий коммит.
Три места для запуска проверки
| Место | Что проверять | Цена | Зачем применять |
|---|---|---|---|
| Редактор | Текущий файл во время ввода | Минимальная задержка, но результат зависит от настроек IDE | Быстро исправлять ошибки до сохранения |
| Git pre-commit | Только staged-файлы | Нужно один раз настроить хук на каждой рабочей копии | Не пропускать очевидные ошибки в коммит |
| CI после push | Весь проект или изменённый пакет | Проверка занимает время и использует ресурсы runner | Сделать правило обязательным для всей команды |
Для большинства JavaScript-проектов разумная связка выглядит так: редактор показывает проблему сразу, pre-commit запускает ESLint для staged-файлов, CI выполняет полную проверку и не зависит от локальных хуков.
Подход 1. Локальный хук через lint-staged
Установка и команда линтера
Выполните команды в корне проекта. Они добавят lint-staged в dev-зависимости и создадут скрипт для полной проверки.
npm install --save-dev lint-staged@15
npm pkg set scripts.lint="eslint ."
npm pkg set scripts.lint:ci="eslint . --max-warnings=0"
Параметр --max-warnings=0 делает предупреждения ошибкой в CI. Это полезно, если команда хочет постепенно убрать не только ошибки, но и накопленные предупреждения.
Добавьте в package.json настройку для staged-файлов:
{
"lint-staged": {
"*.{js,mjs,cjs}": [
"eslint --cache --max-warnings=0"
]
}
}
lint-staged передаст ESLint список подходящих файлов сам. Это важнее, чем вручную собирать список через git diff: готовый инструмент корректно работает с именами файлов, пробелами и несколькими группами расширений.
Подключение Git-хука
Git умеет хранить хуки в отдельном каталоге. Это позволяет положить скрипт в репозиторий, а не копировать его вручную каждому разработчику.
mkdir -p .githooks
cat > .githooks/pre-commit <<'EOF'
#!/bin/sh
npx --no-install lint-staged
EOF
chmod +x .githooks/pre-commit
git config core.hooksPath .githooks
git add .githooks/pre-commit package.json package-lock.json
git commit -m "Configure staged linting"
После настройки измените JavaScript-файл, добавьте его через git add и выполните коммит. В выводе должна появиться задача lint-staged с именем изменённого файла. Если изменить файл, но не добавить его в индекс, хук не обязан его проверять.
Настройка core.hooksPath локальная. Она не записывается в Git автоматически, поэтому добавьте команду подключения в README или скрипт первоначальной настройки проекта.
Подход 2. Команда без постоянного хука
Иногда хук нельзя навязать: например, часть команды работает в разных окружениях или проект подключается как шаблон. Тогда оставьте lint-staged доступным вручную:
npx --no-install lint-staged
Этот вариант не требует Git-конфигурации, но его легко забыть. Он подходит для локального запуска перед отправкой ветки, а не для контроля качества в защищённой ветке.
Подход 3. Полная проверка в CI
В CI не нужно имитировать staged-состояние рабочей копии. Runner должен установить зависимости из lock-файла и выполнить отдельный скрипт на всём проекте.
npm ci
npm run lint:ci
Если проект использует GitHub Actions, эти две команды размещают в шаге job после установки Node.js и перед тестами или сборкой. Конкретная разметка workflow зависит от версии action и политики репозитория, поэтому не копируйте чужой YAML без проверки его документации.
Для pull request CI должен быть обязательной проверкой правила ветки. Иначе результат будет виден в интерфейсе, но коммит можно будет слить до окончания анализа.
Когда какой подход выбирать
- Небольшой проект и одна команда. Используйте lint-staged в pre-commit и полную команду ESLint в CI.
- Монорепозиторий. Проверяйте staged-файлы локально, а в CI запускайте линтер по пакетам или всему репозиторию в зависимости от времени выполнения.
- Большой legacy-проект. Не включайте все предупреждения сразу. Начните с изменённых файлов, а правила для старого кода ужесточайте постепенно.
- Команда с разными ОС. Храните хук в репозитории и проверьте его на Unix-подобной системе и Windows. Если shell-хук создаёт проблемы, оставьте обязательной проверку CI, а локальный запуск сделайте рекомендацией.
Что обычно ломается
Хук не запускается
Проверьте каталог командой git config --get core.hooksPath. Затем убедитесь, что файл существует по этому пути и имеет право на выполнение. Если Git использует другой каталог, файл в .githooks не будет найден.
Проверяется не тот файл
Чаще всего файл изменили, но забыли выполнить git add. Посмотрите состояние командой git status. lint-staged работает с индексом, а не со всеми изменениями в рабочем каталоге.
В CI команда проходит, а локально падает
Сравните версии Node.js, lock-файл и установленные зависимости. В локальном окружении может использоваться глобальный ESLint, тогда как npx --no-install намеренно требует пакет из проекта.
Линтер исправляет файл, но коммит содержит старую версию
Такое бывает с инструментами, которые меняют файлы. Проверьте документацию конкретной версии lint-staged и посмотрите git diff --cached после запуска. Если автоматическое исправление не добавляет результат в индекс ожидаемым образом, разделите проверку и исправление: исправляйте заранее командой проекта, а pre-commit оставьте только для проверки.
Разработчики обходят хук
Это не ошибка Git, а ограничение локального контроля: pre-commit можно пропустить. Не пытайтесь запретить обход на рабочей станции. Перенесите обязательное правило в CI и защитите основную ветку настройками репозитория.
Что измерять после настройки
В течение недели соберите три показателя: среднее время pre-commit, долю неуспешных запусков и время полного линтера в CI. Если локальный хук стабильно занимает десятки секунд, проверьте, действительно ли lint-staged получает список файлов, а не запускает ESLint на всём проекте.
Следующим шагом настройте одинаковую команду npm run lint:ci локально и в CI, затем добавьте её в правила основной ветки. После этого отдельно решайте вопросы форматирования, тестов и инвалидации кеша: они связаны с качеством кода, но не заменяют линтер.
Проверка грамотности: Орфография, пунктуация, стиль — с объяснением каждой правки
Спросить за 10 ₽Источники: Git hooks — официальная документация Git, lint-staged — документация проекта
Частые вопросы
Можно ли полностью полагаться на pre-commit-хук?
Почему lint-staged не проверяет незакоммиченные изменения?
Что делать, если у меня другая версия ESLint или Node.js?
Нужно ли запускать ESLint и локально, и в CI?
Что делать, если хук не сработал, а коммит уже создан?
Можно ли запускать в pre-commit автоматическое исправление ESLint?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.