Skip to content

feat(history): add commit lineage highlight with hover + selection#2348

Draft
heartacker wants to merge 11 commits into
sourcegit-scm:developfrom
heartacker:feat/lineage-highlight-clean
Draft

feat(history): add commit lineage highlight with hover + selection#2348
heartacker wants to merge 11 commits into
sourcegit-scm:developfrom
heartacker:feat/lineage-highlight-clean

Conversation

@heartacker
Copy link
Copy Markdown
Contributor

背景

在提交历史视图中,用户很难快速判断一个提交与其祖先/后代的关系,尤其在 merge 较多时。这个 PR 引入“提交血缘高亮”能力,支持:

  • 选中提交后高亮其血缘路径
  • 鼠标悬停提交时即时预览其血缘路径
  • 在仓库页提供可开关的配置项

设计思路

核心目标是把“血缘关系”从数据层、状态层、渲染层、交互层分离,保证功能可扩展且编译/行为稳定。

  1. 索引层(Index Mapping)
  • 建立 SHA -> Commit 映射与 ParentSHA -> Children 反向映射,避免每次查询线性扫描。
  • Commit 与图形元素记录稳定的索引(Commit.Index / PathIndex / StartCommitIndex / EndCommitIndex),把“图上元素”与“历史列表项”连接起来。
  1. 查询层(Lineage Query)
  • 使用 BFS 分别向上(祖先)和向下(后代)搜索。
  • 通过 visited 集合去重,避免在复杂图中重复遍历。
  • 增加深度上限,控制最坏情况开销,避免大仓库下 UI 卡顿。
  1. 状态层(ViewModel State)
  • 新增悬停与选中两套 lineage 状态集合,分别驱动临时预览与稳定高亮。
  • 在选中项变化时异步计算目标 lineage,计算完成后回到 UI 线程更新,避免阻塞界面。
  1. 渲染层(Graph Rendering)
  • CommitGraph 中根据 lineage 状态提升路径/连线可视权重(线宽与显著度)。
  • 与“仅高亮当前分支”策略兼容:非目标路径按灰化处理,目标 lineage 保留强调。
  1. 交互层(Hover + Toggle)
  • 悬停时把 DataGrid 行索引映射为提交索引,触发 lineage 预览。
  • 通过仓库级 UI 配置项开启/关闭选中 lineage 高亮,默认行为可控。

方法与关键实现

  • 数据结构:Dictionary<string, Commit>Dictionary<string, List<Commit>>HashSet<int>
  • 遍历算法:双向 BFS(parents/children)
  • 并发策略:Task.Run 计算 + Dispatcher.UIThread.Post 回写
  • 复杂度(单次查询):
    • 时间:约 O(V + E)(受 depth 限制)
    • 空间:约 O(V)(队列 + visited + 结果集合)

提交拆分

本 PR 按“可独立编译 + 渐进集成”拆分为 6 个提交:

  1. feat(CommitGraph): add index tracking for paths and links
  2. feat(Histories): add commit lineage query engine
  3. feat(Histories,CommitGraph): add lineage state management
  4. feat(CommitGraph): implement lineage highlight rendering
  5. feat(Histories): add hover-based lineage highlighting interaction
  6. feat(Histories,Repository): add UI configuration for lineage highlighting

验证方式

  • 构建验证:dotnet build SourceGit.slnx 通过
  • 功能验证:
    • 单选提交后,图中血缘路径被正确高亮
    • 鼠标悬停不同提交时,预览路径实时切换
    • 切换配置项后,高亮开关行为符合预期

影响范围

  • 主要影响 History/CommitGraph 相关模块与 Repository 配置入口。
  • 对现有 Git 命令执行链无侵入,仅新增图查询与可视化增强逻辑。

风险与后续优化建议

  • 大型仓库下 hover 高频触发仍可能带来额外计算成本。
  • 后续可考虑:
    • lineage 结果缓存(LRU)
    • hover 防抖 + 任务取消
    • 使用边集合直接驱动高亮以提升精确性

