(startPath: string, indexRoot: string)
| 145 | * common dir): the #155 borrowed-worktree case, warned about, not refused. |
| 146 | */ |
| 147 | export function nestedRepositoryBelow(startPath: string, indexRoot: string): NestedRepository | null { |
| 148 | // git needs an existing directory to run in: a file, or a sub-path that does |
| 149 | // not exist yet, belongs to the repository of its nearest existing directory. |
| 150 | let dir = path.resolve(startPath); |
| 151 | while (!isDirectory(dir)) { |
| 152 | const up = path.dirname(dir); |
| 153 | if (up === dir) return null; |
| 154 | dir = up; |
| 155 | } |
| 156 | const repoRoot = gitWorktreeRoot(dir); |
| 157 | if (!repoRoot) return null; |
| 158 | |
| 159 | // The on-disk spelling of both ends (`realpathSync.native` normalizes case on |
| 160 | // macOS and Windows), so `relPath` matches the paths the index stored. |
| 161 | const rel = path.relative(nativeRealpath(indexRoot), nativeRealpath(repoRoot)); |
| 162 | if (!rel || rel === '..' || rel.startsWith(`..${path.sep}`) || path.isAbsolute(rel)) return null; |
| 163 | |
| 164 | const repoCommon = gitCommonDir(repoRoot); |
| 165 | if (!repoCommon || repoCommon === gitCommonDir(realpath(indexRoot))) return null; |
| 166 | return { root: repoRoot, relPath: rel.split(path.sep).join('/') }; |
| 167 | } |
| 168 | |
| 169 | function isDirectory(p: string): boolean { |
| 170 | try { |
no test coverage detected