03 · 变更与 Diff
状态:✅ 已实现 · 范围:v1 · 工程参考:
../spec.md
Source Control 视图(活动栏)就是多仓库变更列表:每个仓库一节,全部未提交工作一目了然。
哪些仓库会出现
- 仓库默认全部勾选:在 Repos 视图取消勾选会把它从本列表隐藏。因此默认语义是"只要有变更就可见",勾选集合用于在 50+ 仓库的工作区里收缩视图。
- 工具栏操作:"仅所选"(默认开启,只显示 Repos 视图中勾选过的仓库的变更)、"全选 / 全不选"。
- 有进行中操作(merge、rebase、cherry-pick、revert、bisect)的仓库始终出现,其分节顶部显示操作横幅:操作名、未解决文件数的实时计数,以及该操作允许的按钮——merge 只有 Continue / Abort,rebase、cherry-pick、revert 是 Continue / Skip / Abort,bisect 期间只有 Abort(详见第 06 页)。
分组与开关
每个仓库分节按此顺序分组:Merge Conflicts(冲突)、Staged Changes(已暂存)、Changes(未暂存)、Untracked Files(未跟踪)。分组可见性在 Source Control 视图自己的工具栏菜单里开关——例如很少提交新文件时可以关掉 Untracked Files。默认全部可见:你不关,就不会隐藏任何内容。
每个分节底部是提交框(消息输入、✨ 生成按钮、Commit / Amend / Stage-all——详见第 04 页)。
文件行操作
状态字母:M 修改 · A 新增 · D 删除 · R 重命名 · C 复制 · T 类型变更 · U 未跟踪 · ! 未合并/冲突。
- 悬停操作:Stage / Unstage / Discard。支持多选(Shift/Ctrl+点击),操作作用于整个选中集合。
- 目录粒度:未跟踪文件夹折叠成一行,暂存该行即暂存其下全部内容。已跟踪的变更逐文件列出,因此没有对应的文件夹行。
- Hunk 级暂存——在 diff 视图中,每个 hunk 边栏有操作:暂存该 hunk(未暂存文件)或取消暂存该 hunk(已暂存文件)。每个变更行还有一个更小的标记,只对这一行做同样的操作(见下方 Diff 视图)。
- 加入 .gitignore——未跟踪行可用;模式追加到
.gitignore并立即暂存。 Space暂存/取消暂存选中行;Enter打开 diff。
Discard 的语义(重要)
| 情况 | 行为 |
|---|---|
| 已修改 / 重命名文件 | 从 index 恢复。不可逆——确认对话框会明确说明将丢失什么。 |
| 未跟踪文件 | 文件被移入系统回收站——可从回收站找回,无需恐吓式对话框。 |
| 冲突文件 | 不可 discard;先解决冲突(第 06 页)。 |
Diff 视图
点击变更文件会在编辑区打开 diff 标签。
- 布局:并排 ⇄ 内联切换。忽略空白开关。自动换行遵守编辑器设置。
- 重命名显示 旧路径 → 新路径 及内容 diff。二进制文件显示体积信息;图片以前后 2-up 预览打开,洋葱皮模式把两个版本叠放在一条可拖动的分界线后面——线左侧是旧版,右侧是新版;同一栏里的滑块也能不拖动就移动这条分界线。只有两侧都能解码为图片时才有洋葱皮模式;单侧存在的版本仍保持 2-up。
- 边栏操作:点击 hunk 旁的标记即暂存它(未暂存文件)或取消暂存它(已暂存文件);同一标记的右键菜单还提供还原此片段与复制片段为补丁。每个变更行旁的小圆点只对这一行生效——暂存、取消暂存或还原它。git 把某行记为"被改写"时,新旧两行之间没有上下文,圆点会把两者一起处理;这一对本来就是 git 能拆分的最小单位。这些标记只在有意义的地方出现——两个提交之间的 diff、重命名 diff 是只读的;被删除行的圆点位于左侧面板,行内对比模式下不显示。
- 与…对比——切换文件的对比基线:
INDEX、HEAD、任意 ref / 分支。仓库范围的对比从分支选择器进入:它把仓库的HEAD与你选择的 ref 对比(选择器最多列出 40 个 ref)。目录范围的对比在文件夹行上:文件夹与…对比提供同一份基线列表,把该路径下的改动与工作区比较——仓库自身那一行则覆盖整个 checkout。只有一条改动时直接打开它的 diff,没有改动时给一条提示,多条改动打开列表,点其中一行就按同样两侧打开该文件的 diff。
文件历史
- diff 标签工具栏有 History 开关:列出触碰过该文件的提交列表;点击某提交打开该文件在该版本的 diff。
- 列表默认跟随重命名(
--follow),因此首次重命名之前的提交也会包含在内。重命名之前的每一行会标出文件当时的名字,打开它比较的就是那个旧名字。面板里的 跟随重命名 开关可以切换为只看当前名字下的提交。
边界情况
- 未跟踪文件数量病态:Untracked 组只列带上限的一批并给"显示更多…",不会把视图卡死。
- 超大 diff:超过 2 MB 的文本 diff 不会自动渲染——标签页提供"仍要加载完整 diff",并在 20 MB 处有硬上限,超过则完全不拉取内容。编辑器中的文件遵循编辑器自身规则(第 10 页)。
- 打开期间的磁盘外部变更:标签标记为过期并提供重新加载。
- CRLF / .gitattributes:diff 按 Git 产出的原始内容展示——GitTreeDesk 永不自行归一化行尾。忽略空白开关可缓解。