Repository navigation
How Worktrees Work
Nibtree lists, creates, locks, removes and prunes linked worktrees (git worktree), and opens any worktree folder as a repository. For the user side, see Worktrees.
A linked worktree is a second folder with another branch checked out, sharing the main repository's objects and refs. Its .git is a file that points into <main>/.git/worktrees/<name>. People use worktrees to keep a long-running branch or a hotfix open next to their main work. The app must show them, create them without the user typing paths, and still treat each folder as a normal repository: status, watcher and tabs.
git/worktree.rs runs git worktree list --porcelain and parses its records with parse_porcelain: worktree <path>, HEAD <id>, branch <ref>, detached, bare, locked [reason], prunable [reason]. The first record is the main worktree. list marks the one it was read from as is_current by comparing canonical paths. This is a read through the CLI, an exception to "reads use git2", because the porcelain gives every field (including lock and prune reasons) in one cheap call.
flowchart LR
Sidebar["Sidebar.svelte effect: refs changed"] --> Store["worktreeStore.load(active repo)"]
Store --> Cmd["list_worktrees"]
Cmd --> Git["git worktree list --porcelain"]
Git --> Parse["parse_porcelain + is_current"]
Parse --> Sort["sortedWorktrees: main first, then by path"]
Sort --> Tree["tree.ts: Worktrees section rows"]
worktreeStore keeps only the active repository's list. It reloads whenever the sidebar sees that repository's refs replaced (every refresh), so new or removed worktrees show up without a separate watcher. A failed list (for example an old git) only empties the section.
| Action | Command | git |
|---|---|---|
| New Worktree | add_worktree(repoPath, worktreePath, branch) |
worktree add -- <path> <branch>, worktree add -b <name> -- <path> <base> or --detach
|
| Lock / Unlock |
lock_worktree, unlock_worktree
|
worktree lock [--reason r] -- <path>, worktree unlock -- <path>
|
| Remove | remove_worktree(..., force) |
worktree remove [--force] -- <path> |
| Prune | prune_worktrees |
worktree prune --verbose; the report decides the toast |
| Changes check | worktree_has_changes(worktreePath) |
git2 status with untracked files, without submodules |
WorktreeBranch is a tagged enum: existing { branchName }, new { branchName, baseRef } or detached { baseRef } (the dialog offers the first two). add refuses a relative path, an existing non-empty folder, and values starting with -, and every path goes after --. It returns the canonical path of the new folder.
sequenceDiagram
participant D as NewWorktreeDialog
participant API as api.addWorktree
participant R as git/worktree.rs
participant RS as repoStore
D->>API: repoRoot, folder, { kind: "new", branchName, baseRef }
API->>R: add_worktree
R->>R: git worktree add -b name -- folder base
R-->>D: canonical folder
D->>RS: refreshRepo, worktreeStore.load
alt Open in this window
D->>RS: open(folder)
else Add to workspace
D->>RS: addFolder(folder)
else neither
D->>D: toast "Created worktree ..."
end
NewWorktreeDialog.svelte loads refs and the worktree list. Existing branch lists only availableBranches: local branches not checked out in any worktree, because git refuses those. From offers HEAD, local and remote branches. The folder default is defaultWorktreePath(mainRoot, branch): <repo>-<branch> next to the main worktree, with / and other unsafe characters turned into -. It follows the branch until the user types in the folder field (folderEdited). "Open in this window" and "Add to workspace" are two check boxes that exclude each other.
worktreeActions.ts builds the section and row menus. Remove is disabled for the main, current, locked or prunable worktree. Before removing, worktree_has_changes decides between "Remove Worktree" and "Worktree Has Changes" with Force Remove, both danger confirms. A worktree that is a workspace folder (with other folders left) leaves the workspace first, so no tab points at a deleted folder.
git2 opens a linked worktree folder like any repository. RepoInfo.worktree is repo.is_worktree(), set by git/repo.rs and the workspace scan, and the Changes sidebar shows a worktree badge. The watcher maps git dirs that are not <root>/.git (git_dir_links in watcher.rs): changes inside <main>/.git/worktrees/<name> are rewritten to the worktree's own .git path (relink), so its HEAD and index changes refresh it. The shelf lives in the common git dir and is shared (see How the Shelf Works).
| File | What it does |
|---|---|
src-tauri/src/git/worktree.rs |
WorktreeInfo, WorktreeBranch, porcelain parser, add, remove, lock, unlock, prune, has_changes
|
src-tauri/src/commands/worktree.rs |
The seven *_worktree* commands |
src-tauri/src/watcher.rs |
git_dir_links, relink for external git dirs |
src/lib/views/git/worktrees/worktreeStore.svelte.ts |
The active repository's list |
src/lib/views/git/worktrees/worktreeActions.ts |
Menus and actions |
src/lib/views/git/worktrees/worktreeModel.ts |
Labels, tooltip, default folder, validation, sort |
src/lib/views/git/worktrees/NewWorktreeDialog.svelte |
The New Worktree dialog |
src/lib/views/sidebar/tree.ts, RowContent.svelte, src/lib/views/Sidebar.svelte
|
The Worktrees section, its rows, tags and + button |
src/lib/menu/menuSpec.ts, menuActions.ts
|
Git > Worktrees |
Folder next to the main worktree. A sibling folder is easy to find, never ends up inside the repository (where it would show as untracked), and the name says which branch it holds.
Only branches git will accept. Filtering out checked-out branches in the dialog avoids a git error after the user filled in the form.
Reload with refs, not a watcher. Worktrees change rarely and always change refs or the repository's git dir, which the existing refresh already sees.
Force only after asking. Removing a worktree with changes loses them, so the danger confirm names that case and only then passes force.
-
src-tauri/src/git/worktree.rs:parses_every_porcelain_field;adds_lists_locks_removes_and_prunes_worktrees(new and existing branch, the current worktree seen from a linked one, a non-empty folder refused, lock with a reason and unlock, a dirty worktree needs force, prune of a deleted folder);a_worktree_folder_opens_as_a_repository(workspace scan,worktreeflag, status of its own). -
src-tauri/src/commands/tests.rs:open_workspace_finds_linked_worktrees. -
src/lib/views/git/worktrees/worktreeModel.test.ts: labels, default folder, main worktree lookup, validation and available branches.
- Update this page when
git/worktree.rs,commands/worktree.rsorsrc/lib/views/git/worktrees/change. - Update Worktrees for any change to the section, the menus or the dialog, and retake
worktrees-section.pngandworktrees-new-dialog.png. - The commands are listed in Commands and Events; the sidebar in How Branches and Tags Work.
None yet.
These pages are generated from docs/wiki. To correct something, open a pull request against the source file; edits made here are overwritten.
Using Nibtree
- Getting Started
- Welcome Screen
- Workspaces
- Files Panel
- File Operations
- File Icons
- Rounded Panels
- Editor and Tabs
- Pin Reorder and Wrap Tabs
- Single Tab Title
- Split Editor
- New File and Unsaved Changes
- Unload Hidden Tabs
- Editing Code
- Code Appearance
- Markdown Editor
- Image and PDF Preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and Replace
- Changes and Commits
- Sign In Prompts
- Commit Box Layout
- Repository Actions
- Commit Options
- Ignoring Files
- Diffs
- Inline Diffs
- Staging View
- Revert a Change
- Resolving Conflicts
- Merge Tool
- Blame
- History and Log
- Merge Commits
- Branches and Tags
- Branches Popup
- Remotes
- Stashes
- Shelf
- Git Menu
- Git Dialogs
- Interactive Rebase
- Worktrees
- AI Agents
- AI Tasks
- AI Usage
- Keep Computer Awake
- Submodules
- Git LFS
- GitHub
- Git Console
- Terminal
- Terminal Features
- Scripts
- Navigation
- Menus
- Settings
- Settings Search
- Color Themes
- Settings Terminal and Automation
- Settings Files
- Updates
- Status Bar and Help
- Notifications
- Memory Use
- Clear Cache
- MCP and CLI
- Git Mergetool
- Keyboard Shortcuts
- Keyboard Shortcuts Editor
- Troubleshooting
- Troubleshooting Git
Developers
- Developer Guide
- Architecture
- Project Layout
- Backend
- How Folder Watching Works
- Folder Watching Bugs We Fixed
- How Workspace Files Work
- How the Preview Scheme Works
- Backend Services
- How Terminal Features Work
- Terminal Bugs We Fixed
- Frontend
- How the Rich Markdown Editor Works
- Rich Markdown Bugs We Fixed
- Git Menu Links
- Menu Keys and Routing
- Frontend Modules
- Blame Bugs We Fixed
- Project Color And Title Bar
- One Diff View
- Diff Bugs We Fixed
- Merge Tool Layouts
- Merge Tool Bugs We Fixed
- Color Theme Bugs We Fixed
- How the Connected Diff Works
- Rounded Panels Bugs We Fixed
- Update Bugs We Fixed
- Status Bar Bugs We Fixed
- MCP and CLI Bugs We Fixed
- Repository Actions Bugs We Fixed
- How the Changes Tab Works
- CodeMirror Patterns
- How the Cursor Works
- How Editor Features Work
- How the Path Bar Works
- Commands and Events
- Settings Reference
- Commands Workspace and Changes
- Commands Branches and Remotes
- Commands History and Extras
- Commands App and Tools
- Testing
- Test Suites
- Debugging
- Debugging with MCP
- Measuring Setting Memory
- How Terminal Memory Is Measured
- How Markdown Diagrams Work
- Releases and CI
- Publishing the Wiki
- Versioning and Changelog
- Browser Version Packages
- Browser Release Checks
- Docker Image
- Platforms and Signing
- Windows Support
- Windows Bugs We Fixed
- Windows MCP and CLI
- Docs and Screenshots
- UI Library
- UI Library MCP
- UI Library Bugs
- UI Library Migration
- Contributing
How features work
- Welcome screen
- Workspaces and folders
- Files panel
- File operations
- File icons
- Editor and tabs
- Pin, reorder and wrap tabs
- Single tab title
- Split editor
- New File and unsaved changes
- Unload hidden tabs
- Editing code
- Code appearance
- Markdown editor
- Image and PDF preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and replace
- Changes and commits
- Sign-in prompts
- Commit box layout
- Repository actions
- Commit options
- Ignoring files
- Diffs
- Inline diffs
- Staging view
- Revert a change
- Resolving conflicts
- Merge tool
- Blame
- History and log
- Merge commits
- Commit tabs
- Branches and tags
- Branches popup
- Remotes
- Stashes
- Shelf
- Git menu
- Git dialogs
- Interactive rebase
- Worktrees
- AI agents
- AI usage
- Keep computer awake
- AI tasks
- Submodules
- Git LFS
- GitHub account
- Git Console
- Back and Forward
- Integrated terminal
- Scripts tool window
- Menu bar
- Settings
- Search in Settings
- Color themes
- Rounded panels
- Updates and release channels
- Status bar and help links
- Notifications
- Memory readout and memory log
- Clear Cache
- MCP server and command line tool
- git mergetool mode