Repository navigation
Description
Split out of #629, which delivered its first three slices and is otherwise done. This is the "later" bullet from that issue, kept separate because the other three were fixes for an app that actively misled you, while this is a feature.
What is missing
There is no WORKTREES section in the sidebar next to SUBMODULES, and no way to add, remove, lock or prune a worktree from the app.
What already exists to build on
git worktree list --porcelainis already read, once per refs reload and off the drawing path (Add basic support for worktree branches (issue #629) #633, Worktree lookup runs git on the main thread while labels are drawn #647, Stop the worktree lookup stalling the history while it draws #656).- The sidebar already knows how to render a group of external things:
submodules = [PBSourceViewItem groupItemWithTitle:@"Submodules"]filled fromrepository.submoduleswithPBSourceViewGitSubmoduleItem. A WORKTREES section would follow that shape, needing arepository.worktreesand aPBSourceViewGitWorktreeItem. - A branch held by another worktree already carries an icon and an Open Worktree menu item, so opening one is solved.
The actual gap
+worktreePathsFromPorcelain:excludingWorktreeAtPath: keeps only what marking branches needed, a branch to path mapping, and only for worktrees other than this one. Everything else in the porcelain output is dropped on the floor:
HEAD, and worktrees with nobranchline at all. A detached worktree would simply not appear in the section, since nothing records it.bare, so the main bare repository cannot be distinguished.lockedand its reason, which a remove action has to respect.prunableand its reason, which is the whole basis of a prune action.- This repository's own worktree, deliberately excluded, which a list should show and mark as current.
So the first piece of work is reading the porcelain into a model rather than into a lookup table. The current parser is right for what it does and should probably stay as the cheap path for the label drawing, which runs far more often than a sidebar reload.
Suggested slices
- parse the full porcelain into a worktree model: path, HEAD, branch or detached, bare, locked with reason, prunable with reason, and which one is ours
- a WORKTREES group in the sidebar listing them, marking the current one and showing locked or prunable state
git worktree prune, and lock/unlockgit worktree add, andgit worktree removerefusing or warning where git wouldgit worktree repairfor a worktree whose folder was moved: offer it on a worktree whose folder is missing, pointing git at where the folder went (git 2.29, as Tower does)
The first two stand on their own and are worth having without the rest.
Slices 1 and 2 landed in #709. Slices 3 and 4 have swapped places: prune and lock/unlock come first, because they bring the git version check and the worktree row menu that remove then builds on. Slice 5 was added later, after looking at how other clients treat a worktree whose folder is gone.
Activity
goneng commentedon Sep 23, 2026
Git version requirements for the remaining slices
GitX accepts any git from 1.6.0 (
MIN_GIT_VERSION), but the worktree commands arrived much later. Checked againstbuiltin/worktree.cat each git tag:worktree add,pruneworktree list --porcelain(read since #709)lock/unlock, with--reasonremove,movelocked/prunablelines in the porcelainlist -zNothing crashes on an older git: a failing command comes back as an error, and before 2.7 the WORKTREES group is simply empty. From 2.7 to 2.30 the porcelain carries no lock or prune state, so every worktree reads as unlocked and not prunable. Apple's git on macOS 13 and later (our deployment target) should be 2.37 or newer, which covers the whole table; the exposure is an older git picked up from
PATHor set in the preferences.The plan:
PBGitBinary, named per feature, and cache the version (+versionrunsgit --versionon every call today).git worktree prune --dry-run --verbose(2.5+), so what it lists does not depend on the porcelain.removebefore 2.17: the only substitute is deleting the folder and pruning, which skips git's check for uncommitted work.worktrees/<id>/lockedto recover lock state before 2.31; the extra code is not worth it when the system git reports it.--porcelain, not-z.MIN_GIT_VERSIONalone, since raising it would change the requirement for every GitX user.The gate lands with slice 3 (prune and lock/unlock), the first slice that needs it.
[Worktree] Prune worktrees, and lock or unlock them
[-]Worktrees: no sidebar section, and no way to add or remove one[/-][+]Enhance: [Worktrees] no sidebar section, and no way to add or remove one[/+][Worktree] Check git's version before offering what it cannot do
[Worktree] Prune worktrees, and lock or unlock them
[Worktree] Check git's version before offering what it cannot do
[Worktree] Prune worktrees, and lock or unlock them
goneng commentedon Sep 29, 2026
All five slices have landed:
Not covered: repairing after the main repository's own folder moves (
git worktree repairwith no path). That can get its own issue if it is wanted.