* 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)
| 575 | * data dirs. Depth- and entry-capped so a huge ignored tree can't stall the scan. |
| 576 | */ |
| 577 | function findNestedGitRepos(absDir: string, relPrefix: string): string[] { |
| 578 | const found: string[] = []; |
| 579 | const defaults = defaultsOnlyIgnore(); |
| 580 | const queue: Array<{ abs: string; rel: string; depth: number }> = [ |
| 581 | { abs: absDir, rel: relPrefix, depth: 0 }, |
| 582 | ]; |
| 583 | let examined = 0; |
| 584 | while (queue.length > 0) { |
| 585 | const { abs, rel, depth } = queue.shift()!; |
| 586 | if (++examined > EMBEDDED_REPO_SEARCH_ENTRIES) { |
| 587 | logDebug('Embedded-repo search entry cap hit — deeper repos (if any) not discovered', { under: relPrefix }); |
| 588 | break; |
| 589 | } |
| 590 | const cls = classifyGitDir(abs); |
| 591 | if (cls === 'worktree') { |
| 592 | continue; // a git worktree duplicates an already-indexed repo (#848) — skip |
| 593 | } |
| 594 | if (cls === 'embedded') { |
| 595 | found.push(rel); |
| 596 | continue; // its own git handles everything below |
| 597 | } |
| 598 | if (depth >= EMBEDDED_REPO_SEARCH_DEPTH) continue; |
| 599 | let entries: fs.Dirent[]; |
| 600 | try { |
| 601 | entries = fs.readdirSync(abs, { withFileTypes: true }); |
| 602 | } catch { |
| 603 | continue; |
| 604 | } |
| 605 | for (const entry of entries) { |
| 606 | if (!entry.isDirectory()) continue; |
| 607 | if (entry.name === '.git' || isCodeGraphDataDir(entry.name)) continue; |
| 608 | const childRel = rel + entry.name + '/'; |
| 609 | if (defaults.ignores(childRel)) continue; |
| 610 | queue.push({ abs: path.join(abs, entry.name), rel: childRel, depth: depth + 1 }); |
| 611 | } |
| 612 | } |
| 613 | return found; |
| 614 | } |
| 615 | |
| 616 | /** |
| 617 | * Workspace-scope ignore matcher. Ordinary paths get the root's matcher |
no test coverage detected