Repository navigation
fix(cli): stop glob and grep include patterns from bypassing .gitignore - #15017
Conversation
Code Review SummaryStatus: No Issues Found | Recommendation: Merge Incremental review at Files Reviewed (1 file)
Previous Review Summary (commit e48c978)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit e48c978)Status: No Issues Found | Recommendation: Merge The change stops glob patterns from bypassing ignore rules by matching the agent's pattern in Files Reviewed (6 files)
Reviewed by deepseek-v4.1-flash · Input: 44K · Output: 7.7K · Cached: 269.2K Review guidance: REVIEW.md from base branch |
Same root cause as #15003: ripgrep overrides beat ignore rules.
… fix/glob-respect-gitignore
Closes #15003.
What
Glob searches, the grep tool's
includefilter and Corefindstop returning gitignored files and stop walking ignored folders such asnode_modules,distor.venv, whatever the shape of the pattern.Cause: the Core ripgrep adapter passed the agent's pattern as
--glob=<pattern>. That makes it a ripgrep override, and overrides win over ignore rules. Any pattern that also matches folder names (**/*,**,*) whitelisted ignored folders, and any gitignored file that matched was returned. In this repo,**/*matched 139,817 files, and 128,897 of them were ignored; the glob tool hid most of that only because it stops at 100 results.Fix: ripgrep now lists only the files its ignore rules allow, and the pattern is matched in
packages/core/src/kilocode/ripgrep-glob.ts, using the same gitignore-style rules ripgrep uses for overrides.packages/core/src/ripgrep.tsgets only marked hooks (the pattern arguments and a per-line filter).glob,findandgrep(withinclude): the glob and grep tools, their Core v2 versions, filesystem search, the file API and the marketplace scan.includeglob is applied to each match's path. Grep always searched hidden files, so only ignored files change. A search of an explicit file still ignoresinclude, as before.Behavior kept on purpose
**/.gitignore,.env.example), and a hidden folder is still searched only when the pattern matches the folder itself.!*.ts) are still passed to ripgrep, since they never bypass ignore rules. Invalid patterns are still reported by ripgrep itself:--pre-glob=<pattern>makes ripgrep parse the pattern without using it, because no--precommand is set..gitis never searched.experimental.glob_include_ignoredallowlist from feat(cli): let glob search an opt-in allowlist of ignored paths #14988 keeps its semantics. Its extra ripgrep run still uses override globs, so that run now keeps only paths matching a listed entry, and the filter runs before the result limit, so ignored files elsewhere can't take up the result slots. The normal search runs alongside it.How it's verified
packages/core/test/kilocode/ripgrep-glob.test.ts): for 41 patterns ×hiddenon/off, on a fixture with nested.gitignorefiles,.ignore, negations (!out/keep.txt), hidden files and folders, and folders named like patterns, results equal exactly whatrg --glob=<pattern>returned before, minus ignored files.hiddenon/off: 0 differences.findand grepinclude: for every pattern above,find(hidden on/off) and grepincludereturn exactly what ripgrep returned before, minus ignored files.mainon this machine.Performance
Measured in-process with the real glob tool, alternating
mainand this branch, 20 runs per round, 3 rounds. The workspace was this repo: 10.6k searchable files, 139k withnode_modules.mainmedians**/*.ts(stops after 100 results)**/*.nomatch(walks every non-ignored file)**/package.jsonpackages/*/src/**/*.ts**/***/*.ts,*.md) are also passed to ripgrep as a file type, so it still prints only matching files.experimental.glob_include_ignoredset, every search now runs both ripgrep passes, and the allowlist pass no longer stops early on results it would throw away. That adds about 15 ms on this repo (e.g.**/*.tswithpackages/*/dist: 9.7 → 29.4 ms).Grep and find (Core
ripgrep.grep/findon this repo, 2 rounds, medians):mainEffect.gen,include: "*.ts"(stops after 100 hits)include: "*.ts"include: "packages/**/*.ts"include: "**/*"Effect.gen,include: "packages/core/**/*.ts"(stops after 100 hits)**/*/**/*.nomatchincludenames a folder path and that stops early. Ripgrep now searches every file of that type (here every.ts) and the folder part is checked afterwards, so it finds the 100 hits later. It can never cost more than a search through every file of that type (~75 ms here).packages/core) would be faster, but ripgrep always searches an explicitly named folder even if it's ignored, so I left it out.Follow-ups
**/*lists node_modules) #15003: glob, grepincludeandfindare all covered here.