* Discover embedded repos hidden by `repoDir`'s OWN gitignore rules: for each * gitignored directory, search for nested `.git` roots. Returns repo paths * relative to `repoDir`, trailing-slashed. * * OPT-IN ONLY. Walking into a gitignored directory contradicts what every other * tool (and CodeG
(repoDir: string, includeIgnored: Ignore | null, prefix: string)
| 867 | * default excludes (`node_modules`, …) are always skipped. |
| 868 | */ |
| 869 | function findIgnoredEmbeddedRepos(repoDir: string, includeIgnored: Ignore | null, prefix: string): string[] { |
| 870 | if (!includeIgnored) return []; |
| 871 | const defaults = defaultsOnlyIgnore(); |
| 872 | const repos: string[] = []; |
| 873 | for (const dir of listIgnoredDirs(repoDir)) { |
| 874 | if (defaults.ignores(dir)) continue; |
| 875 | const nested = findNestedGitRepos(path.join(repoDir, dir), dir); |
| 876 | if (includeIgnored.ignores(normalizePath(prefix + dir))) { |
| 877 | // The whole ignored dir is opted in — every nested repo under it counts. |
| 878 | repos.push(...nested); |
| 879 | } else { |
| 880 | // A single gitignore rule often covers the PARENT of the opted-in |
| 881 | // repos: `.gitignore: /repos/` lists `repos/` as ONE ignored entry, |
| 882 | // while `includeIgnored: ["repos/a/"]` (the CLI hint's own suggested |
| 883 | // spelling) names the child — which never matches the parent path, so |
| 884 | // the opt-in silently did nothing (#1295). Match each nested repo |
| 885 | // root individually so both spellings work. The walk is bounded |
| 886 | // (depth/entry caps in findNestedGitRepos) and only runs when |
| 887 | // includeIgnored is configured at all. |
| 888 | repos.push(...nested.filter((r) => includeIgnored.ignores(normalizePath(prefix + r)))); |
| 889 | } |
| 890 | } |
| 891 | return repos; |
| 892 | } |
| 893 | |
| 894 | /** |
| 895 | * Collect git-visible files (tracked + untracked, .gitignore-respected) from the |
no test coverage detected