Documents / Issues / issue-0d4741c85e7f
Code globs stop matching under a gitignored path, so governed clones lose invalidation
The fix for issue-ec3819b1f13c excluded ignored files from matching as well as fingerprinting, silencing every document governed by a vendored or mirrored source.
What is wrong¶
Since 0.28.0 a code: glob naming a file under a gitignored directory matches nothing. The
fix for A code glob fingerprints gitignored build output, so a rebuild reports drift excluded ignored files from matching as well as from
fingerprinting, so a repository that governs vendored or mirrored sources — checked out into
an ignored directory because they are read-only working copies, not sources — loses every
code-changed signal it had and gains one unmatched-code finding per document.
Measured¶
Reported against 0.28.0 from an adopting store: 288 of 288 code-governing documents at once, and the invalidation queue went from 102 live findings to none.
0.27.0 0.28.0, same store, same commit
102 code-changed 288 unmatched-code
35 code-drifted 11 code-changed
40 stale 15 code-drifted
3 orphan 40 stale
3 orphan
The direction is what makes this worse than what it replaced. 0.27.0 over-reported; 0.28.0
under-reports silently, and an empty queue is indistinguishable from a clean one. The 288
unmatched-code findings say "update the pattern" about 288 patterns that are correct.
Why it slipped through¶
A code glob hashes what the repository tracks, not what it builds extended one rule to two questions in one sentence — a path git ignores
"is not hashed into a code: glob's digest and does not count as a match". The argument
behind it is only about the first: it is about files a broad glob sweeps up beside the ones
it was aimed at. Nobody sweeps a vendored clone up by accident.
Every test of the matcher builds its own tree in tmp_path with one ignore rule over a
subdirectory of a tracked tree, which is exactly the mixed case the rule is right about. The
all-ignored case had one test, and it asserted the defect.
The workaround, and why it is not a fix¶
The adopter moved the exclusion to .git/info/exclude, which docir deliberately does not
read. It works — 102 code-changed, 0 unmatched-code, measured on 0.28.0 — and it costs the
exclusion the property it had: .gitignore is committed, .git/info/exclude is per-machine
and invisible to everyone who clones.
Resolution¶
FIXED — A code glob a repository ignores entirely is still the code it governs. .gitignore drops files from a glob that reaches something
else, and is not consulted for a glob that reaches nothing else. Two passes, the second
running only for a pattern that used to resolve to nothing, so the common case pays what it
paid before and still prunes ignored subtrees. The hardcoded floor stays absolute on both.
Four guards in tests/platform/test_infra_filesystem.py, verified against the old matcher:
the two that pin the new half fail on it, and the two that pin the unchanged half pass on
both, which is what says the mixed case did not move.
Un-silenced globs arrive carrying no baseline, so they surface as code-unwatched
(A code glob verified while it matches nothing records an empty baseline that never re-arms) and docir check --fix arms them.
Reported as GitHub #24.