Pre-commit в Git: типичные ошибки и способы их исправить
Pre-commit часто ломается не из-за самих линтеров, а из-за Git hooks, виртуальных окружений и неверных ожиданий от проверки staged-файлов. Разбираем ошибки, команды диагностики и рабочую схему для локальной разработки и CI.

Pre-commit обычно «ломается» в одном из трёх мест: hook не установлен, проверка запускается не на тех файлах или отдельный инструмент не может собрать своё окружение. В результате разработчик видит зелёный локальный коммит, а CI отклоняет тот же код, либо получает исправленный файл после проверки и забывает добавить его в индекс. Ниже — практика для pre-commit 4.x и Git 2.x: как отличить проблему конфигурации от проблемы hook и не превратить проверки в случайный набор команд.
Сначала проверьте, какой режим запускается
У pre-commit несколько режимов, и они проверяют разные наборы файлов. Команда без параметров обычно работает с файлами, подготовленными к коммиту. Это не то же самое, что полный прогон по репозиторию.
| Команда или событие | Что проверяется | Когда использовать |
|---|---|---|
git commit | Файлы, которые Git собирается закоммитить | Обычная защита перед коммитом |
pre-commit run | Подготовленные к коммиту файлы | Повторить локальный hook вручную |
pre-commit run --all-files | Все файлы, подходящие под правила hook | Первое подключение и проверка всей кодовой базы |
CI с pre-commit run --all-files | Весь checkout в окружении CI | Единая проверка ветки перед слиянием |
Главная ловушка pre-commit: успешная команда не означает, что проверен весь репозиторий. Сначала выясните область проверки, затем ищите ошибку в инструменте.
Staged-файлы1 — это файлы, добавленные в индекс Git командой git add. Именно их содержимое попадёт в следующий коммит.
Ошибка 1. Hook не запускается при коммите
Самая частая причина — pre-commit установлен как пакет, но hook ещё не зарегистрирован в локальном репозитории. Установка программы и установка Git hook — разные операции.
# Выполнить из корня репозитория
pre-commit install
# Проверить hook на всех подходящих файлах
pre-commit run --all-files
После pre-commit install попробуйте создать обычный коммит. Если Git по-прежнему не запускает проверки, проверьте, не задан ли отдельный каталог hooks:
git config --show-origin --get core.hooksPath
Если команда вернула путь, Git может использовать его вместо стандартного .git/hooks. Это часто встречается в корпоративных шаблонах и монорепозиториях. Не меняйте значение вслепую: сначала выясните, какие ещё hooks зависят от этого каталога.
Ошибка 2. Конфигурация есть, но YAML не читается
Файл должен называться .pre-commit-config.yaml и находиться в корне репозитория. В YAML критичны отступы: табы и неверный уровень вложенности меняют структуру конфигурации.
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
Для диагностики используйте встроенную проверку:
pre-commit validate-config
pre-commit run --all-files
Если ошибка появилась после изменения rev, проверьте, существует ли такая версия в репозитории hook. Не подставляйте произвольный тег: pre-commit скачивает код hook по указанной ссылке, и несуществующая ревизия остановит запуск до проверки файлов.
Ошибка 3. Hook исправил файл, а коммит всё равно не проходит
Некоторые hook не только проверяют, но и изменяют файлы. Например, форматировщик может переписать код, а end-of-file-fixer — добавить перевод строки в конце файла. После изменения pre-commit завершает запуск с ошибкой, чтобы вы явно увидели новый diff.
Посмотрите, что изменилось:
git diff. Не добавляйте изменения автоматически, пока не проверили результат.Добавьте исправленные файлы в индекс:
git add path/to/file.Повторите проверку:
pre-commit run.Если все hook завершились успешно, повторите
git commit.
Ошибка здесь не в том, что pre-commit «запускается дважды». Первый запуск изменил рабочее дерево, а второй должен проверить уже обновлённое содержимое. Особенно важно это для форматировщиков: локальный файл и staged-версия до повторного git add могут различаться.
Ошибка 4. Локально проверяется не тот набор файлов
Разработчик запускает pre-commit run, получает успешный результат и считает задачу закрытой. Но незакоммиченные изменения не попадут в проверку, если они не добавлены в индекс. Для полной проверки используйте --all-files, а перед коммитом смотрите, что именно подготовлено:
git status --short
git diff --cached --name-only
pre-commit run
Обратная ошибка тоже распространена: новый hook запускают с --all-files, он форматирует сотни старых файлов, и разработчик получает огромный diff. В существующем проекте сначала согласуйте отдельный коммит с массовым форматированием. Иначе функциональные изменения смешаются с механическими.
Ошибка 5. Не совпадают версии и окружения
Pre-commit создаёт отдельные окружения для hook и кэширует их. Поэтому установленный в проекте Python-пакет не всегда влияет на версию инструмента внутри hook. Локально может работать один набор зависимостей, а в CI — другой, если конфигурация или ревизия hook различаются.
Проверьте версию самого pre-commit и состояние его окружений:
pre-commit --version
pre-commit run --all-files -v
Флаг -v добавляет подробный вывод: по нему видно, какой hook запускается и на каком этапе возникает ошибка. Если окружение повреждено или в нём осталась старая зависимость, очистите кэш и запустите проверку заново:
pre-commit clean
pre-commit run --all-files
Не удаляйте кэш на каждом запуске. Первая повторная сборка может занять заметно больше времени, а постоянная очистка маскирует проблему с версией или сетью.
Ошибка 6. Обновление hook превращается в случайный массовый diff
Команда pre-commit autoupdate обновляет ревизии hook в конфигурации. Это не просто обновление утилиты: новая ревизия может изменить форматирование, набор проверок или минимальную версию интерпретатора.
Обновляйте hook отдельным коммитом и проверяйте результат на полном репозитории. Если diff большой, выясните, что именно изменилось: версия hook, его зависимости или правила форматирования. Закреплённая ревизия обычно безопаснее плавающей ссылки на ветку, потому что одинаковый конфиг даёт воспроизводимый результат.
Два рабочих подхода к запуску
В небольшом проекте достаточно запускать pre-commit перед каждым коммитом. В команде с CI этого мало: hook можно пропустить через git commit --no-verify, а локальная машина может отличаться от runner. Поэтому практичнее сочетать быстрый локальный запуск с обязательной проверкой в CI.
| Подход | Плюс | Цена и риск |
|---|---|---|
| Только локальный hook | Быстрая обратная связь, меньше нагрузки на CI | Проверку можно обойти, окружения разработчиков различаются |
| Только CI | Единая среда и обязательный контроль | Ошибка обнаруживается после push, цикл исправления дольше |
| Локальный hook и CI | Быстрая ошибка у автора и защита ветки | Нужно поддерживать одинаковую конфигурацию в двух местах |
Для CI не копируйте вручную список отдельных hook. Запускайте ту же конфигурацию репозитория, обычно через pre-commit run --all-files. Так CI проверит именно те правила, которые разработчик видит локально.
Что ломается чаще всего
- «command not found: pre-commit». Пакет не установлен в активное окружение или его каталог не добавлен в
PATH. Проверьте, каким менеджером пакетов установлен инструмент, и запускайте его из того же окружения, где он был установлен. - «InvalidConfigError». Ошибка в YAML, имени файла, ссылке на репозиторий или ревизии hook. Начните с
pre-commit validate-config, а затем проверьте подозрительный блок конфигурации. - «Executable not found». Hook ожидает программу, которой нет в его окружении или в системе. По подробному выводу определите конкретный hook и сверяйте его требования с официальной документацией.
- «Permission denied». Проблема с правами на hook, рабочий каталог или временное окружение. Не запускайте весь Git с повышенными правами: это может создать файлы, которыми потом не владеет ваш обычный пользователь.
- Hook не видит новый файл. Файл не добавлен в индекс, подпадает под
excludeили не соответствует типам файлов hook. Сравнитеgit status --shortс правиламиfiles,typesиexcludeв конфигурации.
Что делать дальше
Сначала закрепите одну ревизию каждого hook, установите pre-commit 4.x в документации проекта и добавьте проверку полного репозитория в CI. Затем измерьте время pre-commit run --all-files на чистом runner и время обычного pre-commit run перед коммитом. Если локальный запуск стал мешать работе, не отключайте все проверки: разделите быстрые hook для каждого коммита и тяжёлые проверки для CI. Инвалидация кэша и настройка параллельности — отдельная тема; здесь важнее сначала добиться одинакового набора hook на рабочей станции и в CI.
Проверка рекламы на риски: Что в макете вызовет вопросы ФАС: превосходные степени, сравнения, обещания результата, маркировка.
Спросить за 40 ₽Источники: Официальная документация pre-commit, Git documentation: Git Hooks
Частые вопросы
Почему pre-commit установлен, но при git commit ничего не происходит?
Почему pre-commit исправляет файл и завершается с ошибкой?
Почему команда pre-commit run не проверяет мои незакоммиченные изменения?
Можно ли пропустить pre-commit, если нужно срочно сделать коммит?
Что делать, если в CI pre-commit работает иначе, чем локально?
Подойдёт ли эта схема для другой версии pre-commit?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.