# dsh-git-chain 后续路线 > 这份文档是对当前仓库实现、`dsh-better-sidebar` 本地契约以及 GitHub 同类项目的对照结果。 > 项目对比以 2026-08-26 可读取到的仓库文档和包声明为准;除本仓库与本地 DSH 依赖外,其他项目没有在本机逐一运行。 ## 结论先行 当前项目的方向是成立的:保留 Host 侧受门禁的原生 Git 服务、浏览器侧 React/SVG 链路图,以及 better-sidebar 常驻入口,不需要为了“看起来更完整”改成新的 Git 引擎或复制完整 Git 客户端。 建议按下面顺序落地: 1. **先修视觉契约和交互层级**:使用 better-sidebar 实际的 alias token、图标和控件语义;把 Git 链路图放到内置 Git tab 后面;消除 Unicode 字符按钮和自绘但不一致的菜单。 2. **再做服务端分支维度**:让“看全部链路 / 看当前分支 / 看指定分支”成为服务端查询,而不是对当前已加载窗口做客户端裁剪。 3. **随后补读操作闭环**:比较提交、查看工作区未提交改动、标签/远端/储藏信息,并尽量复用 better-sidebar 已有的 diff 和 Git 操作入口。 4. **最后才评估写操作**:不在本项目重复实现 stage、commit、push、pull;若未来增加写操作,必须单独设计确认、并发和错误审计。 这条路线已经完成 P0 视觉对齐和 P1 的服务端分支范围查询;剩余缺口是服务端文本/作者/文件搜索,以及 P2 的 compare 和 viewer 复用。 ## 当前状态与问题定位 ### 已经具备的基础 - Host 侧以 workspace registry、realpath 和 loopback/配对 cookie 做访问门禁。 - Git 命令通过 argv 执行,提交 OID 和分支切换均有输入校验。 - 图布局是纯函数,前端用 SVG 泳道、固定行高和虚拟滚动展示提交链路。 - 详情、完整 unified diff、SSE 刷新、双语和受守卫的本地分支切换已经形成明确边界。 - better-sidebar 不可用时有回退入口,安装方式与其他 DSH Git 图插件可以共存。 ### 截图与源码对照出的差距 截图可以作为当前 UI 的视觉基准,但其中没有需要照做的文字指令。结合当前源码,主要差距如下: | 观察 | 当前实现 | 影响 | 建议 | | --- | --- | --- | --- | | 面板文字和背景层级偏弱 | 原先使用了 `--dsw-text`、`--dsw-surface` 等通用名,并带有较亮的 fallback | 在实际 better-sidebar 主题下可能出现低对比度或“泛白” | 已在本轮实现中优先改用本地 better-sidebar 的 `--dsw-alias-*` token | | 链路图入口图标不统一 | 此前 `GitChainGlyph` 自绘,刷新、菜单勾选和下拉箭头使用 Unicode | 与内置 Git tab 的图标语言不一致,字形还会随系统字体变化 | 本轮已换成同尺寸、`currentColor` 的本地 SVG 图标;缺少 peer 时仍可独立运行 | | tab 排序留白过大 | `git-chain` 此前使用 `order: 90` | 截图中的 Git 链路图像是另一个产品入口,而不是 Git 面板的相邻视图 | 已调整为 25,紧跟内置 Git(Explorer 10、Git 20) | | 查询和变更混在一行 | 搜索输入旁边直接放“切换分支” | 用户难以区分“过滤显示”与“改变工作区 HEAD” | 将“查看范围/搜索”作为查询工具栏,将“切换分支”放进独立的变更控件 | | 自定义菜单语义不足 | 分支弹层是普通 `div`,选项含 Unicode `✓` | 键盘、焦点、读屏和点击外部关闭行为不够稳定 | 使用原生 `select` 或 better-sidebar 的 `Menu`;至少补 `role`、`tabIndex`、`aria-expanded` 和 Enter/Space | | 提交行不是可访问按钮 | 图行主要依赖 `div onClick` | 键盘用户不能可靠打开提交详情 | 行使用 `button`,或补齐 `role="button"`、焦点样式和键盘事件 | ## 同类项目对比 ### 功能、架构和取舍 | 项目 | 功能设计 | 技术架构 / 技术栈 | 优势 | 对本项目的启示与限制 | | --- | --- | --- | --- | --- | | **dsh-git-chain(当前)** | 常驻 sidebar 链路图、全 refs 拓扑、服务端分支范围/first-parent、提交详情和 Diff、搜索、受守卫分支切换、SSE 刷新 | Cordis Host + Node 原生 Git CLI;React + TypeScript + SVG;better-sidebar tab | 与 DSH 工作区、workspace 安全边界和现有 Git 面板天然融合;实现边界小 | 文本过滤仍是加载窗口内客户端过滤;服务端全文搜索和 compare 尚未实现 | | [VS Code Git Graph](https://github.com/mhutchie/vscode-git-graph) | 本地/远端分支、标签、未提交改动;分支和提交操作;比较、代码审查、快捷键、图表和列配置 | VS Code 扩展;扩展 Host 与 Webview 组合;通过 Git CLI/扩展 API 工作 | Git 图工作流最完整,分支、提交、标签操作成熟 | 功能面明显更大;不应直接照搬全部写操作,先借鉴过滤、比较和快捷键 | | [GitLens](https://github.com/gitkraken/vscode-gitlens) | Commit Graph、分支/文件/提交搜索、ahead/behind 状态、PR/forge、worktree、stash/tag、行级操作 | VS Code 扩展;Git 服务与编辑器/Forge 集成;TypeScript/JavaScript 生态 | “每行都有 live state”,信息密度和 Git 上下文很强 | Community/Pro 功能边界和产品复杂度较高;本项目应优先选择 read-only 信息密度,不复制商业化功能层 | | [WhitePlusMS/dsh-git-graph](https://github.com/WhitePlusMS/dsh-git-graph) | DSH 内只读 Git Graph;分支/refs/first-parent/排序/正则搜索;提交详情、文件树、逐文件 Diff、未提交改动、比较 | DSH Typert remote + React/TypeScript + Vitest;独立 conversation view | 是最直接的 DSH 对照,查询契约和 read-only 信息面比当前更完整 | 顶层 conversation view 不等于常驻 sidebar;与本项目的入口和受守卫 checkout 形成互补,不建议重复合并成两套 Git 面板 | | [dsh-better-sidebar](https://github.com/omdsh-dev/DSH-better-sidebar) | 服务优先的 tab/文件查看器;内置 Git 的 stage、commit、history、diff;i18n、懒加载、移动端抽屉、设置 | DSH service API + 前端 React 组件和统一设计 token | 已经定义了入口、顺序、图标、Menu、Input、diff 和移动端交互的产品契约 | 本项目应作为 Git 链路图的宿主和视觉基线;不能再自创一套控件语言 | | [dsh-web-ui](https://github.com/zhu1090093659/dsh-web-ui) | 将 DSH UI/皮肤/功能插件拆成可独立安装的包,也提供聚合包 | 多 package 前端生态,独立插件 + aggregate 包 | 说明 DSH 插件适合小而清晰、可组合的能力边界 | 不应同时安装聚合包和独立同名插件;本项目保持单一职责,不复制其打包体系 | | [ungit](https://github.com/FredrikNoren/ungit) | Web/自托管 Git UI;图、提交、分支和常用 Git 操作 | Node 服务端 + 浏览器 UI;Express、Socket.IO、Knockout、Snap.svg、diff2html 等 | 证明 Git 图可以以 Web 服务形态落地,交互直观 | 历史栈较宽,且部署边界与 DSH workspace 安全模型不同;只借鉴 Web 图和 Diff 呈现 | | [lazygit](https://github.com/jesseduffield/lazygit) | 终端内覆盖 staging、commit、分支、worktree、rebase、比较和图 | Go TUI;命令、GUI context/controller、视图顺序分层 | 工作流完整,快捷键和状态反馈成熟 | 终端布局不适合直接移植;可借鉴“上下文控制器 + 明确视图顺序 + 快捷键”的信息组织 | | [gitui](https://github.com/gitui-org/gitui) | 异步 Git API、stage/hunk/line、stash、push/fetch、分支、搜索、Diff 和响应式布局 | Rust TUI + 异步 Git 操作 | 对大仓库和异步交互的性能意识强 | Rust/TUI 是另一套产品边界;可借鉴分页、异步和大仓库基准,不建议为当前插件换后端语言 | | [gitgraph.js](https://github.com/nicoespeon/gitgraph.js) | 可嵌入的 Git graph 渲染 API,支持 JS/TS 包 | 前端渲染库 / monorepo,不负责仓库读取与权限 | 可作为布局算法和渲染抽象的参考 | 当前项目已经有纯函数布局和 SVG 渲染;引入它不能解决 Git 查询、安全或 DSH 集成问题 | | [isomorphic-git](https://github.com/isomorphic-git/isomorphic-git) | 在 Node/浏览器内用纯 JS 读写、fetch、push Git | 纯 JS Git 实现,需要浏览器 FS 模拟 | 去除本机 Git 依赖,适合特定浏览器/边缘环境 | 对本项目是高风险换血:要重新处理 FS、一致性、凭据、性能和安全;当前没有必要替换原生 Git CLI | ### 取舍结论 - **最值得吸收的功能模型**:WhitePlusMS 的查询维度(branch/ref、first-parent、排序、全范围搜索)、GitLens 的状态信息密度、VS Code Git Graph 的比较和快捷键。 - **最值得吸收的架构模型**:better-sidebar 的 service-first 入口契约,以及 lazygit/gitui 将 Git 查询、视图状态和异步更新分开的方式。 - **不值得现在吸收的内容**:全量写操作、完整 Forge/PR 系统、切换 Rust 或 isomorphic-git、引入一个只负责画图的第三方库。 ## 优先级路线 ### P0:better-sidebar 原生化(已实施) #### 1. 统一 token 将 `src/client/theme.ts` 的视觉变量映射到当前 better-sidebar 实际使用的 alias token,至少覆盖: - 文本:`--dsw-alias-label-primary/secondary/tertiary/dimmed`; - 背景:`--dsw-alias-bg-layer-1/2/3`、`--dsw-alias-bg-module-platform`; - 边框和交互:`--dsw-alias-border-l1/l2`、`--dsw-alias-interactive-bg-hover/active/hover-accent`; - 品牌和状态:`--dsw-alias-brand-primary`、`--dsw-alias-label-error`、`--dsw-alias-state-error-primary`、`--dsw-alias-state-success-primary`; - 阴影和代码字体:`--dsw-shadow-lv2/lv3`、`--ds-font-family-code`。 Fallback 只用于独立回退面板,且应保持暗色/亮色都可读;不要让 fallback 反过来覆盖 better-sidebar 的主题。当前实现已按此方式更新。 #### 2. 统一图标和控件 - 链路图 tab 使用与内置 Git 同源的分支图标风格,尺寸优先 16px。 - 刷新使用 `IconRefreshOutline16` 语义,不再使用 `⟳`。 - 下拉使用 chevron 图标,选中状态使用图标组件,不使用 `✓` 字符。 - 搜索、过滤、合并、标签、比较等图标统一 `currentColor`、约 1.75px stroke,并设置 tooltip/`aria-label`。 - 如果 peer UI icon 包在独立安装中不可用,保留本地 SVG fallback,但接口和尺寸必须与 peer 版本一致。 #### 3. 调整菜单顺序和信息层级 better-sidebar 当前内置 tab 顺序是 Explorer 10、Git 20、Subagent 30、Sidechat 35;建议 `git-chain` 使用 25,紧跟 Git 而不是使用 90。 推荐工具栏层级: ```text Git 链路图 repo-name [当前 HEAD / 状态] [刷新] [查看范围:全部 / 当前分支 / 指定分支] [搜索提交] [过滤条件] ``` “切换工作区分支”是可能改变 HEAD 的操作,应放在明显的 secondary control 或菜单中,与“查看指定分支链路”使用不同文案和不同图标。这样用户不会把查询分支误认为 checkout。 #### 4. 补可访问性 - 提交行改为可聚焦、可按 Enter/Space 打开的按钮语义。 - 分支菜单补 `aria-expanded`、当前值、焦点回收、Esc 关闭和键盘上下选择。 - 刷新、清除过滤、加载更多、关闭详情均提供可读标签。 - 保持 32–34px 控件高度、8px 圆角和 4/8/12px 间距;行高可继续使用 30px,但焦点态必须清晰。 **代码级验收已完成**:tab 顺序改为 25;图标、token、菜单按钮语义和提交行键盘事件已落地;现有 jsdom 测试通过。仍需在真实 better-sidebar profile 下补亮色/暗色截图验收。 ### P1:服务端分支维度查询(已实施) 该功能已完成。客户端文本过滤仍只在已加载数据上筛选,但“这个分支完整的链路是什么”已经由服务端 scope 查询回答。 #### 1. 先采用最小查询协议 建议新增共享类型,避免把查询字段散落在 route、service 和 client: ```ts type GraphScope = 'all' | 'current' | 'branch' interface GraphQuery { limit?: number scope?: GraphScope branch?: string // scope=branch 时为精确的本地分支名 firstParent?: boolean } ``` 规则: - `scope=all`:保持当前全 refs 行为,默认值兼容已有调用。 - `scope=current`:服务端解析当前 HEAD 对应的本地分支;detached HEAD 时明确回退到 HEAD 或显示 detached 状态。 - `scope=branch`:只接受已存在的本地分支精确名称,不接受模糊匹配,不接受任意 ref 表达式。 - `firstParent=true`:服务端追加 `--first-parent`,用于只看主线发布链路;默认保留完整父关系。 - 所有字段先做运行时窄化;分支名沿用现有分支校验,并通过 argv 传递,绝不拼 shell 字符串。 #### 2. Host 侧命令形态 当前全量图使用 `git log --branches --tags --remotes --topo-order --parents ...`。建议只在服务端生成查询形态: ```text all: git log --branches --tags --remotes --topo-order --parents ... current: git log --topo-order --parents ... HEAD branch: git log --topo-order --parents ... refs/heads/ ``` `firstParent` 只影响对应命令的排序/父关系选项;不要让前端拿到全部提交后再模拟分支范围。返回的 `GraphView` 可增加归一化后的 query/scope,使界面在刷新、SSE 和错误恢复后仍知道当前查看范围。 #### 3. 路由、客户端和状态更新 - `/git-chain/graph` 接收 `{ path, limit, scope, branch, firstParent }`,保持 JSON 信封和现有错误码。 - `api.graph()` 传递完整查询对象;默认调用行为与现在一致。 - 切换查看范围时取消或忽略旧请求,清空选中提交,重置滚动窗口和详情,重新计算泳道。 - SSE 触发刷新时保留当前 `path + query`,不能刷新后偷偷回到全量图。 - 缓存键使用 `path + scope + branch + firstParent + limit`;第一版可以不做持久缓存,先保证状态正确。 - UI 以“查看范围”显示当前值,例如 `全部链路`、`当前分支`、`feature/foo`;与 checkout 控件分开。 #### 4. 测试与验收 至少覆盖: 1. 分支名包含 `/`、空格或边界字符时,argv 仍是独立参数,不能注入额外命令。 2. 不存在的分支、非法 scope、`scope=branch` 缺少 branch 均返回稳定错误码。 3. 含 merge 的仓库中,全量、指定分支和 first-parent 三种结果的父关系正确。 4. 前端切换范围后不会展示上一查询的提交详情,也不会被旧响应覆盖。 5. SSE/窗口聚焦刷新会保留当前范围。 6. 真实 profile 冒烟:全部、当前分支、指定分支、空仓库、detached HEAD、超长分支名均可展示。 ### P1:图信息密度和大仓库体验 在分支查询完成后再增加这些低耦合能力: - 分支范围下的 `first-parent` 开关,默认关闭; - refs 分组显示 local / remote / tag / HEAD,当前分支使用 brand token,其余使用 secondary/tertiary token; - 稳定的分支颜色分配,避免刷新或分页后同一分支换色; - 提交行显示更清晰的 subject、作者、时间、refs 和 ahead/behind 等状态,窄屏隐藏次要列而不是压扁主标题; - 搜索从客户端窗口过滤升级为服务端 `git log --grep` 等安全查询,后续再评估作者、文件路径和正则; - 分页保持 100–200 条一页,避免一次性把整个仓库历史送到浏览器; - 加载、无结果、仓库不存在、权限拒绝、超时都使用统一的空状态和错误状态。 不要把“日期排序”“正则”“文件路径查询”与第一版 branch scope 绑在同一个大协议里。先让范围语义稳定,再扩展过滤字段。 ### P2:读操作闭环和 better-sidebar 复用 - 支持两个提交的 compare:单击选中,Shift/Cmd 点击第二个提交,调用现有或新增的 compare endpoint。 - 将文件 Diff 尽量打开到 better-sidebar 已有的 diff/file viewer;链路图只保留上下文和入口,减少重复实现。 - 增加 tags、remotes、stashes 元数据和未提交工作区行,但保持 read-only。 - 提交行上下文菜单优先提供 Copy OID、Compare、打开文件、复制引用;菜单使用 better-sidebar `Menu` 语义。 - 可参考 VS Code Git Graph / GitLens 的快捷键和 row action,但只引入能直接服务“查看链路”的动作。 ### P3:性能基准与发布质量 建立固定 fixture 和验收矩阵: | 场景 | 指标 | | --- | --- | | 200、2k、10k、50k 提交 | 首屏时间、服务端耗时、返回字节数 | | 大量分支/标签/远端 refs | lane 数、布局耗时、滚动是否掉帧 | | 快速切换分支/刷新 | 旧请求是否覆盖新状态、重复请求数量 | | 360 / 480 / 720px 面板宽度 | 截断、横向溢出、详情面板可用性 | | 亮色/暗色、无 better-sidebar 回退 | 对比度、控件可辨识度、错误/空状态 | gitui README 中的大仓库 benchmark 可以作为“需要测量”的提醒,但不是当前项目的直接性能结论。这里应以自己的真实 Git fixture 和 DSH profile 截图/浏览器指标为准。 ## 可行性与优先级矩阵 | 事项 | 价值 | 工作量 | 风险 | 建议 | | --- | --- | --- | --- | --- | | better-sidebar token / icon / order | 高 | 低 | 低 | 已实施 | | 服务端 `scope=branch` | 高 | 中 | 中 | 已实施 | | `current`、`firstParent` | 高 | 低-中 | 低 | 已实施 | | 服务端全文搜索 | 中-高 | 中 | 中 | branch scope 稳定后做 | | compare / tags / stash / 工作区行 | 中 | 中 | 中 | P2,优先复用现有 viewer | | stage / commit / push / pull | 中 | 高 | 高 | 暂缓,避免重复 better-sidebar | | 引入 isomorphic-git | 低 | 高 | 高 | 当前不做 | | 换用 gitgraph.js | 低 | 中 | 中 | 当前不做,已有 SVG 布局足够 | | 改成 Rust/Tauri 或完整桌面 Git 客户端 | 与当前目标不匹配 | 很高 | 高 | 不做 | ## 明确不建议的方向 1. **不要把客户端 filter 继续包装成“按分支过滤”**:这会让结果看似正确,实际只覆盖当前窗口。 2. **不要把 checkout 和查看 branch scope 共用一个按钮**:前者改变工作区,后者只是查询维度,必须在文案、图标和确认行为上区分。 3. **不要直接复制其他 DSH Git 图的全部功能**:不同项目的 conversation/sidebar 入口、权限边界和维护状态不同,先吸收协议和交互启发。 4. **不要重复实现 better-sidebar 已有的 stage/commit/push/diff 能力**:链路图的价值是拓扑、查询和上下文导航。 5. **不要用 Unicode 字符作为核心控件图标**:不同平台字形、基线和主题表现不稳定。 6. **不要为了大仓库先替换 Git CLI**:先测量 `git log`、服务端分页和前端虚拟滚动,证据不足时换引擎只会扩大风险。 ## 建议的实施拆分 ### PR 1:视觉和交互对齐(已实施) 已改 `src/client/theme.ts`、tab 注册、工具栏/菜单/图标和可访问性;未改 Git 查询协议。代码级测试已完成,真实 better-sidebar profile 截图验收仍待执行。 ### PR 2:GraphQuery 与 branch scope(已实施) 已改 `core/types`、`git-command`、Host service/routes 和 API 类型,并接入客户端状态。已覆盖命令 argv、真实 merge 仓库、未知分支和旧调用兼容;路由结构校验继续作为下一轮 route 专项测试入口。 ### PR 3:信息密度与大仓库体验 branch scope、first-parent 和 current scope 已完成;下一步增加 refs 分组、状态信息和空/错状态,避免与 compare 或写操作混在一个 PR。 ### PR 4:compare / viewer 复用 / 性能基准 以 better-sidebar 的已有 viewer 为出口,补真实大仓库 fixture、屏幕宽度和主题矩阵。 ## 参考资料 - [VS Code Git Graph](https://github.com/mhutchie/vscode-git-graph) - [GitLens](https://github.com/gitkraken/vscode-gitlens) - [ungit](https://github.com/FredrikNoren/ungit) - [GitButler](https://github.com/gitbutlerapp/gitbutler) - [lazygit](https://github.com/jesseduffield/lazygit) - [gitui](https://github.com/gitui-org/gitui) - [gitgraph.js](https://github.com/nicoespeon/gitgraph.js) - [isomorphic-git](https://github.com/isomorphic-git/isomorphic-git) - [WhitePlusMS/dsh-git-graph](https://github.com/WhitePlusMS/dsh-git-graph) - [dsh-better-sidebar](https://github.com/omdsh-dev/DSH-better-sidebar) - [dsh-web-ui](https://github.com/zhu1090093659/dsh-web-ui) - [DeepSeek Harness 插件说明](https://github.com/deepseek-ai/deepseek-harness)