中文EN

dsh-git-idea

git已测通过npmMIT

照着 IDEA 的 VCS 做的 Git 集成,装进 DSH 会话:输入框「权限模式」旁边的 Git 图标显示当前分支与未提交改动数,悬停可切分支,点击弹出 IDEA 风格的面板(分支树、提交图、变更与暂存、提交详情、文件差异),另有一个设置页管提交身份、git 位置和网络参数。不向 DSH 注册任何模型工具。

下载量 / Downloads
1,358
依赖体积 / node_modules
1.52 MB
测试时间 / Tested
2026-11-06
DSH 版本 / Version
0.2.2-rc.1

安装

dsh plugin --profile web add dsh-git-idea

沙箱测试结果

阶段结果
1 安装✓
2 列装✓
3 挂载✓
4 启动—

四阶段在隔离沙箱里跑:安装(有网)→ 列装 → 挂载 → 启动(后三步断网)。

README

dsh-git-idea

照着 IDEA 的 VCS 做的 Git 集成,装进 DSH 会话:输入框「权限模式」旁边一个 Git 图标 —— 显示当前分支与未提交改动数,悬停切分支,点击弹出 IDEA 风格的面板(分支树、提交历史与提交图、变更与暂存、提交详情、文件差异),另有一个设置页管提交身份、git 位置和网络参数。

