Issue 192 - ShaoClean/Alune GitHub Wiki
Issue #192:可视化交互式变基
-
类型:功能
-
状态:已实现,本地验收通过,待 PR 审阅合并;跨平台现场验证未完成
-
最近更新:2026-10-05
-
代码基线:
c567e48;实现分支:codex/interactive-rebase -
最新集成提交:ad29517ff84dd7c686bb6ef02dbe74003c22b888(合入 development 的通用冲突处理)
背景与问题
整理本地提交需要在终端运行 git rebase -i 并编辑 todo 和提交信息。Alune 现在提供历史入口、计划编辑、结果预览与冲突恢复,让用户在同一仓库页面完成整个流程。
目标与范围
选择当前分支的祖先提交作为基准,整理基准之后的线性历史;基准本身不变。本地、独立 Worktree 和 SSH 仓库使用相同界面与原生 Git 语义。
支持 pick、reword、squash、fixup、drop,拖拽、按钮及 Alt+↑/↓ 排序,完整提交信息编辑、执行前预览和取消。包含远程跟踪引用可达的提交时,需要明确确认重写已推送历史的影响。冲突可编辑文本、选择当前或传入版本、删除并暂存,然后继续、跳过或中止。
本期不包括 edit、autosquash、rebase-merges、游离 HEAD、自动强制推送或自动签名。#181 的通用历史菜单仍独立跟踪。development 已通过 #194 引入 #182 的通用冲突管理,本实现与其共用文件及冲突块解决入口,并保留交互式变基的会话与提交信息管理。
方案与取舍
计划和执行
共享类型和 previewRebasePlan 统一预览与执行的合并规则。计划必须完整包含所有提交且不重复,第一个保留提交不得合并到上一个。提交信息支持完整正文,上限 32 KiB;序列化计划最多 900 KiB,提交数最多 500。
服务端读取当前分支、HEAD、基准、提交和远程引用形成快照;开始执行时再次核对,拒绝已过期的计划、脏工作区、无关基准、合并历史或游离 HEAD。已推送判断只依据已有远程跟踪引用,不隐式 fetch;用户可先获取远程更新。
执行器通过 GIT_SEQUENCE_EDITOR、GIT_EDITOR 调用生成的脚本及消息文件,使用原生 git rebase -i,不会启动外部编辑器。文件通过本地传输或 SSH/SFTP 写入对应 Worktree 的 Git 目录,命令参数进行安全引用。要求执行端 Git 2.38+。
恢复和写入隔离
独占创建会话目录并记录原始分支、HEAD 和随机归属标记。标记写入 Git 变基状态目录,重开应用或重建连接后可恢复;即使旧会话残留,也不会接管外部重新发起的变基。Git 已结束时可清理中断准备产生的残留。应用外发起的变基由通用冲突控制栏提供继续、跳过和中止;不会归入本功能的托管会话。托管变基通过通用控制接口操作时,仍委托交互式变基执行器处理,以保留改写后的提交信息并清理会话。
托管变基期间拦截无关 Git 写操作,保留暂存、取消暂存、冲突解决及变基控制。专用持续状态面板承载冲突、继续、跳过和中止反馈,变更列表保留通用文件及冲突块解决入口,并隐藏重复的通用操作栏。中止恢复原始分支、HEAD 与工作区文件;Worktree 操作不会改变主工作区的 HEAD 或未提交文件。
普通 SSH Git 操作先通过命令检查变基标记;无标记时不打开 SFTP。本地仓库使用原生文件检查,保持不执行任意 shell 命令的约束。存在恢复标记时仍执行完整会话检查,读取失败不会绕过写入保护。
冲突和 HTTP 边界
读取冲突索引与工作区内容形成 token,写入前重查,避免覆盖外部已修改的解决结果。只允许解决当前冲突集合中的路径,并防护越界与符号链接。64 KiB 内 UTF-8 普通文件可编辑最终文本;其他文件可选择一侧、删除或外部处理后暂存。
变基路由 JSON 上限单独提升至 1 MiB,其他 JSON 路由保持默认 100 KiB。显式保留全局 JSON 解析器,防止 Nest 将局部解析器误识别为已安装全局解析器,影响登录及普通接口。
验收标准
- 重排、改写、连续 squash / fixup、删除与全部 drop 的结果正确;独立原生 CLI 对照的文件树、作者、提交信息一致。
- 执行前可预览和取消,取消不修改历史;已推送提交需要确认且提示可能需要强制推送。
- 应用内解决冲突后可继续,支持跳过;中止恢复原始 HEAD、分支及文件。
- 不弹出外部编辑器;测试将用户编辑器配置为失败命令,仍能完成变基。
- macOS 上本地、链接 Worktree、真实 loopback SSH/SFTP 的临时仓库验证通过。
- 计划过期、冲突内容变化、脏工作区、不合法计划、外部变基和中断准备均有回归覆盖。
- 浅色、深色和 390px 窄屏完成浏览器检查,窄屏无横向溢出。
- Windows / Linux 原生环境、真实远程主机和 Electron 安装包现场验收;本次未运行。
验证记录
日期均为 2026-10-05。环境:macOS arm64、Node.js 25.5.0、Git 2.43.1。自动化使用临时仓库;浏览器使用隔离数据与合成提交,没有改写用户仓库历史。下表区分全量测试时点与最终补充测试,不累加重复用例。
| 代码 / 环境 | 命令或场景 | 结果与证据 |
|---|---|---|
| 实现工作树,macOS | npm run build -w @alune/shared、npm run build -w @alune/ssh-client、npm run build -w @alune/ui、npm run build -w server、npm run build -w web |
全部通过;Vite 仍有既有大 chunk 提示 |
| 最终实现 | npm test -w web |
240 通过 |
| 最终启动请求体回归加入前 | npm test -w server -- --runInBand |
27 suites / 285 通过 |
| 最终实现 | npm test -w server -- --runInBand src/git/interactive-rebase.spec.ts |
4 通过;真实启动验证普通 JSON / 登录、120+ KiB 计划、其他路由 100 KiB 限制、变基 1 MiB 限制 |
| 实现工作树,本地 / Worktree / SSH | npm test -w @alune/ssh-client |
171 项中 169 通过,2 项 Windows 原生测试按平台跳过 |
| 最终实现,本地 / Worktree / SSH | node --test packages/ssh-client/tests/interactive-rebase.test.cjs |
20 通过;涵盖原生 CLI 等价性、会话恢复、中止、全部 drop、skip、过期状态和外部变基归属 |
| 真实浏览器 | 预览后取消;勾选已推送确认;执行成功并检查历史与磁盘 | 通过,见预览截图 |
| 真实浏览器 | 键盘重排引发冲突,先编辑文本解决,继续后选传入版本解决第二次冲突,再继续完成 | 通过,最终 Git log 与文件内容一致,见冲突截图 |
| 真实浏览器 | 深浅主题及 390px 宽度 | 通过,见主题和窄屏截图 |
提交 d1fd4ce |
git diff --check、commit-msg 与 pre-push hook |
通过 |
PR 创建后的代理回归修复
首版提交 d1fd4ce 的 GitHub CI 在 macOS 与 Linux 网络代理场景失败,错误为 Unable to start subsystem: sftp。原因是新增状态检查使普通 fetch / pull / push 也尝试连接 SFTP。此失败确实由本 PR 引入,已在 076f2f2 修复。
2026-10-05 补充记录:无变基标记时跳过 SFTP,存在恢复标记时仍严格校验;本地路径检查使用原生文件 API。中间试跑曾因 LocalConnection 不支持任意 shell 命令及适配层未透传原生探测能力失败,修正后验证如下。原有首次验证记录保留,不以新结果覆盖历史失败。
| 命令 / 范围 | 环境 | 实际结果 |
|---|---|---|
npm run build -w @alune/ssh-client、npm run build -w server |
macOS arm64 | 通过 |
node --test packages/ssh-client/tests/proxy-transport.test.cjs apps/server/test/proxy.integration.cjs packages/ssh-client/tests/interactive-rebase.test.cjs |
最终修复、本地 / Worktree / 真实 SSH | 28 通过:含 21 项变基测试,以及无 SFTP 服务上通过代理执行 HTTPS/SSH fetch / pull / push 的集成场景 |
npm test -w server -- --ci --runInBand |
最终修复 | 27 suites / 286 全部通过 |
npm test -w @alune/ssh-client |
状态探测修复版本 | 172 项中 170 通过、2 项 Windows 原生用例跳过;随后补充取消信号透传及服务端适配后,上述 28 项与服务端全量重新通过 |
格式检查及 git diff --check |
最终修复 | 通过 |
修复已推送至同一 PR,GitHub CI 重新运行;未把未完成的 CI 或跨平台现场验证记为通过。
合入通用冲突处理后的集成验证
2026-10-05,提交 ad29517ff84dd7c686bb6ef02dbe74003c22b888 合入 development 的 6bbb7e7(PR #194),解决 Git 冲突及两套变基控制的行为重叠。以下为合入后的独立验证记录,不与历史测试数量累加。
| 检查 / 场景 | 实际结果 |
|---|---|
| shared、ssh-client、server、web 构建 | 全部通过 |
npm test -w web |
248 通过;覆盖托管变基隐藏重复操作栏且保留冲突文件操作 |
npm test -w server -- --ci --runInBand |
27 suites / 289 通过;新增真实 Git HTTP 场景覆盖通用接口继续、跳过及中止托管变基,校验提交信息和会话清理 |
npm test -w @alune/ssh-client |
共 185 项,183 通过,2 项 Windows 原生用例按平台跳过 |
| 代理传输及服务端代理集成回归 | 7 通过 |
| 真实浏览器:托管交互式变基 | 仅显示专用变基控制栏;通过通用文件解决器连续解决两次冲突并继续,状态栏消失,工作区干净,两条改写后的提交信息均保留 |
| 真实浏览器:应用外发起的变基 | 仅显示通用变基控制栏;选择传入文件版本并继续成功,状态栏消失,工作区干净,最终提交信息正确 |
git diff --check、提交信息与推送 hook |
通过 |
浏览器使用隔离服务和临时合成仓库,截图已检查,无真实用户凭据。未重复跨平台实机或 Electron 安装包验收;CI 状态以 PR 检查页为准。
托管变基保留专用控制栏,同时使用通用文件解决器:

应用外变基使用通用控制栏与文件解决器:

界面证据
采集日期:2026-10-05;版本:本 PR 实现工作树。旧版本没有可视化变基流程,本次未保存改动前截图;以下均为新流程的实际截图,不构造前后对照。
预览最终提交及已推送确认(未勾选时禁用执行):

应用内选择版本、编辑冲突结果并暂存:

深色主题计划编辑:

390px 浅色主题窄屏:

风险、未决事项与回退
重写历史会改变提交 ID;是否需要强制推送依赖实际远端状态,应用不自动推送。新提交不会自动签名。其他分支、标签和远程引用可能仍保留旧提交,所有分支提交图可能同时显示两组历史。
SSH/SFTP 已使用真实 loopback 服务验证,但未验证真实网络中断及其他操作系统;持久恢复通过重建执行器测试,不将此等同于所有断线场景通过。Windows 的 2 项原生测试按平台跳过,Windows / Linux 实机及 Electron 安装包仍未验证。
没有数据库迁移。回退代码前应先完成或中止托管变基;不要在 Git 操作进行中直接删除会话文件。Wiki 独立于代码仓库,代码回退后需单独核对页面和验收记录。