* Find git repositories nested under `absDir` (inclusive), shallow bounded BFS. * Stops descending at each repo root found — contents belong to that repo's own * enumeration. Skips default-ignored dirs (`node_modules` can contain `.git` * from npm git-dependencies — that never makes it project co
(absDir: string, relPrefix: string)
| 408 | * data dirs. Depth- and entry-capped so a huge ignored tree can't stall the scan. |
| 409 | */ |
| 410 | function findNestedGitRepos(absDir: string, relPrefix: string): string[] { |
| 411 | const found: string[] = []; |
| 412 | const defaults = defaultsOnlyIgnore(); |
| 413 | const queue: Array<{ abs: string; rel: string; depth: number }> = [ |
| 414 | { abs: absDir, rel: relPrefix, depth: 0 }, |
| 415 | ]; |
| 416 | let examined = 0; |
| 417 | while (queue.length > 0) { |
| 418 | const { abs, rel, depth } = queue.shift()!; |
| 419 | if (++examined > EMBEDDED_REPO_SEARCH_ENTRIES) { |
| 420 | logDebug('Embedded-repo search entry cap hit — deeper repos (if any) not discovered', { under: relPrefix }); |
| 421 | break; |
| 422 | } |
| 423 | const cls = classifyGitDir(abs); |
| 424 | if (cls === 'worktree') { |
| 425 | continue; // a git worktree duplicates an already-indexed repo (#848) — skip |
| 426 | } |
| 427 | if (cls === 'embedded') { |
| 428 | found.push(rel); |
| 429 | continue; // its own git handles everything below |
| 430 | } |
| 431 | if (depth >= EMBEDDED_REPO_SEARCH_DEPTH) continue; |
| 432 | let entries: fs.Dirent[]; |
| 433 | try { |
| 434 | entries = fs.readdirSync(abs, { withFileTypes: true }); |
| 435 | } catch { |
| 436 | continue; |
| 437 | } |
| 438 | for (const entry of entries) { |
| 439 | if (!entry.isDirectory()) continue; |
| 440 | if (entry.name === '.git' || isCodeGraphDataDir(entry.name)) continue; |
| 441 | const childRel = rel + entry.name + '/'; |
| 442 | if (defaults.ignores(childRel)) continue; |
| 443 | queue.push({ abs: path.join(abs, entry.name), rel: childRel, depth: depth + 1 }); |
| 444 | } |
| 445 | } |
| 446 | return found; |
| 447 | } |
| 448 | |
| 449 | /** |
| 450 | * Workspace-scope ignore matcher. Ordinary paths get the root's matcher |
no test coverage detected