@heartacker
Copy link
Copy Markdown
Contributor Author

heartacker commented May 15, 2026

把我之前的实现用 AI 帮我从新整理了一下。

抛砖引玉并希望可以继续讨论

#2344

@heartacker heartacker marked this pull request as draft May 15, 2026 11:41
@heartacker heartacker force-pushed the feat/lineage-highlight-clean branch from 33f8e79 to e795dc5 Compare May 15, 2026 12:28
@love-linger
Copy link
Copy Markdown
Collaborator

Just try the feature/highlighting-in-graph

image

@heartacker heartacker force-pushed the feat/lineage-highlight-clean branch from e795dc5 to 8d804fb Compare May 15, 2026 14:20
@heartacker
Copy link
Copy Markdown
Contributor Author

好的,试试你的实现。对了。

希望你能,你可以看看我的实现。你可以checkout我的分支编译体验下不。真心感谢。

真心希望你能感受一下。我在X11 转发下,dotnet run 下,在大型项目(vscode的源代码)下性能还是很快的。

Uploading hhahaha.mp4…

@heartacker
Copy link
Copy Markdown
Contributor Author

我试了你的实现体验和我的类似。

但是我的这种方式(不是说代码质量)而是说体验感觉会更好。可以搜索子类,父类。还自带追踪和加粗)

image image

@love-linger
Copy link
Copy Markdown
Collaborator

我想我在 #2344 中应该已经说的很明确了。我并不希望加入任何hover相关的功能,一是没有任何明确的功能性,二是搞的跟跑马灯似的。

@heartacker
Copy link
Copy Markdown
Contributor Author

heartacker commented May 15, 2026

明白。我是这样理解的。

  1. 我觉得可以保留这种可能性。如果解析逻辑不错的话。 这个可以不加粗。
  2. 第二就是childs 搜索。这个也很关键。
  3. 因为我主要用我自己的添加很多其他东西的版本,所以希望底层代码能保留这种可能性。我后续紧跟你的新代码 rebase 的话 也方便处理。

@heartacker
Copy link
Copy Markdown
Contributor Author

甚至可以添加一个选项。默认关闭也行

@heartacker
Copy link
Copy Markdown
Contributor Author

heartacker commented May 15, 2026

顺带提一下,我一朋友是色盲(红绿)也是程序员,他的反馈是这个加粗功能给他比较大的帮助。建议保留这个可能性。

## 改动思路与算法

### 问题
提交图中的 Path/Link 与具体 Commit 缺少稳定索引映射,后续做血缘高亮时无法 O(1) 命中。

### 方案
建立三层映射:SHA -> Commit.Index -> Commit.PathIndex。
- 在 Commit 模型新增 Index、PathIndex(默认 -1)
- 在 CommitGraph.Parse 阶段为路径分配连续 PathIndex
- 在 Histories 侧按列表顺序初始化 Commit.Index

### 关键实现
1. 给 Path / Link 增加起止提交索引字段,避免渲染期反查字符串 SHA。
2. Parse 时维护 pathIndex 计数器,完成 Commit 到绘制 Path 的静态绑定。
3. 补充 CommitLineageSearchMethod 枚举,为后续 lineage 查询提供统一方向定义。

### 复杂度与收益
- 初始化复杂度:O(commits + paths)
- 渲染阶段索引命中:O(1)
- 相比字符串比对,int 索引在高频绘制循环中更节省 CPU 与内存。
## 改动思路与算法

### 问题
仅靠当前选中提交无法快速得到完整血缘关系(祖先/后代/双向),并且在大仓库中容易出现遍历开销过大。

### 方案
在 Histories 中实现基于 BFS 的血缘查询引擎,并引入预构建索引。
- _commitMap: SHA -> Commit
- _childrenMap: ParentSHA -> Children[]

