Branch switching and isolated git worktrees as real workspaces, from the Web UI composer.
Install
# from npm (prebuilt)
dsh plugin --profile web add @laoyuehanni/dsh-git-worktree
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:LaoYueHanNi/dsh-git-worktree
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README

简体中文 | English
A dsh plugin for simple branch & worktree management in the Web UI. The composer tool row shows the current branch: pick another to switch in place, or flip the Worktree toggle to get an isolated worktree as a real workspace — as shown in the screenshot above.
Repo: https://github.com/LaoYueHanNi/dsh-git-worktree
[!IMPORTANT] GitHub direct installs have ended — the repository no longer carries prebuilt output. Install from npm instead:
dsh plugin --profile web add @laoyuehanni/dsh-git-worktreeUpgrading from a legacy
github:install (≤ 0.3.2, package namedsh-git-worktree)? An in-placeupdatefails to load — remove the old name first, then add again. Worktree folders and the plugin's settings carry over untouched.
Features
- IDEA-style branch picker: the branch menu treats
/as a folder hierarchy — collapsible folders, last-segment labels, the checked-out branch's chain opens centered. Local and remote branches render as two collapsible groups (a single remote strips its prefix), with bottom search (ancestor folders kept, hits highlighted), locate-current-branch and expand/collapse tools, and ↑N/↓N divergence marks on tracking branches. - Remote branch checkout: pick
origin/feat-xin the remote group and it checks out in place with a tracking branch directly (no confirmation); the worktree toggle sends the pick to an isolated worktree instead. - Row context menu: right-click a branch row for six verbs — check out (immediate, no confirmation), new branch, new branch and check out, rename branch (local rows), delete branch (local rows, the safe
-d: git refuses unmerged commits and occupied branches), copy branch; a worktree row offers go-to-worktree, copy path, and remove worktree. Second-level dialogs open IN PLACE of the menu; in-place actions keep the menu open, so rows can be acted on in a run. Keyboard: arrow keys + Enter. - Worktree quick hop: the main checkout's blank-session menu groups branches held by live worktrees under Worktrees (hover shows the directory) — the row menu's "Go to this worktree" hops straight into that directory and starts a fresh session.
- Branch switching: pick a branch — an in-place switch, no confirmation. Inside a linked worktree the entry scopes down: other branches stay listed but dimmed, with a hint to act from the main checkout; a started session's menu shows only its own branch (fetch and update still work).
- Create from any branch, rename in place: right-clicking any branch row creates FROM that branch (checkouts untouched) or creates-and-checks-out (checked out on the spot); the create flyout validates as you type (git ref rules plus a duplicate check) and fires in one stroke, a failure keeping it open for a renamed retry. Local rows rename in place too.
- Remote sync: the last toolbar tool fetches every remote and prunes stale tracking branches — the list refreshes in place, no terminal round-trip.
- Branch update: update the CURRENT branch to its upstream (fast-forward only); divergence, a missing upstream, or conflicting uncommitted changes are refused with git's own explanation — the plugin never stashes or rewrites history on your behalf.
- Worktree isolation: in a session that has not started, right-clicking any branch row offers Create worktree (reuse or fresh directory) or New branch and worktree (cut a new branch off that row, name typed by hand); confirming isolates into
<repo>/.dsh/gitworktree/<branch>/inside the repository (locally ignored through.git/info/exclude— the repo'sgit statusstays clean) and registers a real workspace, with same-branch re-creates reusing the existing worktree wherever it lives. Once the session starts the directory is fixed — the worktree verbs hide along with the Worktrees group. - Worktree removal: the Worktrees group's row menu (and the manager dialog) offers Remove worktree — the confirm first counts uncommitted files (red) and ahead commits, and warns the workspace's sessions will be archived; confirming removes the git worktree (the branch itself survives), then archives the sessions and drops the workspace registration. A git failure leaves the DSH side untouched and retries in place. A directory with a running session withholds the verb.
- Worktree manager: the plugin's configuration page on Settings → Plugins opens a dialog listing every worktree across both storage locations — the per-repository
.dsh/gitworktreelayouts (new) and the legacy central root (old, kept for existing worktrees) — grouped by repository with a source badge, orphan directories included. - Legacy storage, read-only: the same page shows the historical central storage root (
~/.dsh/gitworktreeby default) read-only — existing worktrees stay put and keep working; new ones are created inside their repository. A legacy~/.dsh/gitworktree/settings.jsonvalue migrates automatically on upgrade.
[!NOTE]
- The native sidebar is untouched: worktrees are ordinary registered workspaces, and the workspace tree nests the per-repository layouts under their repository automatically (existing centrally-stored worktrees keep their old location — only new ones nest).
git clean -xdff(double-f) deletes the in-repository worktree directories (a single-fskips nested repositories).git worktree prunerestores the registrations afterwards, but uncommitted work inside them is lost.- If every workspace of a repository is deregistered, its worktrees no longer appear in the manager (or the auto-prune); re-register any directory of that repository to bring them back.
Install
dsh plugin --profile web add @laoyuehanni/dsh-git-worktree
The package declares
dsh.bundle, soaddwires the plugin into the profile's layer stack automatically — no config editing needed. Requires thewebprofile (dsh web) and a dsh 0.2.0-rc.1 (or later) host.
Running a dsh 0.1.2 alpha host? Install the dedicated compatibility build instead:
dsh plugin --profile web add @laoyuehanni/dsh-git-worktree@dsh-alpha
@dsh-alphais a dist-tag resolving to the latest alpha-host compatibility build (currently0.4.3-dsh-0.1.2-alpha.5) with peers pinned to the alpha line — a plainupdatenever mixes the two channels. On 0.2.0-rc.1 or later, use the default line above.
Update
dsh plugin --profile web update @laoyuehanni/dsh-git-worktree
Remove
dsh plugin --profile web remove @laoyuehanni/dsh-git-worktree
Worktree folders are kept at both locations (the per-repository .dsh/gitworktree layouts and the legacy central root); the plugin's own settings live in the dsh settings document.
Development
Build once, install a symlink, iterate:
pnpm install
pnpm build:all
pnpm test # vitest
node scripts/smoke.mjs # real-git smoke over the built lib
dsh plugin --profile web add link:D:/Code/dsh-worktree
Rebuild and restart dsh web to apply changes (pnpm watch:client in the plugin directory hot-reloads the client). No prepare script by design — lib/ never enters the repo; pnpm publish builds it fresh into the tarball.
Temporary host-only mount (this launch only, no profile changes): create a cordis.yml next to the repo pointing at the built host half (Windows needs the file:/// form), then launch with it:
- insert:
- id: git-worktree
name: 'file:///D:/Code/dsh-worktree/lib/index.js'
dsh web --patch <plugin-dir>/cordis.yml
Only the host half mounts in this mode (the /plugin/git-worktree/* routes keep working); for UI work use the link: install above.
Links
More in this category
zhu1090093659/dsh-web#packages/dsh-git-graph★ 8178
Git branch selector and Git graph for the dsh web GUI: switch branches and explore branch-lane and commit history from the conversation header.
Akimiya-z/codex-guard#dsh★ 139
Pre-submit pull-request hygiene checks inside DeepSeek Harness: scans the current diff for TODO leftovers, hardcoded secrets, and non-conventional commit subjects.
Cerbur/clutch-dsh#clutch-dsh-worktree★ 30
Adds a Worktree view to DSH Web UI that groups Sessions by Git worktree while keeping DSH as the source of truth.
lehhair/dsh-diff-viewer★ 26
PiUI-style diff viewer replacing the stock DiffBlock for write/edit tool calls.
DietCokewithSugar/dsh-user-experience★ 20
Finds potential UX issues in your project: automatically reviews React/TypeScript code, pinpoints each problem, and gives concrete suggestions.
DamonKoy/dsh-web-ui#dsh-git-graph★ 19
Git branch selector and Git graph in the conversation header of the dsh web GUI.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.