dsh-worktree-space
Verifieddsh-worktree-space · v1.0.4 · MIT · Web UI
Per-task Git worktrees for DeepSeek Harness: a task space spans one or more repositories, is registered as a DSH Workspace, and finishing merges the branches, removes the worktrees and files the documents.
Install
dsh plugin add dsh-worktree-space Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Creators
Readme
Worktree Space
DeepSeek Harness 的 Worktree Space 插件:一个任务可以横跨多个仓库,每个仓库用 Git worktree 各开一份, 共用同一个分支,放在源码树之外的任务空间里,并注册成一个 DSH 工作区,自带独立会话。

简体中文 · English
功能
从会话里建任务。 选源码根、给任务起名、选分支前缀、勾选要横跨的仓库、指定任务空间放哪。每个仓库都会得到 一份位于
<分支前缀><任务名>的 worktree(前缀默认task/),起点可以是各仓库当前的 HEAD, 也可以指定某个分支或提交。注册成工作区,名字是
<上级>/<任务名>,同时开一个会话,工作目录就是这个任务空间 —— Agent 可以 跨仓库改代码,不会动到源码检出。管理页面,分三个视图(两种入口与各自默认值见「管理任务」一节):
- 任务空间视图:把每个任务下面的仓库列在一起(分支、改动数、是否被锁定、是否可清理);
- 工作区视图:哪些工作区可以建任务空间,以及每个工作区里有几个仓库;
- 代码仓库视图:扫到的每个 Git 仓库,以及它链接的 worktree。
三个视图都能搜索,也能用「待处理」筛出需要注意的行(有改动、被锁定、可清理,或状态读取失败); 每行左边的箭头能单独折叠,筛选旁的按钮可以一次全部展开或折叠。
结束任务:在任务行上点「结束任务」。默认把各仓库的分支合并回该仓库当前检出的分支(也就是任务空间的 起点;插件不会切换源码仓库的检出),也可以在对话框里按仓库改成别的分支 —— 那会在一个临时 worktree 里 合并,同样不碰你的检出。然后删掉 worktree,把任务空间里的 文档存到
archived-docs/<工作区名>-<YYYYMMDD-HHMMSS>(不勾选归档,就会连这些文件一起删掉), 最后注销这个工作区。要是该工作区里还有会话在跑,会先拒绝,等它结束或停掉再试。结束任务空间也在这个工作区列表自己的
⋯菜单里 —— 只对确实是任务空间的目录出现。新建任务空间同样在那个
⋯菜单里 —— 只对挂有代码仓库的工作区出现,点开的就是同一个创建对话框。不需要额外服务。 入口开关、扫描深度和目录上限都在插件自己的配置里改(见「配置」)。支持 DSH 主题;界面语言跟着 DSH 的语言设置走;插件列表里的名称、描述和图标也由本插件提供。
任务目录结构
<任务空间根目录>/
├── <任务名>/ 任务空间 —— 同时是会话的工作目录
│ ├── README.md 任务的分支、起点与约定
│ ├── <仓库 A>/ 位于 <分支前缀><任务名> 的 worktree
│ └── <仓库 B>/ 同名分支的 worktree
└── archived-docs/
└── <上级>-<任务名>-20260926-020933/ 归档文档时存到这里
删掉 worktree 不会删除对应的 Git 分支;结束任务会先把分支合并回去,再删 worktree。
兼容性
基于 DSH 0.1.7-rc.1 的客户端契约开发(web profile)。已在 0.1.7-rc.1 上验证:宿主 RPC 路由
能注册,客户端 bundle 不用改就能加载,插件列表里的名称、描述、图标和配置区都正常显示。
使用
安装
从 npm 安装:
dsh plugin --profile web add dsh-worktree-space
插件的挂载行写在 profile 的 cordis.patch.yml —— 本仓库带着 DSH 的 bundle patch,一般会自动生效;
若插件列表里一直没出现,就手动补上:
- id: worktree-space
name: dsh-worktree-space
config:
panelEntry: hide # 「新会话」下方的管理页面入口(默认隐藏)
sidebarEntry: show # 侧边栏底部的快捷入口(默认显示)
scanDepth: 2
maxScanDirectories: 1000
卸载:dsh plugin --profile web remove dsh-worktree-space;更新时先卸载再重新安装。
配置
在界面里改(推荐):侧边栏 →「插件」→ Worktree Space → 配置区,和其它插件的配置在同一处,
改完立刻生效,不用重启。也可以直接改配置文件:DSH 数据目录下 profiles/<profile>/cordis.patch.yml
里这个插件的 config: 区块(见上方示例),改完重启 DSH 生效。
| 设置 | 取值 | 默认 | 说明 |
|---|---|---|---|
| 面板入口(新会话下方) | 显示 / 隐藏 | 隐藏 | 侧边栏面板列表里那一行,整页打开管理页面(页面自带左侧导航和「返回会话」);默认隐藏 |
| 侧边栏底部入口 | 显示 / 隐藏 | 显示 | 侧边栏底部那个快捷入口,以对话框打开同一个管理页面 |
| 扫描深度 | 1–5 层 | 2 层 | 从工作区目录(第 0 层)往下找 Git 仓库的层级数 |
| 最大遍历目录数 | 500 / 1000 / 2000 / 3000 / 5000 / 10000 | 1000 | 一次扫描最多读多少个目录;超过会提示你换一个更小的工作区 |
| 默认分支前缀 | 任意文本 | task/ |
新建任务空间时默认用的前缀;在新建面板里改动并勾选「设为默认分支前缀」,点创建时一并写回这里 |
扫描覆盖全部工作区;按广度优先逐层进行,每层最多同时读 8 个目录。任何一层只要发现 .git 就认定是
仓库;node_modules、dist、build、vendor 等目录和隐藏目录会跳过(.worktrees 除外)。
创建任务