### 关键实现
1. 在 PostCommitsChanged 中一次性构建两张 Map,避免查询期重复扫描。
2. GetCommitLineage(commit, method, depth)
   - 使用队列做 BFS
   - 使用 visited 防止重复访问
   - 支持 ParentsOnly / ChildsOnly / FullLineage
3. 增加 depth 上限(默认 1000),避免极端图结构导致卡顿。

### 复杂度与收益
- Map 构建:O(N + E)
- 单次 lineage 查询:O(V + E)(受 depth 限制)
- 相比每次线性扫列表,交互场景延迟显著下降。
## 改动思路与算法

### 问题
lineage 查询与 UI 绘制耦合过深,容易阻塞主线程,且缺少 hover/selected 两类状态的统一管理。

### 方案
建立“计算层 + 状态层 + 视图层”三段式状态管理。
- Histories 维护 HoveredCommitIndex / HoveredLineageCommits / SelectedLineageCommits / SelectedLineagePaths
- CommitGraph 暴露对应 AvaloniaProperty 并参与重绘触发

### 关键实现
1. 计算放到后台线程:Task.Run
2. 结果回到 UI 线程:Dispatcher.UIThread.Post
3. 通过属性变更触发局部重绘,保证交互实时性。
4. 保留 HighlightSelectedLineage 开关,兼容配置驱动的启停。

### 复杂度与收益
- 查询成本沿用 BFS 引擎
- UI 线程只做状态应用与绘制,不做重计算
- 在大历史列表中滚动/悬停更平滑。
## 改动思路与算法

### 问题
已有 lineage 结果但渲染层无法表达“选中血缘/悬停血缘/当前分支高亮”的优先级关系。

### 方案
重写 DrawCurves 高亮判定路径,按优先级合成样式:
hovered > selected > currentBranch > default。

### 关键实现
1. 通过 SelectedLineageCommits / HoveredLineageCommits / SelectedLineagePaths 做 O(1) 命中。
2. 对命中的 Path/Link 使用更粗线宽(hoverBold)与更高对比色。
3. 当 only-highlight-current-branch 开启时,非目标线统一灰化。
4. 保持锚点绘制与曲线绘制一致的索引语义,避免视觉跳变。

### 复杂度与收益
- 每次重绘主循环为 O(paths + links)
- 判定阶段以 HashSet 查询为主,避免字符串比较。
- 视觉反馈清晰,且不会显著增加重绘开销。
缺少鼠标悬停驱动的 lineage 交互,用户只能通过选中提交观察血缘。

在 Histories 列表中加入基于指针位置的行命中算法,并触发异步 lineage 计算。

1. 在 OnPointerMoved 中用坐标换算行号:
   row = floor((y - headerHeight) / rowHeight)
2. 做边界检查,越界时回退为 -1,避免脏状态。
3. HoveredCommitIndex 变化后触发 CalculateTargetLineage。
4. 复用既有 BFS 引擎,计算逻辑统一,避免双实现漂移。

- 行命中 O(1)
- lineage 计算与选中逻辑共享,维护成本低
- 提升探索历史关系的交互效率。
@heartacker heartacker force-pushed the feat/lineage-highlight-clean branch 2 times, most recently from b9874d3 to a1f84fd Compare May 15, 2026 17:10
@heartacker
Copy link
Copy Markdown
Contributor Author

710e17e - perf(Histories): optimize lineage calculation with linear scan and bit array(O(V+E) -> O(N)).

  1. 废弃 Queue 驱动的 BFS,改用连续内存的 bool[] 数组配合双向固定窗口(视口感知)进行线性扫描。
  2. 渲染层规避 Hash 计算,让 Render 循环直接通过索引读取 bool[] 状态进行 O(1) 的纯指针偏移操作。

