@@ -84,7 +84,7 @@ func runStatus(cmd *cobra.Command, args []string) error {
8484 // Print worktrees
8585 fmt .Println ("Worktrees:" )
8686 fmt .Printf (" %-20s %-30s %s\n " , "BRANCH" , "PATH" , "STATUS" )
87- var unmanagedWorktrees []string
87+ var warningWorktrees []worktreeWarning
8888
8989 // Determine which worktree we're currently in
9090 cwdAbs , _ := filepath .Abs (cwd )
@@ -97,6 +97,9 @@ func runStatus(cmd *cobra.Command, args []string) error {
9797 }
9898 }
9999
100+ // Track branches that have worktrees
101+ worktreeBranches := make (map [string ]bool )
102+
100103 for _ , wt := range worktrees {
101104 prefix := " "
102105 // Check if current directory is within this worktree
@@ -108,6 +111,8 @@ func runStatus(cmd *cobra.Command, args []string) error {
108111 branchName := wt .Branch
109112 if branchName == "" {
110113 branchName = "(detached)"
114+ } else {
115+ worktreeBranches [branchName ] = true
111116 }
112117
113118 // Check if this worktree is broken (path doesn't exist)
@@ -120,22 +125,54 @@ func runStatus(cmd *cobra.Command, args []string) error {
120125 "[Broken]" ,
121126 " ⚠️" ,
122127 )
128+ warningWorktrees = append (warningWorktrees , worktreeWarning {
129+ path : wt .Path ,
130+ branch : branchName ,
131+ reasons : []string {"broken" },
132+ })
123133 continue
124134 }
125135
126- // Check if managed and not nested inside another worktree
127- managed := wtMgr .IsManaged (wt .Path ) && ! wtMgr .IsNestedInWorktree (wt .Path , allWorktreePaths )
136+ // Determine detailed status flags
137+ var statusParts []string
138+ var reasons []string
139+
140+ isInRepoRoot := wtMgr .IsManaged (wt .Path )
141+ isNested := wtMgr .IsNestedInWorktree (wt .Path , allWorktreePaths )
142+
143+ // Check path-branch name mismatch
144+ relPath , _ := filepath .Rel (repoRoot , wt .Path )
145+ nameMismatch := false
146+ if branchName != "(detached)" && relPath != branchName {
147+ nameMismatch = true
148+ }
149+
150+ if ! isInRepoRoot {
151+ statusParts = append (statusParts , "Outside root" )
152+ reasons = append (reasons , "outside-root" )
153+ }
154+ if isNested {
155+ statusParts = append (statusParts , "Nested" )
156+ reasons = append (reasons , "nested" )
157+ }
158+ if nameMismatch {
159+ statusParts = append (statusParts , "Name mismatch" )
160+ reasons = append (reasons , "name-mismatch" )
161+ }
162+
128163 status := "[Managed]"
129164 statusSymbol := ""
130-
131- if ! managed {
132- status = "[Unmanaged]"
165+ if len (statusParts ) > 0 {
166+ status = "[" + strings .Join (statusParts , ", " ) + "]"
133167 statusSymbol = " ⚠️"
134- unmanagedWorktrees = append (unmanagedWorktrees , wt .Path )
168+ warningWorktrees = append (warningWorktrees , worktreeWarning {
169+ path : wt .Path ,
170+ branch : branchName ,
171+ relPath : relPath ,
172+ reasons : reasons ,
173+ })
135174 }
136175
137- relPath , _ := filepath .Rel (repoRoot , wt .Path )
138-
139176 fmt .Printf (" %s %-20s %-30s %s%s\n " ,
140177 prefix ,
141178 branchName ,
@@ -147,8 +184,27 @@ func runStatus(cmd *cobra.Command, args []string) error {
147184
148185 fmt .Println ()
149186
187+ // Print local branches without worktrees
188+ localBranches , err := wtMgr .ListLocalBranches ()
189+ if err == nil {
190+ var orphanBranches []string
191+ for _ , branch := range localBranches {
192+ if ! worktreeBranches [branch ] {
193+ orphanBranches = append (orphanBranches , branch )
194+ }
195+ }
196+ if len (orphanBranches ) > 0 {
197+ fmt .Println ("Branches without worktrees:" )
198+ for _ , branch := range orphanBranches {
199+ fmt .Printf (" %-20s (no worktree)\n " , branch )
200+ }
201+ fmt .Println ()
202+ }
203+ }
204+
150205 // Print warnings
151- if len (unmanagedWorktrees ) > 0 || len (brokenWorktrees ) > 0 || defaultBranchMissing {
206+ hasWarnings := len (warningWorktrees ) > 0 || len (brokenWorktrees ) > 0 || defaultBranchMissing
207+ if hasWarnings {
152208 fmt .Println ("Warnings:" )
153209 if defaultBranchMissing {
154210 fmt .Printf (" - Default branch worktree '%s' does not exist\n " , mgr .Config .Repository .DefaultBranch )
@@ -157,14 +213,24 @@ func runStatus(cmd *cobra.Command, args []string) error {
157213 fmt .Println (" - Use 'main' as default: bt config default-branch --unset" )
158214 fmt .Println (" - Or set your default branch: bt config default-branch <branch>" )
159215 }
160- for _ , path := range unmanagedWorktrees {
161- fmt .Printf (" - Worktree at %s is outside managed directory\n " , path )
162- fmt .Printf (" Run 'bt repair %s' to fix it\n " , path )
163- }
164- for _ , bw := range brokenWorktrees {
165- fmt .Printf (" - Worktree '%s' has broken path (moved or deleted)\n " , bw .branch )
166- fmt .Printf (" Last known: %s\n " , bw .oldPath )
167- fmt .Printf (" Run 'bt repair --fix-paths /new/path' to fix it\n " )
216+ for _ , ww := range warningWorktrees {
217+ for _ , reason := range ww .reasons {
218+ switch reason {
219+ case "outside-root" :
220+ fmt .Printf (" - Worktree '%s' at %s is outside repository root\n " , ww .branch , ww .path )
221+ fmt .Printf (" Run 'bt repair %s' to move it inside\n " , ww .path )
222+ case "nested" :
223+ fmt .Printf (" - Worktree '%s' at %s is nested inside another worktree\n " , ww .branch , ww .relPath )
224+ fmt .Printf (" Run 'bt repair %s' to fix it\n " , ww .path )
225+ case "name-mismatch" :
226+ fmt .Printf (" - Worktree '%s' path '%s' does not match branch name\n " , ww .branch , ww .relPath )
227+ fmt .Printf (" Expected path: %s\n " , ww .branch )
228+ fmt .Printf (" Run 'bt repair %s' to rename it\n " , ww .path )
229+ case "broken" :
230+ fmt .Printf (" - Worktree '%s' has broken path (moved or deleted)\n " , ww .branch )
231+ fmt .Printf (" Run 'bt repair --fix-paths /new/path' to fix it\n " )
232+ }
233+ }
168234 }
169235 fmt .Println ()
170236 }
@@ -277,6 +343,14 @@ func joinWorktrees(names []string) string {
277343 return result
278344}
279345
346+ // worktreeWarning holds details about a worktree issue for the warnings section
347+ type worktreeWarning struct {
348+ path string
349+ branch string
350+ relPath string
351+ reasons []string // "outside-root", "nested", "name-mismatch", "broken"
352+ }
353+
280354// isPathWithin checks if childPath is within parentPath
281355func isPathWithin (childPath , parentPath string ) bool {
282356 // Clean and ensure trailing separator for accurate prefix matching
0 commit comments