- 在会话里,点输入框上方的 新建 Worktree Space。
- 给任务起名 —— 会转成小写,空格、中文和其它字符都换成连字符(
hotfix-placeorder);名字不合法时 会告诉你哪里不合规。 - 需要的话改 分支前缀。分支名就是这个前缀加上任务名;留空则用配置里的默认前缀(默认
task/), 输入框下面那行会告诉你当前用的是哪个。只有你填的前缀和默认不一致时,才会出现 设为默认分支前缀 勾选框 —— 勾上它,点「创建并打开」时会把这个前缀写回插件设置。 - 设置任务空间放哪。必须在源码树之外,界面会填好推荐的路径。
- 勾选任务要横跨的仓库(每张仓库卡片上标出它当前 HEAD 所在的分支),并选择分支起点。
- 点 创建并打开。新工作区会直接开一个会话,工作目录就是任务空间。
如果任务空间已经建好、但工作区注册失败,对话框会说明原因,并让你重试注册。
管理任务
打开 管理页面,两种入口:
- 侧边栏底部的 Worktree Space(默认显示)—— 以对话框打开;
- 侧边栏「新会话」下方的 Worktree Space 行(默认隐藏,在配置里打开)—— 在主区域整页打开, 页面自带左侧导航:第一项是 返回会话(面板占用了会话所在的主区域,所以留一个明确的回头路), 下面三项切换视图。对话框形态的视图切换仍在工具栏里。
三个视图的区别见「功能」一节:任务空间视图看每个
任务和它的各个仓库,工作区视图看哪些工作区能建任务空间,代码仓库视图看扫到的每个 Git 项目及其 worktree。
右侧的统计会跟着视图变(N 个任务 / N 个工作区 / N 个仓库 · M 个 Worktree),搜索或筛选时显示
可见 / 总数。
面板每次打开都会重新扫描,但会先用宿主记住的上一次扫描结果把界面画出来,所以打开就能看到数据,扫描 结束后自动换成新结果(标题栏会显示「正在扫描所有工作区…」)。这份记忆只放在 DSH 实例的内存里:既不写磁盘, 也会在实例关闭时随之清空。
结束任务

在任务行上点 结束任务,或在工作区列表的 ⋯ 菜单里点 结束任务空间。对话框会先说明接下来会
发生什么:未提交的文件、待合并的提交、合并到哪个分支,以及任务空间里的文档(确实有东西可归档时,
才会出现「归档文档」选项)。默认勾选「合并回目标分支」;「删除分支」和「强制」默认不勾选。
「删除分支」平时需要先有合并:取消勾选合并,它也一起不可用。要放弃一个任务空间而不是结束它 ——什么都不合并,worktree 移除、分支连同上面的提交一起丢弃——同时勾选「强制」即可,那是唯一允许 删除未合并分支的方式。
各选项组合的行为
| 合并回目标分支 | 删除分支 | 强制 | 会发生什么 |
|---|---|---|---|
| ✓ | 每个仓库把任务分支以 --no-ff 合并进它那一行选定的目标分支(默认是该仓库源检出所在的分支);移除 worktree;分支保留。合并冲突的仓库原样保留、其余照常结束 |
||
| ✓ | ✓ | 同上,并在合并成功后删除分支(git branch -d,所以未合并的分支删不掉) |
|
| ✓ | ✓ | 同上,并丢弃 worktree 里未提交的改动(未勾选时,有未提交改动的 worktree 会因 worktree remove 失败而整个保留);分支保留 |
|
| ✓ | ✓ | ✓ | 合并、丢弃未提交改动、强制删除分支(git branch -D);分支已合并,所以并不额外丢东西 |
| 什么都不合并:只移除 worktree 和任务空间,分支保留(随时可以自己合) | |||
| ✓ | 只移除 worktree,丢弃未提交的改动;分支保留 | ||
| ✓ | ✓ | 放弃:不合并,强删分支,分支上未合并的提交一并丢弃 |
无论哪种组合:插件写的 README.en.md 总是被清除;任务空间里其它内容按「归档文档」的选择处理(不勾选就直接丢弃)。未勾选「强制」时,只要某个 worktree 里还有未提交的文件,git worktree remove 就会失败,那个仓库原样保留、记为未完成(其余仓库照常结束),任务空间目录和它的工作区注册也因此都留下——换句话说,不勾强制就绝不会丢未提交的东西。反过来,只有所有仓库都真的移除了、容器空了,任务空间目录和工作区注册才会一起删除,其中的会话落到「未分组」但对话记录保留。
「结束任务」按钮的颜色跟着这件事走:橙色是常规收尾(合并可以回退,没有东西被丢);只有对话框能 点名说清"什么会被丢掉"时才是红色——计划里有未提交的文件而你又勾了强制,或者不合并却要删掉一个 还有提交的分支。