* Get all files visible to git (tracked + untracked but not ignored). * Respects .gitignore at all levels (root, subdirectories) and descends into * embedded (nested, non-submodule) git repos. Returns null on failure * (non-git project) so callers can fall back to a filesystem walk.
(rootDir: string)
| 1016 | * (non-git project) so callers can fall back to a filesystem walk. |
| 1017 | */ |
| 1018 | function getGitVisibleFiles(rootDir: string): Set<string> | null { |
| 1019 | try { |
| 1020 | // Check if the project directory is gitignored by a parent repo. |
| 1021 | // When rootDir lives inside a parent git repo that ignores it, |
| 1022 | // `git ls-files` returns nothing — fall back to filesystem walk. |
| 1023 | const gitRoot = execFileSync( |
| 1024 | 'git', |
| 1025 | ['rev-parse', '--show-toplevel'], |
| 1026 | { cwd: rootDir, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true } |
| 1027 | ).trim(); |
| 1028 | |
| 1029 | if (path.resolve(gitRoot) !== path.resolve(rootDir)) { |
| 1030 | try { |
| 1031 | // git check-ignore exits 0 if the path IS ignored, 1 if not |
| 1032 | execFileSync( |
| 1033 | 'git', |
| 1034 | ['check-ignore', '-q', path.resolve(rootDir)], |
| 1035 | { cwd: rootDir, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true } |
| 1036 | ); |
| 1037 | // Directory is gitignored by parent repo — fall back to filesystem walk |
| 1038 | return null; |
| 1039 | } catch { |
| 1040 | // Not ignored — safe to use git ls-files |
| 1041 | } |
| 1042 | } |
| 1043 | |
| 1044 | const files = new Set<string>(); |
| 1045 | const embeddedRoots = new Set<string>(); |
| 1046 | collectGitFiles(rootDir, '', files, embeddedRoots, loadIncludeIgnoredMatcher(rootDir)); |
| 1047 | // Apply built-in default ignores uniformly — to tracked files too, since |
| 1048 | // committing a dependency/build dir doesn't make it project code. A |
| 1049 | // `.gitignore` negation (e.g. `!vendor/`) is the explicit opt-in. (issue #407) |
| 1050 | // Files inside an EMBEDDED repo are matched against that repo's own rules, |
| 1051 | // not the parent's: the parent's .gitignore hides the child repo from git, |
| 1052 | // not from the index. (#514) |
| 1053 | const ig = buildScopeIgnore(rootDir, embeddedRoots); |
| 1054 | const visible = new Set([...files].filter((f) => !ig.ignores(f))); |
| 1055 | // Force-include first-party source the project whitelisted in |
| 1056 | // `codegraph.json` `include`. These are gitignored, so `git ls-files` never |
| 1057 | // listed them above — discover them directly off disk and add them. (The |
| 1058 | // common SVN+Git dual-VCS case: source committed to SVN, gitignored out of |
| 1059 | // Git, but still wanted in the graph.) |
| 1060 | for (const f of collectIncludedFilesForRoot(rootDir)) visible.add(f); |
| 1061 | return visible; |
| 1062 | } catch { |
| 1063 | return null; |
| 1064 | } |
| 1065 | } |
| 1066 | |
| 1067 | /** |
| 1068 | * Result of git-based change detection. |
no test coverage detected