Skip to content

Resolve excluded ancestor directories before descendant negations - #154

Closed
sricharanreddycheruku wants to merge 1 commit into
cpburnz:masterfrom
sricharanreddycheruku:fix-excluded-ancestor-resolution
Closed

sricharanreddycheruku wants to merge 1 commit into
cpburnz:masterfrom
sricharanreddycheruku:fix-excluded-ancestor-resolution

Conversation

@sricharanreddycheruku

Copy link
Copy Markdown

A negated descendant pattern can currently re-include a file whose parent is still
excluded. For example, ["dir/", "!dir//file"] incorrectly permits
"dir/nested/file" in all three backends. Git keeps it ignored because dir/nested/
is excluded. Likewise, ["/", "!src/"] should permit src/a.txt while keeping
src/nested/file ignored; re-including src/ does not reopen every nested directory.
The simple backend also disagrees with RE2/Hyperscan for ["
", "!**/a.py"].

Resolve strict ancestors from outermost to innermost before matching the requested
path. Return the index of the first blocking rule, and skip repeated ancestor
checks during these individual directory queries. Keep reopened directories usable
and require each still-excluded parent to be re-included independently.

This extends the ancestor-resolution work from #129/#137/#144; the earlier merged
changes leave these cases reproducible. No duplicate open PR was found.

Validation:

  • Six new test methods exercise forward, reverse and shuffled backend configurations,
    file/directory queries, rule indices and explicitly reopened ancestors. Against
    original source they report 68 failures, including subtests.
  • Complete Python 3.12.14 and 3.14.7 suites: 238 passed, 1 skipped and 1,044 subtests
    passed on each, with all three matching backends installed.
  • Minimum Python 3.9.25: 173 passed, 66 optional-backend skips.
  • mypy and pyright pass for Python 3.14 targets; warning-as-error Sphinx build passes.
  • Expected outcomes reproduced with git check-ignore --no-index on real file trees.

Update the README with the parent-exclusion rule and change history.

Performance: checking every strict ancestor adds work for unignored nested paths.
A small four-pattern, 2,000-query microbenchmark measured roughly 4/17/62 µs per
query at depths 1/5/12 with the simple backend, 5/19/48 µs with RE2 and 1.5/8/20 µs
with Hyperscan. The original implementation took approximately 1–4 µs in these
cases. These are workspace measurements under concurrent build load, not a general
throughput estimate. Ancestor queries avoid recursive rechecking and stop at the
first excluded directory.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant