perf: Index repo gitignore matchers (#12928)
## Why
The repo-index untracked-file walk prebuilds gitignore matchers, but
still checked every matcher for every visited path. Repos with many
nested .gitignore files pay unnecessary CPU during dry runs, especially
when building package hashes without cache hits.
Release-binary benchmarks against pristine main showed consistent wins:
- This repository: 1.08-1.09x faster for a dry multi-task run.
- Internal repository A: 1.09-1.16x faster for dry task graph runs.
- Internal repository B: 1.03-1.04x faster for dry task graph runs, with
lower aggregate user CPU.
## What
Index gitignore matchers by the directory they apply to, then check only
matchers in the visited path's ancestor chain. This preserves nested
gitignore scoping while avoiding full matcher scans for unrelated
subtrees.
## How
Validated with:
- cargo fmt --package turborepo-scm
- cargo test -p turborepo-scm repo_index
- cargo test -p turborepo-scm
- git diff --check
The pre-push hook also ran repository formatting/TOML checks and Rust
checks successfully.