diff --git a/src/extension.ts b/src/extension.ts index 993a341..739189f 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -175,17 +175,18 @@ async function githubinator({ } const gitDir = gitDirectories.git + const commonGitDir = gitDirectories.commonGit const repoDir = gitDirectories.repository let headBranch: [string, string | null] | null = null if (mainBranch) { - const res = await findShaForBranches(gitDir) + const res = await findShaForBranches(commonGitDir) if (res == null) { return err(`Could not find SHA for branch in ${mainBranches()}`) } headBranch = res } else { - headBranch = await git.head(gitDir) + headBranch = await git.head(gitDir, commonGitDir) } if (headBranch == null) { return err("Could not find HEAD.") @@ -209,7 +210,7 @@ async function githubinator({ const parsedUrl = await new provider( providersConfig, globalDefaultRemote, - (remote) => git.origin(gitDir, remote), + (remote) => git.origin(commonGitDir, remote), ).getUrls({ selection, // priority: permalink > branch > branch from HEAD diff --git a/src/git.ts b/src/git.ts index 4df9866..eceeb71 100644 --- a/src/git.ts +++ b/src/git.ts @@ -9,6 +9,7 @@ interface IRemote { interface IGitDirectories { git: string + commonGit: string repository: string } @@ -71,6 +72,7 @@ export async function getSHAForBranch( /** Get the current SHA and branch from HEAD for a git directory */ export async function head( gitDir: string, + commonGitDir?: string, ): Promise<[string, string | null] | null> { const headPath = path.resolve(gitDir, "HEAD") if (!(await fs.exists(headPath))) { @@ -91,7 +93,7 @@ export async function head( return [maybeSha.trim(), null] } const branchName = maybeHeadInfo.trim().replace("refs/heads/", "") - const sha = await getSHAForBranch(gitDir, branchName) + const sha = await getSHAForBranch(commonGitDir ?? gitDir, branchName) if (sha == null) { return null } @@ -102,6 +104,15 @@ export function dir(filePath: string) { return walkUpDirectories(filePath, ".git") } +function resolveCommonGitDir(gitDir: string): string { + const commondirPath = path.resolve(gitDir, "commondir") + if (fs.existsSync(commondirPath)) { + const commondir = fs.readFileSync(commondirPath, "utf8").trim() + return path.resolve(gitDir, commondir) + } + return gitDir +} + function walkUpDirectories( file_path: string, file_or_folder: string, @@ -116,8 +127,10 @@ function walkUpDirectories( .match(/gitdir: (.+)/) if (submoduleMatch) { + const gitDir = path.resolve(directory, submoduleMatch[1]) return { - git: path.resolve(path.join(directory, submoduleMatch[1])), + git: gitDir, + commonGit: resolveCommonGitDir(gitDir), repository: directory, } } else { @@ -126,6 +139,7 @@ function walkUpDirectories( } else { return { git: newPath, + commonGit: newPath, repository: directory, } } diff --git a/src/test/suite/git.test.ts b/src/test/suite/git.test.ts index 398d750..a117f65 100644 --- a/src/test/suite/git.test.ts +++ b/src/test/suite/git.test.ts @@ -10,10 +10,12 @@ suite("git", async () => { assert.deepStrictEqual(dir(__dirname), { git: gitPath, + commonGit: gitPath, repository: repoPath, }) assert.deepStrictEqual(dir(repoPath), { git: gitPath, + commonGit: gitPath, repository: repoPath, }) @@ -24,7 +26,30 @@ suite("git", async () => { assert.deepStrictEqual(dir(submodulePath), { git: path.join(repoPath, ".git/modules/test_submodule"), + commonGit: path.join(repoPath, ".git/modules/test_submodule"), repository: submodulePath, }) + + // worktree: gitdir redirect with a commondir file + const worktreeGitDir = path.join(repoPath, ".git/worktrees/my-feature") + fs.mkdirSync(worktreeGitDir, { recursive: true }) + fs.writeFileSync(path.join(worktreeGitDir, "commondir"), "../..") + + const worktreePath = path.join(__dirname, "test_worktree") + fs.mkdirSync(worktreePath, { recursive: true }) + fs.writeFileSync( + path.join(worktreePath, ".git"), + `gitdir: ${worktreeGitDir}`, + ) + + assert.deepStrictEqual(dir(worktreePath), { + git: worktreeGitDir, + commonGit: gitPath, + repository: worktreePath, + }) + + // cleanup + fs.rmSync(worktreePath, { recursive: true }) + fs.rmSync(worktreeGitDir, { recursive: true }) }) })