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