Repository navigation
release-v0.1.10
0.1.10
0.1.9 让索引说清楚「我知道什么、不知道什么」。0.1.10 做的是另一半:在漂移影响到你之前先说出口——提交时间线终于是一张图、每个提交带着它碰过的文件、被查询的工具会在结果前面加一句实话,CI 也能用一个退出码挡住「索引漏了文件」。
新增
提交时间线是图,不是一列点
0.1.9 的泳道有三个毛病被人一眼看出来:线宽 10px 而点直径只有 6.4px,相邻两列差不到一个点的宽度;颜色编码的是「索引裁决」,于是每条分支都是同一个绿;git log 只走 HEAD,除 merge 外根本没有并行可画。三处一起改:
- 列宽 14、每列一个固定色(八色调色板),点用自己列的颜色,索引裁决改成点外面的细环——两套语义不再抢同一个通道。
--all:时间线读所有 ref,才真的出现并行分支;代价是聚合统计(提交者、改动数)也计入未合并分支,这一点写进了命令注释。- 分支名进载荷:解析
%D(HEAD -> main, origin/main, tag: v0.1.9)得到refs,行内渲染成与列同色的胶囊,HEAD ->剥成裸分支名,tag:前缀保留(tag 不是分支)。 - 超过 6 列折叠:右缘写
+N,数字按本行穿过的被折叠列统计,而不是laneCount - 6(否则只穿越两条线的行会谎报)。<title>里仍报真实总数。 - 悬停一行:该行的线加粗到 2.8px、点放大 0.7px,它穿越的其它列淡到 0.3——在并排三条线时能一眼分清「这条是哪一行」。
- 曲线用竖直中位控制点的三次贝塞尔,线与点在 6.5px 处留空(
DOT_RADIUS + DOT_GAP),不再有线从点中间穿过去。
没有引入图库,理由记在计划文档 §2.1:@gitgraph/core 按「分支从哪个提交创建」分列,用 --all 反推会把主干塞进匿名列;而本插件的客户端构建链没有 bundler,引包只能 vendored 源码。
每个提交带着它碰过的文件,点文件就地看 diff
git log现在多解析%P(父提交)与--numstat的逐文件增删,每个提交带changed: [{ path, insertions, deletions }],在解析处按 40 个封顶(COMMIT_FILE_LIMIT),超出的提交标filesTruncated,面板写「仅列出前 40 个文件(共 N 个)」。- 点提交展开文件列表,再点某个文件,就地复用已有的
DiffView渲染补丁——走的是 0.1.8 就有的/api/gitnexus/file-diff路由,没有新路由、没有新的写路径。宿主不认识这条路由时,面板明说「当前宿主没有文件改动路由;重启 DSH 后再试」,不伪装成空 diff。
「更多」不是「最多看到前几个」
四个文件列表各自记住翻到哪(基线 8、频繁 8、最近 5、缺失 8,每次 +25),提交时间线一次 15 条、每次 +50,尾部按钮写清还剩多少。翻页状态按列表分开存,切列表不会互相重置。
索引落后时会先说话(面板与三个工具)
一句话由 describeStaleness() 生成,面板与工具共用同一套规则:
- 干净就一个字都不说:
needsRefresh === false且certain === true才返回null。截断过的「干净」不算干净,会走第三类。 - 落后就说清楚:「索引落后:自
99c1e78起 16 个文件已改(14 改 / 2 增 / 0 删),以下结果可能过期;建议增量刷新。」 - 无法确认单独措辞:「索引新鲜度无法确认…;以下结果可能过期。」
unknown不借用「落后」这句话——否则用户会去刷新一个本来没问题的索引。
gitnexus_impact / gitnexus_context / gitnexus_query 的返回顶部会带上这句(5 秒 TTL,失败静默;工具本身从不为测新鲜度而变慢);面板把它画成图卡片顶部的一条窄提示。老宿主根本不发这个字段,所以客户端把「缺席」当作 null:宁可安静,也不误报。
CI 能挡住「索引漏了文件」
gitnexus-coverage 新增两道门,与原有的 --fail-on-large 分工:
| 开关 | 命中 | 退出码 |
|---|---|---|
--fail-on-uncovered |
扫描选中但索引里没有的文件 | 3 |
--fail-on-missing |
没有索引、索引指向已删文件、目标分析不了 | 3 |
--fail-on-large |
有文件因体积上限被跳过(原有) | 2 |
2 说的是「索引有一个记录在案的洞」,3 说的是「索引和检出已经分叉」——两者的处置不同,所以不合并。原因行打到 stderr,--json 仍可被 JSON.parse 直接吃掉,退出码才是契约。裁决本身是纯函数 coverageGateVerdict(),因为一道不能被 import 的门禁就没法被测试。
提交前检查不再被「改动过的脚本文件」卡住
test/run.mjs 的顶层 await 收进 export async function main(),只在作为入口运行时执行。这不是风格问题:detect-changes 把改动行映射到符号,一个整体都是顶层语句的文件没有任何符号区间可落,于是整次检查回 PARTIAL。
修正
- 「索引不收录这个文件」不再被说成「新增」:
git diff --name-status区分了「仓库刚得到这个文件」与「仓库一直有、索引从来没记过」。像.gitignore这类没有扩展名的小文件永远不会进索引,以前每次改动都会让门禁说「1 个新增」,现在归为excluded并写清「刷新也不会收录」,needsRefresh不再被它触发。 - 临时目录(
.tmp-probe/、.tmp-npm-cache/、.tmp-gitnexus-home/)进了.gitignore:它们会被 delta 引擎当成待索引文件,这正是新鲜度信号承受不起的噪音。
验证
npm run check三套 tsc 全绿;npm test1254 项(引擎 852 / 插件 81 / 客户端 321),0 failed。- 本版的五条提交各自单独 check 过:只 checkout 面板批时 815 / 81 / 307,只 checkout 工具批时 827 / 81 / 310,全绿。
- 变异测试:把
file-diff路由字符串改掉一个字并重建,恰好红一条(「opening a file asks the host for that commit and that path」),其余 320 条仍绿——证明点击链的测试真的会失败,而不是永远为真。 - 索引刷新到
5,352 nodes | 12,420 edges | 115 clusters | 297 flows、121 个文件哈希;门禁checked 0,detect-changes --scope all输出No changes detected,gitnexus-coverage . --fail-on-uncovered --fail-on-missing退出 0。
已知限制
- 交互链的自动化用的是自写的迷你渲染器(没有
react-dom,也不打算为测试装一个浏览器):它证明的是数据与状态流,不是像素。 - 脚本形态的文件(
src/bin/*.ts、测试入口)只要改动落在顶层,detect-changes仍会回PARTIAL,与索引是否新鲜无关;本版两次撞上都已在提交说明与计划文档 §13.5 里归因。 - 观感(曲线手感、暗色对比度、窄侧边栏下的拥挤程度)只能靠离线栅格化加人眼,没有自动化。