.Remotes, .WorktreeCount and .RepoName are wrong outside a repository's main working tree
Code of Conduct
- I agree to follow this project's Code of Conduct
What happened?
Measured across ten positions (plain clone; a clone with two linked worktrees; --separate-git-dir
plus its own linked worktree; a bare-via-.git-file layout plus its worktree; a submodule plus its own
linked worktree):
| Position | .Ref |
.WorktreeCount |
len .Remotes |
.RepoName |
|---|---|---|---|---|
| plain clone | main |
0 | 2 | correct |
| clone + worktrees, main working tree | main |
2 | 2 | correct |
| linked worktree of that clone | ok | 0 ✗ (2) | 0 ✗ (2) | correct |
--separate-git-dir clone |
main |
0 | 0 ✗ (2) | correct |
| linked worktree of that | correct branch | 0 ✗ (1) | 0 ✗ (2) | empty ✗ |
bare-via-.git-file, root |
empty ✗ | 0 ✗ (1) | 1 | correct |
| linked worktree of that | main |
0 ✗ (1) | 0 ✗ (1) | empty ✗ |
| submodule, primary | main |
1 | 2 | correct |
| linked worktree of a submodule | correct branch | 1 | 0 ✗ (2) | empty ✗ |
The worst case: without fetch_status, a submodule's linked worktree displays the primary
submodule's branch, not its own. The checkout is on subfeature; the prompt says main. Verified
directly — the common module directory's HEAD holds ref: refs/heads/main, the worktree admin
directory's HEAD holds ref: refs/heads/subfeature, and the segment reads the former.
Root cause: hasWorktree (src/segments/git.go:450-525) repoints g.scmDir to the common git
directory in a linked worktree but leaves g.mainSCMDir at the per-worktree metadata directory (or, in
--separate-git-dir/bare layouts, at the working-tree root) — the opposite of what a submodule's own
linked worktree needs, where the common-vs-per-worktree split runs the other way. Every reader that
needs the common directory but is handed the wrong one breaks the same way:
getGitConfig()(:624-643) readsconfigfrommainSCMDir→Remotes()(:1239-1259) returns the empty map wherever that's wrong, with no fallback (unlikegetRemoteURL()/getPushRemote()).WorktreeCount()(:1108-1128) looks for<mainSCMDir>/worktrees, a path that only exists in the main working tree of a plain clone.repoName()(:1285-1296) searchesmainSCMDirfor the literal substring.git/worktrees— empty in any layout whose git directory isn't literally named.git(e.g. a.barelayout), or whose common directory isn't where the search expects.
This is not an exotic-layout problem: tools that automate worktrees (agent sessions, git-town,
ad-hoc scripts) create them in a directory of their own choosing — the repository stays an ordinary
clone, and all three fields break as soon as the prompt renders inside one of those worktrees.
Expected: .Remotes, .WorktreeCount and .RepoName read from the repository's actual common git
directory in every layout, and a submodule's linked worktree reports its own branch, not its parent's.
Theme
version: 3
final_space: false
blocks:
- type: prompt
alignment: left
segments:
- type: git
style: plain
properties:
fetch_status: true
template: 'Ref={{ .Ref }} Remotes={{ len .Remotes }} WT#={{ .WorktreeCount }} Repo={{ .RepoName }}'git clone <url> repo
git -C repo worktree add /somewhere/else/feature feature
oh-my-posh print primary --plain --config ./wt.omp.yaml --pwd /somewhere/else/feature --shell zsh
# Remotes=0 WT#=0 — both wrong; git -C /somewhere/else/feature remote -v and
# git -C /somewhere/else/feature worktree list show the truthWhat OS are you seeing the problem on?
Linux, macOS, Windows
Which shell are you using?
zsh
Log output
[TRACE] terminal.go:FileContent(/repo/.git/worktrees/feature/config) - 12µs # no such file
[DEBUG] git.go:getGitConfig → error memoized in sync.Once; Remotes() returns the empty map
[DEBUG] terminal.go:HasFolder(/repo/.git/worktrees/feature/worktrees) → false; WorktreeCount() = 0Source: JanDeDobbeleer/oh-my-posh