Skip to content

Commit fd69e5c

Browse files
authored
feat(Branches): 分支视图支持按 / 前缀分组为可折叠文件夹树(平铺⇄树切换); (#86)
Local/Remote/Tags 三段支持在平铺与「按 / 前缀分组的文件夹树」间切换:共享前缀的分支 收拢到以前缀命名的可折叠文件夹下、叶子仅显示末段后缀(如 bak/2025、bak/master-2025-07 → 📁bak → 2025 / master-2025-07;远程整体收拢为 origin 文件夹并内嵌 feature)。 - 新增纯逻辑引擎 buildRefTree(engine/ref/ref-tree.ts,零 vscode 依赖):复用变更文件目录树 buildFileTree 的 trie 构建 + compact 折叠范式;叶子携完整 RawRef(命令定位不受影响); 分支感知排序(当前 HEAD → 收藏 → 同档文件夹优先、名称数字感知升序)。含 12 条单测。 - 隐藏 origin/HEAD 符号引用:对齐主流 Git UI,消除 origin 叶子与 origin 文件夹同名冲突, 远程计数归为真实分支数。 - 工具栏「平铺 ⇄ 树」切换(branchesGroupByPrefix / branchesFlatten,context key 驱动按钮 互斥),偏好按仓库持久化于 workspaceState(默认树形),文件夹默认展开、展开态跨刷新稳定。 - 文件夹节点用独立 contextValue(hyperGit.branchFolder)且不登记右键命令,多选经 selectedBranchRefs 只保留 branch 节点,checkout/delete/rename/merge/rebase/compare/ favorite 与多选批量均零改动、零破坏。 - 文档:CHANGELOG、docs/features/branch-tree-group-by-prefix、knowledge-map、README(EN/zh)。 🤖 Generated with [Claude Code](https://github.com/claude), [CodeX](https://openai.com), [Gemini](https://github.com/apps/gemini-code-assist)
1 parent 6d937ff commit fd69e5c

10 files changed

Lines changed: 590 additions & 20 deletions

File tree

‎CHANGELOG.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
77
## [Unreleased]
88

9+
### Added
10+
11+
- **Branches 视图按 `/` 前缀分组为文件夹树**:Local / Remote / Tags 三段支持在**平铺**与**按 `/` 前缀分组的可折叠文件夹树**间切换——共享前缀的分支收拢到以前缀命名的文件夹下、叶子仅显示末段后缀(如 `bak/2025`、`bak/master-2025-07` → 📁`bak` → `2025` / `master-2025-07`;远程整体收拢为 `origin` 文件夹并内嵌 `feature`)。新增纯逻辑引擎 [`buildRefTree`](./src/engine/ref/ref-tree.ts)(复用「变更文件目录树」`buildFileTree` 的 trie 构建 + compact 折叠范式;叶子携完整 `RawRef`、命令定位不受影响;分支感知排序:当前 HEAD → 收藏 → 同档文件夹优先、名称数字感知升序),并**隐藏 `origin/HEAD` 符号引用**(对齐主流 Git UI,消除 `origin` 叶子与 `origin` 文件夹同名冲突)。工具栏提供「平铺 ⇄ 树」切换(`hyperGit.branchesGroupByPrefix` / `hyperGit.branchesFlatten`,context key 驱动按钮互斥),偏好按仓库持久化于 `workspaceState`(默认树形),文件夹默认展开、展开态跨刷新稳定。文件夹节点用独立 `contextValue` 且不登记任何右键命令,checkout / delete / rename / merge / rebase / compare / favorite 与多选批量均零改动、零破坏。完整叙述见 [分支前缀分组树](./docs/features/branch-tree-group-by-prefix.md)。
12+
913
## [0.0.14] - 2026-07-06 — 修复 GRAPH 视图提交记录时间倒序
1014

1115
修复 GRAPH 视图「All」范围下提交记录未按时间倒序排列的问题——取数参数由 `--topo-order` 改为 `--author-date-order`,令跨分支提交按作者日期正确交错、消除「日期回跳」。纯取数排序修复,不改数据协议、布局算法与任何视图交互。完整用户视角叙述见 [Release Note v0.0.14](./docs/releases/v0.0.14.md)。

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
- **Multi-Changelist Changes view**: group edits into named lists, mark one as the active commit target, create / rename / delete / move lists, persisted in `workspaceState` (restored across restarts); status colors reuse the `gitDecoration.*` theme tokens.
2828
- **Commit panel**: a hand-built commit view with real-time Conventional Commits validation, Amend / Sign-off / skip hooks, and Commit / Commit & Push; the checkbox selection is the authoritative commit scope, and recent messages are reusable.
2929
- **Log commit graph (hand-rendered DAG)**: colored swimlanes, branch/merge edges, HEAD/branch/tag badges, virtualized incremental loading; 7 composable filters (author / path / grep / regex / merge-mode / date / clear); per-commit actions (Reset, new branch·tag, Cherry-Pick, Revert, list containing branches).
30-
- **Branches management**: favorites / local / remote / tags grouped into four sections with ahead·behind·upstream tracking; create / checkout / delete / rename / merge / rebase / compare / favorite; **multi-select batch** delete, copy ref, and favorite (with an honest merged/unmerged split confirmation).
30+
- **Branches management**: favorites / local / remote / tags grouped into four sections with ahead·behind·upstream tracking; **prefix folder grouping** (flat ⇄ tree toggle) that collapses `/`-shared branches under their common prefix, showing only the suffix; create / checkout / delete / rename / merge / rebase / compare / favorite; **multi-select batch** delete, copy ref, and favorite (with an honest merged/unmerged split confirmation).
3131
- **Stash & Shelf**: full stash operations (including keep-index / clear / create branch from stash); a standalone **Shelf** (patch-based, independent of stash, with 3-way merge Unshelve).
3232
- **Worktrees**: full-lifecycle management — create (new branch / checkout / detached), open in a new window, lock / unlock, move, remove, and prune stale entries.
3333
- **Line-level & hunk commits**: in-editor "Commit this Hunk" CodeLens, partial stage / unstage, stage at cursor, and hunk-to-changelist attribution.

‎docs/.agents/knowledge-map.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
- [Log 视图 CI 状态](../docs/features/log-ci-status.md) — 按提交显示 GitHub CI 最终状态(绿勾/红叉 + Tooltip 明细):认证、限流、懒加载、边界与配置。
2121
- [Commit 视图整合](../docs/features/commit-view-consolidation.md) — 移除 CHANGES 视图,其文件操作/changelist 管理/Git 工具栏/未提交角标零回归平移入 Commit 视图。
2222
- [变更文件目录树](../docs/features/file-list-group-by-directory.md) — Commit / Log 文件列表「平铺 ⇄ 按目录分组」切换:host 侧 `buildFileTree` 构树下发、compact 折叠、目录三态。
23+
- [分支前缀分组树](../docs/features/branch-tree-group-by-prefix.md) — Branches 视图 Local/Remote/Tags「平铺 ⇄ 按 `/` 前缀分组」切换:`buildRefTree` 构树、分支感知排序、compact 折叠、隐藏 `origin/HEAD`、按仓库持久化。
2324
- [Log 提交悬浮详情](../docs/features/log-commit-tooltip.md) — 悬停提交行浮层展示 分支/标签/HEAD/完整消息/作者·提交者/时间/SHA;复用 CI 浮层范式、与其互斥。
2425
- [实施状态总览](../docs/milestones/implementation-status.md) — M0-M5 交付记录 + API 限制 + M5 AI 设计 + 验证/发布(**实施看板**)。
2526
- [工程实施方案](../docs/architecture/engineering-plan.md) — 路径 B 架构 + M0-M5 里程碑(**开发蓝图**)。
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# 分支前缀分组树(Group Branches by Prefix)
2+
3+
> Branches 视图的 **Local / Remote / Tags** 三段支持在**平铺列表**与**按 `/` 前缀分组的文件夹树**之间切换(对齐 VS Code SCM / GitLens 的分支分组)。共享前缀的分支收拢到以前缀命名的可折叠文件夹下,叶子仅显示末段后缀;工具栏一键切换、按仓库记忆偏好,默认树形。**Favorites 段恒平铺**并显示完整短名。
4+
5+
## 效果:扁平 → 前缀树
6+
7+
```mermaid
8+
flowchart LR
9+
subgraph FLAT["平铺(切换前)"]
10+
direction TB
11+
a1["bak/2025"]
12+
a2["bak/master-2025-07"]
13+
a3["feature/1.0.0"]
14+
a4["2022 / 2023 / 2024"]
15+
end
16+
subgraph TREE["前缀树(切换后)"]
17+
direction TB
18+
b0["📁 bak"] --> b1["2025"]
19+
b0 --> b2["master-2025-07"]
20+
b3["📁 feature"] --> b4["1.0.0"]
21+
b5["2022 / 2023 / 2024"]
22+
end
23+
FLAT -->|Group by Prefix| TREE
24+
style b0 fill:#8957e5,color:#fff
25+
style b3 fill:#8957e5,color:#fff
26+
```
27+
28+
远程段整体收拢为单个 `origin` 文件夹,内部再嵌 `feature`:`origin/feature/1.0.0` → `origin` → `feature` → `1.0.0`。
29+
30+
## 设计:引擎算树、适配层渲染(单一事实源)
31+
32+
分支前缀分组与「变更文件目录树」(见 [file-list-group-by-directory](./file-list-group-by-directory.md))是同构问题,故沿用其成熟范式:纯逻辑引擎构树、上层仅渲染。
33+
34+
```mermaid
35+
flowchart LR
36+
A["RawRef[]<br/>(displayRefs,已滤 origin/HEAD)"] -->|adapter| B["buildRefTree()<br/>engine/ref/ref-tree"]
37+
B -->|"RefTreeNode[]<br/>(folder / leaf)"| C["BranchesTreeProvider<br/>toBranchNodes()"]
38+
C --> D{"grouping?"}
39+
D -->|on| E["文件夹节点 + 后缀叶子"]
40+
D -->|off| F["平铺(既有排序)"]
41+
style B fill:#1f6feb,color:#fff
42+
style E fill:#238636,color:#fff
43+
```
44+
45+
- **纯逻辑 `buildRefTree`**([`engine/ref/ref-tree.ts`](../../src/engine/ref/ref-tree.ts),零 vscode 依赖、Vitest 覆盖):按 `shortName` 的 `/` 分段建 trie;叶子携带完整 `RawRef`(短名不丢,命令仍以 `ref.shortName` 定位)、`label` 取末段后缀。**分支感知排序**——当前 HEAD(第 0 档)→ 收藏(第 1 档)→ 同档内**文件夹在前**、名称数字感知升序、稳定;**compact 折叠**单目录子链(如 `a/b/c` → `a/b`,遇含叶子或多子目录即停,对齐 VS Code `explorer.compactFolders`)。
46+
- **含 `/` 的远程名无需特判**:fork 场景 remote 名可含 `/`(如 `myorg/repo`),compact 折叠会把 `myorg/repo` 单目录子链渲染为单个文件夹,视觉上与「remote 为一层」等价;删除等**正确性敏感**逻辑仍走 [`resolveRemoteBranch`](../../src/engine/ref/remote-ref.ts) 的最长前缀匹配,两者正交不耦合。
47+
- **隐藏 `origin/HEAD`**:远程符号引用 `refs/remotes/<remote>/HEAD`(短名如 `origin`)非真实分支,视图统一过滤(`isRemoteHead`)——既对齐主流 Git UI,也消除「`origin` 叶子」与分组后「`origin` 文件夹」的同名冲突,远程计数随之归为真实分支数。
48+
49+
## 切换 UI:原生 TreeView 双命令 + context key
50+
51+
Branches 为原生 TreeView(非 webview),切换采用 VS Code 惯用范式:两条互斥命令 + `setContext` 驱动工具栏按钮显隐。
52+
53+
| 状态 | 工具栏按钮 | 命令 | 图标 |
54+
|---|---|---|---|
55+
| 平铺 | 显示「分组」 | `hyperGit.branchesGroupByPrefix` | `$(list-tree)` |
56+
| 树形 | 显示「平铺」 | `hyperGit.branchesFlatten` | `$(list-flat)` |
57+
58+
- context key `hyperGit.branchesGrouping` 由 [`extension.ts`](../../src/extension.ts) 在 `activate` 时按 provider 持久化初值设定,命令翻转时同步更新;`package.json` 的 `view/title` `when` 子句据此互斥显示两按钮。
59+
- 偏好按仓库持久化于 `workspaceState`(键 `hyperGit.branchesGrouping:${repoRoot}`,仿 [`BranchFavorites`](../../src/adapter/branch-favorites.ts)),重启后恢复;文件夹默认展开、点击即折叠/展开,展开态经 `TreeItem.id`(`folder:${group}:${path}`)跨刷新稳定。
60+
61+
## 兼容性(命令零破坏)
62+
63+
文件夹节点使用独立 `contextValue` `hyperGit.branchFolder`,不匹配任何 `view/item/context` 命令 → 无右键菜单;多选批量经 [`selectedBranchRefs`](../../src/adapter/branch-selection.ts) 只保留 `kind === 'branch'`,文件夹节点天然被忽略。checkout / delete / rename / merge / rebase / compare / favorite 等命令均无需改动。
64+
65+
## 实现
66+
67+
- 引擎:[`engine/ref/ref-tree.ts`](../../src/engine/ref/ref-tree.ts)(+ [`tests/unit/ref-tree.test.ts`](../../tests/unit/ref-tree.test.ts),12 用例)。
68+
- 适配层:[`adapter/tree/branches-tree.ts`](../../src/adapter/tree/branches-tree.ts)(`BranchFolderNode`、`grouping` 状态与持久化、`isRemoteHead` 过滤、`sectionNodes`/`toBranchNodes`、folder 的 `getTreeItem`)。
69+
- 装配 / 贡献点:[`extension.ts`](../../src/extension.ts)(context key + 命令)、[`package.json`](../../package.json)(两命令 + `view/title` 互斥菜单)。
70+
71+
## 验证
72+
73+
`pnpm run test:unit`(含 `ref-tree.test.ts`)全绿;Extension Development Host(F5):Local/Remote/Tags 在平铺 ⇄ 树间即时切换、刷新后保持;共享前缀收拢为文件夹、叶子仅显示后缀;`origin/HEAD` 不再单列、远程计数为真实分支数;文件夹可折叠、compact 生效;分支右键命令与多选批量均正常,文件夹节点无菜单、被多选忽略。

‎docs/i18n/zh-CN/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
- **多 Changelist Changes 视图**:将改动分组到命名列表,设活动列表为提交目标,新建/重命名/删除/移动,`workspaceState` 持久化(重启恢复);状态色复用 `gitDecoration.*` 主题色。
2828
- **Commit 提交窗口**:自绘提交面板 + Conventional Commits 实时校验 + Amend / Sign-off / 跳过 Hook + 提交 / 提交并推送;勾选集即提交权威范围;最近消息复用。
2929
- **Log 提交图(自绘 DAG)**:彩色泳道、分叉·合并连线、HEAD/分支/标签徽标,虚拟滚动增量加载;7 个可组合过滤器(作者/路径/grep/正则/合并模式/日期/清除);per-commit 操作(Reset、新建分支·标签、Cherry-Pick、Revert、查看包含分支)。
30-
- **Branches 分支管理**:收藏/本地/远程/标签四段分组 + ahead·behind·upstream 跟踪;新建/检出/删除/重命名/合并/变基/比较/收藏;**多选批量**删除、复制引用、收藏(已合并/未合并诚实分栏确认)。
30+
- **Branches 分支管理**:收藏/本地/远程/标签四段分组 + ahead·behind·upstream 跟踪;**前缀文件夹分组**(平铺 ⇄ 树切换)将共享 `/` 前缀的分支收拢到共同前缀下、仅显示后缀;新建/检出/删除/重命名/合并/变基/比较/收藏;**多选批量**删除、复制引用、收藏(已合并/未合并诚实分栏确认)。
3131
- **Stash & Shelf**:Stash 全操作(含 keep-index / clear / 从 Stash 建分支);独立 **Shelf**(基于 patch、独立于 stash,含 3-way 合并 Unshelve)。
3232
- **Worktrees**:全生命周期管理——新建(新分支/检出/detached)、在新窗口打开、锁定/解锁、移动、删除、清理失效。
3333
- **行级与 Hunk 提交**:编辑器内 CodeLens「Commit this Hunk」、部分暂存/取消暂存、光标处暂存、Hunk 归属 Changelist。

‎package.json‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,18 @@
194194
"category": "Hyper Git",
195195
"icon": "$(refresh)"
196196
},
197+
{
198+
"command": "hyperGit.branchesGroupByPrefix",
199+
"title": "Group Branches by Prefix",
200+
"category": "Hyper Git",
201+
"icon": "$(list-tree)"
202+
},
203+
{
204+
"command": "hyperGit.branchesFlatten",
205+
"title": "Show Branches as Flat List",
206+
"category": "Hyper Git",
207+
"icon": "$(list-flat)"
208+
},
197209
{
198210
"command": "hyperGit.logFilter",
199211
"title": "Filter Graph…",
@@ -764,6 +776,16 @@
764776
"when": "view == hyperGit.branches",
765777
"group": "navigation@5"
766778
},
779+
{
780+
"command": "hyperGit.branchesGroupByPrefix",
781+
"when": "view == hyperGit.branches && !hyperGit.branchesGrouping",
782+
"group": "navigation@6"
783+
},
784+
{
785+
"command": "hyperGit.branchesFlatten",
786+
"when": "view == hyperGit.branches && hyperGit.branchesGrouping",
787+
"group": "navigation@6"
788+
},
767789
{
768790
"command": "hyperGit.fetch",
769791
"when": "view == hyperGit.branches",

0 commit comments

Comments
 (0)