Skip to content

Issue 183

clean edited this page Oct 6, 2026 · 2 revisions

Issue #183:Diff 按块与按行暂存、取消暂存和放弃

背景与范围

原先暂存、取消暂存和放弃以整个文件为单位,无法在应用内拆分同一文件中的不同改动。现在未暂存 Diff 的每个块提供暂存/放弃,已暂存 Diff 提供取消暂存;可勾选若干新增或删除行执行同样操作。本地、关联 Worktree 和 SSH 共用实现,历史 Diff 保持只读。

普通 UTF-8 文本限 2 MiB,Diff 限 10,000 行。二进制/图片、未跟踪文件、符号链接、子模块、自定义内容过滤器、ident 或工作区编码转换不支持部分操作,继续使用原预览与整文件操作。重命名文件按当前路径处理文本;路径和权限变更仍通过整文件操作完成。

交互

  • 统一、分栏、全屏共用控件。Shift 点击连选,空格切换,↑ / ↓ 移动焦点,Shift+空格 连选。切换视图保留选择,快照变化时清空。
  • 替换由删除行与新增行组成,只选一侧仅处理该侧;两侧都选择才会处理完整替换。
  • 放弃前展示文件与范围,默认聚焦取消;Esc 取消确认并保留全屏。操作过程中禁用重复操作。
  • 完成后刷新 Diff 与状态,同一路径允许同时出现在未暂存与已暂存列表;同一比较保留滚动位置。
  • 失败沿用统一通知,通知与 Diff 都提供刷新入口。旧快照、无效范围、未确认的放弃均不能写入。
  • 本次视觉验证同时修复三位数行号折行、窄屏块按钮移出可视区,以及全屏切换到窄窗口后被父面板隐藏的问题。

接口与实现

GET /api/repositories/:id/diff?file=...&staged=...&editable=true 返回 { diff, revision?, unavailableReason? };无 editable 参数的原文本 Diff 接口保持兼容。POST /api/repositories/:id/partial-diff 接收文件、操作、快照版本与 { hunks: [...] } 或 { lines: [...] },放弃还需 confirmed: true。

服务端解析自己生成的规范 Diff,并重新读取 HEAD、文件索引项、工作区内容和属性。客户端只提供范围编号,不提供任意补丁。快照 SHA-256 绑定仓库、路径、比较方向及内容;预览前后重复读取确保一致,应用前核验版本,Git 可应用性检查后再次核验状态。

选择后的目标文本由基准文件与原始 Diff 重建。为正确保留上下文、混合行尾、BOM 和无末尾换行,服务端将结果编成包含完整基准文本的单文件补丁;暂存和取消暂存用 git apply --cached,放弃用工作区 git apply。补丁通过标准输入传递,本地与 SSH 不把内容拼入 shell 命令。取消暂存重建反向目标文本,不依赖客户端翻转补丁。

同仓库写操作沿用现有互斥与取消机制;部分暂存/取消暂存与原整文件操作一样允许用于管理中的变基。应用失败会显示 Git 原因。快照校验是乐观并发检查,未对编辑器或其他外部 Git 程序建立跨进程事务;断线或外部程序持续写入时需刷新核对状态。

验收标准

  • 单块暂存、取消暂存和放弃,工作区与两侧 Git Diff 结果正确。
  • 逐行选择覆盖新增、删除、替换、无末尾换行和 CRLF。
  • 外部修改、索引更新和应用检查期间的修改会使旧快照失效,不写入错误内容。
  • 统一、分栏、全屏中的操作与键盘选择一致;390px 窄屏控件可用。
  • 放弃需确认,默认取消,失败显示原因并可刷新。
  • 本地、关联 Worktree 和实际 SSH 协议验证通过,含中文路径及 15,000 行文本的小范围改动。

验证记录

日期:2026-10-06;macOS arm64,Node.js 25.5.0。全部文件、SQLite 和 SSH 服务使用本机临时 fixture;没有访问用户仓库或真实远端凭据。

检查 命令或场景 结果
前端全量 npm test -w web 259 项通过;最终相关 4 项再次通过
Git 执行层全量 npm test -w @alune/ssh-client 213 项通过、2 项既有跳过;最终另补过滤器/ident 1 项通过
API 与本地集成 npm run test -w server -- --runInBand partial-diff.spec.ts git.controller.spec.ts git.service.spec.ts 和 local-git.spec.ts 合计 34 项通过;最终相关 6 项再次通过
部分操作回归 node --test packages/ssh-client/tests/partial-changes.test.cjs 本地/Worktree/SSH 等 10 项通过;之后新增过滤器测试单独通过
构建 npm run desktop:build 6 个任务通过,包括 shared、ssh-client、server、web、UI 和 desktop;保留原 Vite 大包提示
规范 git diff --check、相关文件 Prettier、commitlint 通过
真实界面 + Git 生产 HTTP 和浏览器操作后读取 git diff、git diff --cached 和实际文件 逐行暂存、块取消暂存、全屏分栏放弃符合预期,同文件两侧列表同步
安全反馈 编辑文件后使用旧选择 拒绝操作,工作区和索引逐字未变;通知中可直接刷新
键盘及确认 空格、Shift+空格、Esc 行范围正确;默认取消;取消确认不退出全屏
滚动与响应式 同比较操作前后、390px 全屏 scrollTop 100 → 100;页面无横向溢出,块按钮位于可视区

未执行 Windows/Linux 原生现场验收、远端真实主机现场测试、安装包发布。SSH 验证使用真实本机 SSH/SFTP 服务及生产客户端,不代表不同远端系统配置的完整覆盖。

截图

生产前端与后端、隔离真实 Git 仓库。截图对应上述实现提交,仅包含测试数据。

统一视图与部分暂存后的两侧列表

统一视图

分栏与全屏

全屏分栏

外部修改后的拒绝与刷新

旧快照拒绝

窄屏

390px 全屏

复验与回退

构建后运行 node apps/web/tests/partial-diff-fixture.cjs,打开输出的 URL。独立本机控制接口可 POST { "reset": true } 恢复测试状态、{ "edit": true } 模拟外部修改,并返回工作区/索引内容和两侧 Diff。退出进程清理临时数据。

无数据库迁移,回退实现提交恢复整文件操作;回退代码不会撤回已经执行的 Git 改动,Wiki 需单独回退。使用说明见主仓库 docs/workspace.md,源码与自动测试随上述提交维护。

CI 补充记录(2026-10-06)

实现提交 df9f1317a055e84e8fddc82eb077eb91ad8c7a0f 的 PR/分支检查共 27 项全部成功,包括 server、web、UI、desktop、ssh-client 单元测试,macOS/Ubuntu/Windows 本地 Git 与网络代理,以及三平台 PTY 和原生包检查。结果见 CI 与 PTY/原生包。CI 通过不替代前文尚未执行的跨平台人工现场及真实远端主机验收。

Clone this wiki locally