web-terminal · 设计稿

项目详情页 · Git 面板

把「有没有 commit 没推」「现在在哪个 worktree」变成不用问就能看见的信息。 下面每一块都用 web-terminal 此刻的真实状态渲染 —— 包括那个正在说谎的 ↓0。

分支 develop 未推送 9 未提交 3 上次 fetch 19 天前 worktree 2
01

同步状态条

接线即可

替换现在标题行里那个孤零零的圆点。四个格子回答四个问题:我在哪个分支、有多少要推、有多少要拉、这两个数字还能不能信

web-terminal develop ● 3 未提交
/Users/yiukai/Documents/git/web-terminal
Upstream origin/develop
待推送 ↑ 9 9 个 commit 只在本地
待拉取 ↓ 0 存疑 上次 fetch 在 19 天前 — 这个 0 不可信

「存疑」标记是这块最重要的设计。ahead/behind 比的是本地缓存的 @{u},不 fetch 就永远不会变 —— 没有这个标记,面板会自信地告诉你已经同步,而这正是它此刻在做的事。 规则:FETCH_HEAD 的 mtime 超过阈值(建议 1 小时)就给 ↓ 挂上存疑,并把 Fetch 按钮点亮。 Fetch 是只读的,不 pull、不 merge —— 符合写侧一贯的克制。

02

提交列表 · 推送分界线

新增

你要的不是「有 9 个没推」这个数字,而是哪 9 个。复用现有的 commit 列表,给未推送的加左侧竖线和 ↑,在边界上画出 upstream 的位置 —— 一眼看完,零点击。

Recent commits ↑ 9 未推送
553a00c8mdocs(progress): log the three leftover fixes + live verification
d92caed22mMerge fix-tunnel-leftovers: gitignore-swallowed source, host identifiers in logs
2a602d531mfix(tunnel): close the three leftovers from the renewal-deadlock fix
befe6771hMerge fix-cert-renew-deadlock: break the expired-leaf renewal deadlock
7064a391hchore: drop accidentally committed node_modules symlinks
0970c621hdocs(progress): log the expired-leaf renewal deadlock fix + live self-heal proof
5509c812hfix(tunnel): recover an expired leaf over plain HTTPS, not mTLS
f3f4d8b2hfix(tunnel): break the expired-leaf renewal deadlock
b1bc50c3hfix(session): give the PTY a UTF-8 locale so tmux stops mangling CJK
origin/develop
1dbed546ddocs(progress): log the zero-touch enrollment + control-panel session
675de779dfeat(control-panel): web admin UI for the zero-touch tunnel
7c1d43310dMerge feat/zero-touch-enrollment: zero-touch tunnel enrollment (host + phone)
0b35dc010dfeat(android): wire zero-touch device enrollment + fix renew/cache (B-track)
显示最近 20 条

分界线不是装饰 —— 它是 origin/develop 在时间轴上的真实位置。分支没有 upstream 时不画线,改在顶部显示「无 upstream」(见 ④)。

03

Worktree 面板

重做

现在这块叫 BRANCH、只有一行。按「每个 session 一个 worktree」的规矩,它很快会变成 4–5 行,而且每一行要能独立回答:哪个分支、在哪、干净不干净、推没推、里面跑着谁。这是编辑器给不了的视角 —— Cursor 一次只看得见一个 worktree。

Worktrees 2
develop 当前 ● 3 ↑ 9
/Users/yiukai/Documents/git/web-terminal
2 sessions
worktree-project-detail-git-mockup 干净 无 upstream
.claude/worktrees/project-detail-git-mockup
1 session

「无 upstream」必须显式标出。新建的 worktree 分支天然没有 upstream,ahead/behind 全是 undefined —— 绝不能因为「没有数字」就渲染成绿色的「已同步」。这是这套 UI 最容易犯的错。

04

状态变体

规格

同步条的全部形态。做设计稿的意义一半在这里 —— 边界情况不定死,实现时就会各写各的。

已同步 · 刚 fetch
✓ 已同步
↑0 ↓0 且 fetch 在阈值内。唯一可以显示绿色的情况。
待推送
↑ 9
主状态。数字用 accent,提交列表同步高亮。
待拉取
↓ 3
用中性色而非警告色 —— 落后不是错误,只是信息。
数据陈旧
存疑
FETCH_HEAD 超过 1 小时。挂在 ↓ 上,不挂在 ↑ 上 —— ↑ 不依赖 fetch,永远准。
无 upstream
无 upstream
新 worktree 分支的默认状态。不显示 ↑↓,不显示绿色。
HEAD 游离
detached HEAD
不显示分支名和 ↑↓,只显示短 sha。push 按钮禁用。

只有一个状态配用绿色:↑0 ↓0 且刚 fetch 过。其余一律中性或警示 —— 绿色在这里的含义是「我确认过了,你不用管」,给错了就是骗人。

05

数据来源与成本

编号 = 建议实现顺序。01 和 02 共用同一份数据,应该一个 PR 一起做。

元素数据来源后端现状
分支名 .git/HEAD(不 spawn 进程) ✓ 已有
↑ ahead / ↓ behind git rev-list --count --left-right @{u}...HEAD 助手已有,ProjectDetail 没接
upstream 名字 git rev-parse --abbrev-ref @{u}
未推送的 sha 集合 git log @{u}..HEAD --format=%H
上次 fetch 时间 .git/FETCH_HEAD 的 mtime(不 spawn)
Fetch 按钮 git fetch --no-tags,只读 缺(需新路由)
未提交数量 git status --porcelain 的行数 只有布尔 dirty,没有计数
worktree 列表 git worktree list --porcelain ✓ 已有
每个 worktree 的 dirty / ↑↓ 同上,逐 worktree 跑一次 缺 — 成本最高的一项

成本控制。只有分支名和 fetch 时间是读文件、免费的;其余每项都要 spawn 一次 git,而这台机器同时在跑 Claude Code 和构建。三条便宜的对策:按仓库去重(N 个 tab 同一个 repo 只查一次)、盯 .git/HEAD / .git/index / .git/refs 的 mtime 变了才查、页面隐藏时暂停。逐 worktree 的 ↑↓ 建议懒加载 —— 展开那一行才算。

范围外。这一页不加 reset、不加切分支 checkout、不加 clean、不加 force-push。 stage / commit / push 已经在 diff.ts 里,维持现状。 这块面板的职责是告诉你发生了什么,不是替代编辑器去处理它。