int viewportBottomIndex = -1)
{
var active = new HashSet<int>();
var active = new bool[_commits.Count];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably not the best thing. What the size of _commits might be?

Does C# have the BitSet collection? It might be better choice here.

@heartacker heartacker force-pushed the feat/lineage-highlight-clean branch from 710e17e to fa09e59 Compare May 15, 2026 23:43
…ting

lineage 高亮能力已具备,但缺少用户可控开关和页面级配置入口。

打通 Repository UI -> Repository VM -> Histories VM -> CommitGraph 的配置链路,并补齐多语言文案。

1. Histories 视图新增 HighlightSelectedLineage AvaloniaProperty。
2. Repository ViewModel 新增代理属性 HighlightSelectedLineageInHistory,映射到 Histories VM。
3. Repository 页面增加 ToggleButton,并将原有按钮列位顺移保持布局稳定。
4. Histories.axaml 为 CommitGraph 增加完整绑定:
   HoveredCommitIndex / HoveredLineageCommits / SelectedLineageCommits / SelectedLineagePaths / HighlightSelectedLineage。
5. en_US / zh_CN 新增 tooltip 资源键,保证国际化一致性。

ToggleButton(TwoWay) -> Repository.HighlightSelectedLineageInHistory -> Histories.HighlightSelectedLineage -> CommitGraph 重绘。

- 用户可按需启用高亮,默认行为不被破坏。
- 功能发现路径清晰,交互与配置一致。

AAA
思路:将悬停血缘查询从固定深度遍历改为“深度 + 视口”双边界约束,减少大仓库下无效搜索。

方法:
1. 在 Histories 视图层统计 DataGrid 当前可见行范围(topIndex, bottomIndex)。
2. 通过 ViewModel 接口回传可见范围并保存。
3. Hover 触发查询时在原有 depth 基础上叠加 viewportTop/viewportBottom 约束。
4. 引入 guard band(边缘余量)避免视口边界附近高亮突变。

效果:
- 减少 hover 高频滑动时的节点遍历数量。
- 提升复杂提交图下的交互流畅性。
- 保持原有高亮判定语义不变,仅优化查询范围。

实现点:
- src/Views/Histories.axaml.cs:计算并上报可见索引范围。
- src/ViewModels/Histories.cs:新增可见范围状态与带视口参数的 lineage 查询。
在“允许滚动条自动隐藏”下方新增了“开启悬停视图跟踪”的全局选项,并配置了多语言翻译。

FAILED TEST CASES: NONE
…t array(O(V+E) -> O(N)).

1. Replaced Queue-based BFS with bidirectional linear scan (O(V+E) -> O(N)).
2. Changed HoveredLineageCommits and SelectedLineageCommits from HashSet<int> to bool[] array for CPU cache-friendly iteration.
3. Updated CommitGraph render loops to use O(1) array index lookups instead of hash set containment checks.
4. Dropped _childrenMap tracking for faster memory allocation.

FAILED TEST CASES: NONE
@heartacker heartacker force-pushed the feat/lineage-highlight-clean branch from fa09e59 to 639f8ce Compare May 16, 2026 00:05
1. Introduced CommitGraphHighlighting enum to consolidate highlighting modes.
2. Replaced individual toggle buttons in Repository view with a unified menu in Histories column header.
3. Updated CommitGraph rendering to respect the new HighlightMode enum.
4. Added multi-language localizations for the new highlighting modes.
5. Maintained dynamic lineage calculation for hover support while adopting the cleaner UI structure from upstream.

FAILED TEST CASES: NONE
1. Added 'Lineage Search Method' configuration to the Histories header menu.
2. Included 'Parents Only', 'Children Only', and 'Full Lineage' options.
3. Persisted lineage search preference in RepositoryUIStates.
4. Updated lineage calculation logic to respect the selected search method.
5. Added localizations for the new menu items.

FAILED TEST CASES: NONE
@heartacker heartacker force-pushed the feat/lineage-highlight-clean branch from 8ee6c59 to 0ef3676 Compare May 16, 2026 00:35
@heartacker
Copy link
Copy Markdown
Contributor Author

按照 e3d15ff - refactor: highlighting in commit graph

思路也顺带改了菜单。感觉这个方便点。

1778891764102_d

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants