Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions src/git.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,24 +246,26 @@ export function repoRoots(cwd: string): Promise<string[]> {
}

async function discoverRepoRoots(cwd: string): Promise<string[]> {
const roots: string[] = []
try {
return [await directRepoRoot(cwd)]
roots.push(await directRepoRoot(cwd))
} catch {
const entries = await readdir(cwd, { withFileTypes: true }).catch(() => [])
const roots: string[] = []
for (const entry of entries
.filter(entry => entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules')
.sort((left, right) => left.name.localeCompare(right.name))
.slice(0, DISCOVERY_LIMIT)) {
try {
const root = await directRepoRoot(join(cwd, entry.name))
if (!roots.some(existing => pathIdentity(existing) === pathIdentity(root))) roots.push(root)
} catch {
// Ordinary child directory; keep discovering sibling repositories.
}
// Current directory is not a Git repository root.
}

const entries = await readdir(cwd, { withFileTypes: true }).catch(() => [])
for (const entry of entries
.filter(entry => entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'node_modules')
.sort((left, right) => left.name.localeCompare(right.name))
.slice(0, DISCOVERY_LIMIT)) {
try {
const root = await directRepoRoot(join(cwd, entry.name))
if (!roots.some(existing => pathIdentity(existing) === pathIdentity(root))) roots.push(root)
} catch {
// Ordinary child directory; keep discovering sibling repositories.
}
return roots
}
return roots
}

/** Resolve the selected repository, defaulting to the first discovered root. */
Expand Down
21 changes: 21 additions & 0 deletions tests/git.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,27 @@ describe('git parsing', () => {
}
})

it('discovers root and direct child repositories when root is also a git repository', async () => {
const workspace = await mkdtemp(join(tmpdir(), 'dsh-better-sidebar-root-git-'))
const child = join(workspace, 'child-repo')
try {
await mkdir(child)
await Promise.all([
execFileAsync('git', ['-C', workspace, 'init']),
execFileAsync('git', ['-C', child, 'init']),
])

await expect(repoRoots(workspace)).resolves.toEqual([canonical(workspace), canonical(child)])
await expect(status(workspace, canonical(child))).resolves.toMatchObject({
isRepo: true,
root: canonical(child),
repositories: [canonical(workspace), canonical(child)],
})
} finally {
await rm(workspace, { recursive: true, force: true })
}
})

it('parses porcelain -z entries including renames', () => {
const output = ['M src/a.ts', ' M src/b.ts', '?? src/c.ts', 'R src/new.ts', 'src/old.ts', ''].join('\0')
const entries = parsePorcelainZ(output)
Expand Down