no-broken-repo-paths: ложное срабатывание на .git/ (служебные каталоги — не файлы репозитория) #9

Closed
opened 2026-08-26 09:32:31 +07:00 by claude-secretary · 1 comment

Симптом

volody/dispatcher MR !145, pipeline #3343, джоба pre-commit:

FAIL [no-broken-repo-paths]: висячие path-ссылки на файлы репозитория.
  dispatcher/runner.py:338: .git/config.lock

.git/config.lock — не ссылка на файл репозитория, а рантайм-lock, который git создаёт и удаляет по ходу операции. Комментарий описывает поведение git, а не путь в дереве. Правка кода тут ничего не улучшит: любой корректный способ упомянуть .git/config.lock в комментарии будет красным.

Причина

Эвристика хука: токен содержит /, оканчивается файловым расширением, и его первый сегмент — реально существующий каталог репо (резолв от cwd). .git существует всегда, .lock парсится как расширение — условие выполняется, файла нет → FAIL.

Тот же класс ложных срабатываний дадут .venv/, node_modules/, .cache/ — всё, что лежит рядом с деревом, но в него не входит.

Что сделать

Игнорировать пути, чей первый сегмент — служебный каталог, а не часть дерева. Минимально — .git/; заодно стоит закрыть .venv/, node_modules/, .cache/, .pytest_cache/, dist/, build/.

Точнее и надёжнее — сверяться не с файловой системой, а с индексом git (git ls-files): в дереве репозитория .git/ отсутствует по определению, и заодно перестанут ловиться артефакты сборки, которые лежат на диске, но не отслеживаются. Это же уберёт зависимость результата от того, что именно валяется в рабочем каталоге в момент прогона.

Приёмка

  • Комментарий с .git/config.lock проходит хук
  • Ссылка на реально отсутствующий файл дерева (docs/nope.md) по-прежнему падает
  • Ссылка на существующий, но не отслеживаемый артефакт (dist/bundle.js) не падает

Блокирует

volody/dispatcher#180 — MR !145 не может позеленеть, пока хук ловит эту строку. Обходной путь на стороне потребителя (exclude на dispatcher/runner.py) выключил бы проверку всего файла, поэтому лучше починить здесь.

Смежная задача по этому же репозиторию — #8 (no-issue-refs-in-comments для //-комментариев, строгий TODO(#N)); обе просятся в один тег.

## Симптом `volody/dispatcher` MR !145, pipeline #3343, джоба `pre-commit`: ``` FAIL [no-broken-repo-paths]: висячие path-ссылки на файлы репозитория. dispatcher/runner.py:338: .git/config.lock ``` `.git/config.lock` — не ссылка на файл репозитория, а рантайм-lock, который git создаёт и удаляет по ходу операции. Комментарий описывает поведение git, а не путь в дереве. Правка кода тут ничего не улучшит: любой корректный способ упомянуть `.git/config.lock` в комментарии будет красным. ## Причина Эвристика хука: токен содержит `/`, оканчивается файловым расширением, и его первый сегмент — реально существующий каталог репо (резолв от cwd). `.git` существует всегда, `.lock` парсится как расширение — условие выполняется, файла нет → FAIL. Тот же класс ложных срабатываний дадут `.venv/`, `node_modules/`, `.cache/` — всё, что лежит рядом с деревом, но в него не входит. ## Что сделать Игнорировать пути, чей первый сегмент — служебный каталог, а не часть дерева. Минимально — `.git/`; заодно стоит закрыть `.venv/`, `node_modules/`, `.cache/`, `.pytest_cache/`, `dist/`, `build/`. Точнее и надёжнее — сверяться не с файловой системой, а с индексом git (`git ls-files`): в дереве репозитория `.git/` отсутствует по определению, и заодно перестанут ловиться артефакты сборки, которые лежат на диске, но не отслеживаются. Это же уберёт зависимость результата от того, что именно валяется в рабочем каталоге в момент прогона. ## Приёмка - Комментарий с `.git/config.lock` проходит хук - Ссылка на реально отсутствующий файл дерева (`docs/nope.md`) по-прежнему падает - Ссылка на существующий, но не отслеживаемый артефакт (`dist/bundle.js`) не падает ## Блокирует `volody/dispatcher#180` — MR !145 не может позеленеть, пока хук ловит эту строку. Обходной путь на стороне потребителя (`exclude` на `dispatcher/runner.py`) выключил бы проверку всего файла, поэтому лучше починить здесь. Смежная задача по этому же репозиторию — #8 (`no-issue-refs-in-comments` для `//`-комментариев, строгий `TODO(#N)`); обе просятся в один тег.
Author
Owner

Вышло в v0.11.0 (PR #10, коммит 3530435).

.git/ отсечён жёстко — он есть в любом репозитории и содержимым не является. Для остального спрашиваем сам git через check-ignore: путь под .gitignore — артефакт (node_modules/, dist/, .venv/), и его отсутствие нарушением не считается. Своего списка имён не держим: у каждого потребителя он свой и уже описан в его .gitignore.

Вопрос задаётся строго от корня репозитория — иначе при запуске из подкаталога .gitignore подкаталога подменял бы вердикт, и настоящая висячая ссылка тихо пропадала. Это поймало ревью, кейс на подкаталог добавлен.

Проверено, что отсечка не глушит хук целиком: файл со служебными путями и настоящей висячей ссылкой по-прежнему падает.

Разблокирует volody/dispatcher!145, который падал на комментарии с .git/config.lock.

✅ Вышло в `v0.11.0` (PR #10, коммит `3530435`). `.git/` отсечён жёстко — он есть в любом репозитории и содержимым не является. Для остального спрашиваем сам git через `check-ignore`: путь под `.gitignore` — артефакт (`node_modules/`, `dist/`, `.venv/`), и его отсутствие нарушением не считается. Своего списка имён не держим: у каждого потребителя он свой и уже описан в его `.gitignore`. Вопрос задаётся строго от корня репозитория — иначе при запуске из подкаталога `.gitignore` подкаталога подменял бы вердикт, и настоящая висячая ссылка тихо пропадала. Это поймало ревью, кейс на подкаталог добавлен. Проверено, что отсечка не глушит хук целиком: файл со служебными путями **и** настоящей висячей ссылкой по-прежнему падает. Разблокирует `volody/dispatcher!145`, который падал на комментарии с `.git/config.lock`.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
senokosov/pre-commit-hooks#9
No description provided.