不向 DSH 注册任何模型工具(模型要跑 git 本来就有 bash,见[不注册工具](#不注册工具))。

面板属于会话,不属于窗口:同一页面里的每个会话各看各的工作区。

看得见 DSH 的工作树:模型用官方的 create_worktree 把会话搬进一棵链接工作树之后,chip 和面板跟着搬过去(分支、改动、历史都是那一棵的),头上多一颗工作树身份。插件不建树、不删树、不搬会话,只把已经发生的事说清楚 —— 见[工作树](#工作树)。

Git integration for DeepSeek Harness, modelled on IDEA's VCS — a git icon beside the permission mode in the composer (branch + pending count), a branch switcher on hover, an IDEA-style VCS panel on click, and a settings page. Registers no model tools with DSH, and follows a session into the worktree DSH's create_worktree moved it to.

当前版本 · 0.3.0

下载 / 安装 · dsh plugin --profile web add dsh-git-idea(npm)· github:mays-hi/dsh-git-idea(GitHub)· 本地目录

依赖 · DSH >=0.1.5-rc.1(engines.dsh,只声明最低版本);@deepseek-ai/cordis ^4.0.2(peer)

仓库 · <https://github.com/mays-hi/dsh-git-idea>


安装

要求 DSH >=0.1.5-rc.1(只声明最低版本;peer:@deepseek-ai/cordis ^4.0.2)。同一份包在 0.1.5 到 0.2 上都能跑,靠的是三处各自探测:

  • 执行器:0.1.7 把一次性 run(spec) 换成了 execute(spec) 加 result() —— 两种形状都认;
  • 会话工作区:0.1.7 的 sessions.get 只回答活着的会话 —— 解析不到时退到 sessionPersistence 读会话头,刚选中、还在恢复的会话因此也能读到;
  • 生效目录与工作树:0.2 起会话的目录可以移动(SessionHeader.cwd 保留原始项目,workingDirectory 投影说现在在哪),官方还给了 create_worktree —— 插件优先读那个投影,没有它时退回监听 session/event 上的 working-directory/change,再退回会话头。工作树清单要 git worktree list,与 DSH 版本无关。
dsh plugin --profile web add dsh-git-idea                    # npm
dsh plugin --profile web add github:mays-hi/dsh-git-idea      # GitHub
dsh plugin --profile web add /path/to/dsh-git-idea            # 本地

装完重启 dsh web。报 ERR_PNPM_ADDING_TO_ROOT 就在包名前加 -w。

已经跑着旧版动态插件(<DSH_HOME>/dsh-git-idea 那个桥)就先停掉 —— 两个都装着就是两份 chip、两个面板抢同一个 slot。

跑在哪儿

DSH 桌面端(dsh-app://app)

面板的每一次读都走 POST /dsh-git-idea/rpc。桌面端不是把这个地址服务给浏览器,而是由 Electron 主进程把它代理给 Host:它删掉 origin(和 sec-fetch-site),改用 Host 自己那张 cookie 重新认证,再转过去。

所以判据不能是「带没带 Origin」。现在问的是平台自己那道门 —— connection.requestRejection,也就是 /api 走的同一条:Host/Origin 围栏(authority 必须是 loopback,或这份部署信任的)加浏览器会话。装在没有这个 Service 的组合里时退回到围栏本身(跨站标记被拒、Origin 必须与 authority 一致、没有 Origin 是正常的)。

旧版在这里要求「Origin 必须存在且等于 Host」,于是桌面端的每一条请求都被判 403,git/panel 一行都回不来 —— 点开 chip 看到的就是一个空面板。

Windows:脚本由谁来读

这个插件的每一条命令都是一个 POSIX sh 脚本([ -d … ]、printf、command -v)。DSH 的 shell 抽象在 Linux/macOS 上由 bash 实现,在 Windows 上由 pwsh 实现 —— 同一个字符串交给 PowerShell 就是一个解析错误,于是每一次读都会变成「这个目录不存在」/「这台机器上找不到 git」。

Windows 上 DSH 的 shell 默认由 pwsh 实现,而插件的每一条命令都是 POSIX sh 脚本 —— 同一个字符串交给 PowerShell 就是一个解析错误。但那是这个部署的选择,不是平台的:shell 是「抽象 bash 执行服务」,同一个 Windows 上也可以装配 bash 那一半。所以先问一句这个 shell 是什么语言($PSVersionTable):它自己就读得懂 POSIX 时,脚本原样交给它,和别的平台走同一条路。

读出是 PowerShell 时,脚本交给一个真的 POSIX shell:Git for Windows 自带的 usr/bin/sh.exe。它在三个默认安装点里找,也在这台机器 PATH 上每个 git.exe 旁边的 usr\bin 里找(装在 Scoop / Chocolatey / IDE 自带 / 自定义目录的 Git 靠这一条);故意不拿 PATH 上那个 bash —— 它是 WSL 的,看不到 D:\ 这样的路径。脚本走 stdin,命令行走的还是同一条 shell 通道,工作目录、超时、输出上限、沙箱策略一样都不少。

找不到 sh.exe 时照旧把脚本原样交出去(与加这段之前完全一致,不换一种坏法),而设置页的「读命令的 shell」那一行会直说这件事 —— 否则屏幕上只有「目录不存在」,指不到真正的原因。

别的平台上这一整段不生效:shell 本来就是 bash。


用法

chip(输入框「权限模式」旁边那个 Git 图标)

操作 · 结果

看 · 当前分支 + 未提交文件数(干净时只有一个分支名,有改动时是 3 那个徽标)。不在仓库里时直接写出原因:不是仓库 / 没有 git / 目录不存在 / 不是目录 / 选择目录 / 读取失败。数字那一格自己说"核对完了没有":核对过、有改动是实心数字;核对过、干净就一个徽标都没有;有旧数字、正在重核是空心的旧数字;连可信数字都还没有(第一次看这个仓库,或者上次是干净的而这次正在重核)是一个空心的 …。转圈的圆环只留给切换分支 —— 核对读的是整棵树,大仓库上 8–10 秒,让图标转那么久就是一颗停不下来的圈

悬停 · 分支切换卡片:切分支,以及工作区里有多个仓库时换一个仓库看(可在设置里关)

点击 · 开 / 收面板

面板

变更 3 │ 历史   ⟳ ⇣ ↓ ↑   feature-risk ↑2 ↓1   树 扁平
─────────────┬──────────────────────┬──────────────────────
分支树        │ 变更树 / 提交列表      │ 差异 / 提交详情 /
HEAD 本地 远程 │                      │ 提交信息与提交按钮

区域 · 内容

顶栏 · 变更(带数量)/ 历史 页签;⟳ 重读、⇣ fetch、↓ pull、↑ push(四个按钮只有记号,名字在 aria-label 里;领先/落后照旧跟在记号后面,↓2 / ↑3);中间是当前分支,点开切换器;一个工作区里不止一个仓库时,多一颗「仓库」chip(写着现在看的是哪一个、一共几个,点开和分支那颗是同一张卡片 —— 见[看哪个仓库](#看哪个仓库));右端「树 / 扁平」切换变更页视图

左栏 · 分支树:HEAD / 本地 / 远程,带搜索、收藏、排序;名字旁边是等着拉 / 等着推的提交数(↓2 / ↑3,和卡片上那一列同一套记号;与上游一致时不标);行尾 › 是该分支的动作(检出、从此分支新建分支、合并到当前分支、删除)

中栏 · 变更 页是工作区,历史 页是提交列表 + 提交图

右栏 · 差异 patch / 提交详情 / 提交信息与提交按钮

分支切换卡片

悬停输入框那颗 chip,或点面板顶栏的分支名,弹出同一张卡片:

部分 · 内容

顶部 · 搜索框;仓库级动作 ⇣ / ↓ / ↑ / + / ☆(只有记号,一句话在 aria-label 里;角标是数字;☆ 收藏的是列表里高亮那一行);右端排序按钮,两种模式两个图标(A→Z / 时钟),当前是哪种只说给读屏

仓库 · 这个工作区里有不止一个仓库时,列表最上面多一段(可折叠):文件夹字形、相对路径、分支、完整路径,当前那一个带 ★。点一行就是让 chip 和面板改看那一个 —— 换的只是「看哪一个」,不搬会话(和面板那张清单同一条规矩)。只有一个仓库时整段不出现

分组 · HEAD 当前分支 / 本地 / 远端。第一组读的是 Host 清单里带 current 那一条 —— 不记得你最近用过什么,当前分支换了它就是新的那一行。远端 那一组列全部远端跟踪分支(本地已有同名的也在,名字压暗一档 —— 本地那一行右边写的是它的上游 origin/dev,远端这一行写的是远端名 origin;IDEA 的 Remote 节点也是全都列,它用嵌套说明这件事,这里是一张平铺清单所以用深浅)

行 · 分支名、当前分支那行还带着未提交改动数(●3 —— 和面板左栏那一行同一个记号,也就是 chip 角标上那个数)、与上游的差异、上游(或远端):差异只有有事可做的行才带记号 —— ↓3 蓝的是等着拉的、↑2 绿的是等着推的(IDEA 的写法,数字直接写在箭头后面);与上游一致、或者根本没有上游,都空着;行尾 › 是这个分支能做的事(检出、从此分支新建分支、合并到当前分支、删除 —— 删除要按两下,被 git 拒绝会多出一个「强制删除」)

行尾那句「从此分支新建分支…」点下去,子菜单收掉、卡片不跟着收:卡片底部留下一行输入框,已经聚焦,写着「以 <那个分支> 为起点的新分支名」—— 回车或者「创建并切换」就建好并切过去,「取消」或 Esc 退回。悬停卡片本来是「指针一离开就收」的,这一行输入框期间它按住不收(两步删除的第二步同理):子菜单收掉之后指针正好落在卡片外面,不按住的话 200ms 后整张卡片会连那个还没打字的输入框一起消失。

悬浮提示:一个都没有

浏览器自己的那个 title 提示框在这个插件里全部去掉了,而且工具条上一个字都不写:顶栏那四个同步动作(⟳ / ⇣ / ↓ / ↑)、中间那四个提交动作(樱桃 / 还原 / 标签 / 分支)、卡片上那排 chip,皮肤上只有记号 —— 名字只说给读屏(aria-label):重新读取仓库(忽略缓存)、拣选:cherry-pick,把这个提交应用到当前分支…… 同一套规则罩着折叠三角、清空 ×、↑2/↓3 的含义、行尾 › 的说明、拖动手柄)。还有一件事用动说而不是用字说:输入框那颗 chip 最前面那一格变成转圈的圆环 = 正在切分支(只剩这一个用途)。改动数还没核对完不再走这里 —— 那是一次整棵树的读,大仓库上 8–10 秒,让图标转那么久就是一颗停不下来的圈;它由数字那一格说(空心的旧数字,或者还没有数字时的 …),读屏拿到的是同一句话((正在核对改动))。测试里有一条约束守着这件事:chip、面板、分支卡片、设置页各渲染一次,整棵元素树上不允许出现 title。

*历史 页:左边分支树(

…(truncated)

以上内容来自 npm 上的 README,我们只做格式化,不改内容。

版本

npm 上共发布:11,最后更新 2026-10-13

链接

GitHub · Homepage · npm

同类插件