From e17ed2484ce8dfaebc0c7c3ad9d9d2d4a0b7d2c3 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 8 Aug 2026 09:29:20 +0200 Subject: [PATCH] Use the work tree as the repo path when it is the main worktree RepoPath() is meant to be the same as WorktreePath() when we're in the main worktree, but we derived it from the git dir's location instead. That is only the same thing when the git dir lives inside the work tree. With core.worktree, --work-tree, or a .git file pointing at a repo dir that isn't called .git, it lands on a directory that isn't a worktree at all, and the repo name we show follows it there. A worktree that has the repo's common git dir to itself is the main worktree, so use its path. That subsumes the submodule case, whose git dir lives under the superproject's .git/modules but is still the submodule's own common dir; --show-superproject-working-tree is now only needed for a linked worktree of a submodule. The existing bare repo test asserted a git output that can't occur (a work tree and --is-bare-repository=true at once), but the rest of it is the shape of a repo opened with --git-dir/--work-tree, where the new repo path is the correct one. Co-Authored-By: Claude Opus 5 (1M context) --- pkg/commands/git_commands/repo_paths.go | 27 +++++++++++++++----- pkg/commands/git_commands/repo_paths_test.go | 20 +++------------ 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/pkg/commands/git_commands/repo_paths.go b/pkg/commands/git_commands/repo_paths.go index c64debfc5..6783c0971 100644 --- a/pkg/commands/git_commands/repo_paths.go +++ b/pkg/commands/git_commands/repo_paths.go @@ -95,15 +95,30 @@ func GetRepoPathsForDir( repoGitDirPath := gitDirResults[2] isBareRepo := gitDirResults[3] == "true" - // If we're in a submodule, --show-superproject-working-tree will return - // a value, meaning gitDirResults will be length 5. In that case - // return the worktree path as the repoPath. Otherwise we're in a - // normal repo or a worktree so return the parent of the git common - // dir (repoGitDirPath) + // A worktree that has the repo's common git dir to itself is the repo's main + // worktree, so it is the repoPath. That holds for a submodule as well: its + // git dir lives under the superproject's .git/modules, but it is still the + // submodule's own common dir. + isMainWorktree := worktreeGitDirPath == repoGitDirPath + + // If we're in a submodule, --show-superproject-working-tree will return a + // value, meaning gitDirResults will be length 5. That only tells us anything + // new for a linked worktree of a submodule, which isMainWorktree misses. isSubmodule := len(gitDirResults) == 5 + // Otherwise we're in a linked worktree, and the repoPath is the repo's main + // worktree. git won't tell us where that is: `git worktree list` reports it + // as the common git dir with a trailing "/.git" removed, which is this same + // derivation. So take the directory holding the common git dir. That is the + // main worktree of an ordinary repo, and of a bare one it is the directory + // its worktrees live in. It is not the main worktree of a repo that moved + // that elsewhere with core.worktree; there we end up naming the git dir's + // directory, which means that the repo name we display in the status panel + // isn't correct, and we start looking for .lazygit.yml in the wrong place. + // Both of those are not severe enough to justify the extra git call to get + // the real main worktree, so we accept this for this rather niche use case. var repoPath string - if isSubmodule { + if isMainWorktree || isSubmodule { repoPath = worktreePath } else { repoPath = filepath.Dir(repoGitDirPath) diff --git a/pkg/commands/git_commands/repo_paths_test.go b/pkg/commands/git_commands/repo_paths_test.go index 54da6b978..25fd1b2e0 100644 --- a/pkg/commands/git_commands/repo_paths_test.go +++ b/pkg/commands/git_commands/repo_paths_test.go @@ -109,16 +109,16 @@ func TestGetRepoPaths(t *testing.T) { Expected: lo.Ternary(runtime.GOOS == "windows", &RepoPaths{ worktreePath: `C:\path\to\repo`, worktreeGitDirPath: `C:\path\to\bare_repo\bare.git`, - repoPath: `C:\path\to\bare_repo`, + repoPath: `C:\path\to\repo`, repoGitDirPath: `C:\path\to\bare_repo\bare.git`, - repoName: `bare_repo`, + repoName: `repo`, isBareRepo: true, }, &RepoPaths{ worktreePath: "/path/to/repo", worktreeGitDirPath: "/path/to/bare_repo/bare.git", - repoPath: "/path/to/bare_repo", + repoPath: "/path/to/repo", repoGitDirPath: "/path/to/bare_repo/bare.git", - repoName: "bare_repo", + repoName: "repo", isBareRepo: true, }), Err: nil, @@ -159,28 +159,16 @@ func TestGetRepoPaths(t *testing.T) { Expected: lo.Ternary(runtime.GOOS == "windows", &RepoPaths{ worktreePath: `C:\path\to\worktree`, worktreeGitDirPath: `C:\path\to\repo\.git`, - /* EXPECTED: repoPath: `C:\path\to\worktree`, - ACTUAL: */ - repoPath: `C:\path\to\repo`, repoGitDirPath: `C:\path\to\repo\.git`, - /* EXPECTED: repoName: `worktree`, - ACTUAL: */ - repoName: `repo`, isBareRepo: false, }, &RepoPaths{ worktreePath: "/path/to/worktree", worktreeGitDirPath: "/path/to/repo/.git", - /* EXPECTED: repoPath: "/path/to/worktree", - ACTUAL: */ - repoPath: "/path/to/repo", repoGitDirPath: "/path/to/repo/.git", - /* EXPECTED: repoName: "worktree", - ACTUAL: */ - repoName: "repo", isBareRepo: false, }), Err: nil,