[Bug] Git Log 加载更多报 Invalid Git history cursor:cursor 会话空闲 120 秒被回收且无自动恢复

オープン
#1,652 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
25/100
issue の種類
バグ
明瞭さ
おおむね明確
活発さ
活発
技術スタック
git, rust, typescript
領域
backend, devtools

調査の方向性

Start in rust/lithe-core/src/git/history.rs, where HISTORY_CURSOR_IDLE_TTL, the reaper and the git.historyPage cursor sessions live, then read the client handling in use-git-log-controller and getGitHistoryPage. Reproduce by idling past 120 seconds before loadMore, and confirm the Invalid Git history cursor error. Done means that loadMore recovers after idle expiry without leaving the panel in the failed state. The maintainers have not chosen between stateless tiered paging and an offset fallback, so agree on the approach first.

索引モデルが issue の本文から書いたものです。

説明

review: medium
Platform / 平台

Windows

Area / 模块

Git

Lithe version / Lithe 版本

0.6.6(stable 安装包)

Priority / 优先级

P1 / 尽快处理:使用体验大幅下降,但通常仍可继续使用

OS and architecture / 操作系统与架构

Windows 11 Pro(build 26200),x64

Environment / 环境信息
  • Lithe 0.6.6 stable 安装包,普通用户权限运行
  • 项目:本地 Git 仓库(私有项目,路径以 <WORKSPACE> 代替),远端走 SSH
  • 事发时同期有一次 git fetch --prune -- origin 因 SSH 网络缓慢持续约 25 分钟未返回(fetch 本身与故障无因果,只是拉长了用户不滚动列表的时间窗口)
  • 最近一次发生:2026-11-02 13:28(本地时间)
Steps to reproduce / 复现步骤

以下步骤依据 0.6.6 源码时序推导,并有一次真实发生的控制台日志佐证(见"日志"字段);由于回收机制是确定性定时触发,预期为稳定复现,未逐条实测:

  1. 打开任意 Git 仓库项目,打开 Git Log 面板,首屏(50 条)加载成功
  2. 保持列表不做"滚动到底部"的操作超过 120 秒(实际场景:等一次慢速 fetch、切去别的窗口)
  3. 滚动到底部,触发自动加载更早提交
  4. Git 控制台出现 Invalid Git history cursor,列表停在已加载部分,之后滚动不再自动加载
Expected behavior / 预期行为
  • 滚动加载更多在任何空闲时长后都应继续可用;分页状态因空闲过期应对用户透明(自动丢弃游标并重载第一页/当前锚点),不应把整个面板置为失败态
  • 参考 IntelliJ 的成熟做法(intellij-community 源码):Git Log 分页不在服务端维持会话状态。滚动到底时按档位(CommitCountStage(5, 100, 2000, ALL))从 HEAD 重新拉取一次短命 git log --max-count=N(GitLogProvider.readFirstBlock),在客户端与已有数据按哈希合并(VcsLogRefresherImpl + VcsLogJoiner,连接失败则升档直至全量),因此不存在游标过期问题,也没有常驻 git 进程
  • Lithe Core 的 git.historyPage 已保留无状态的 offset 兼容路径(一次性 git log --skip=N,跑完即退),客户端迁移到档位式无状态分页可以复用现有契约
Actual behavior / 实际行为
  • 滚动加载更早提交时 Git 控制台出现一条空命令记录,错误为 Invalid Git history cursor,并标注"未收到已完成的命令记录";面板进入失败态,后续滚动不再自动加载
  • 根因(对照 0.6.6 源码,rust/lithe-core/src/git/history.rs):
    1. git.historyPage 的 cursor 实际绑定一个长驻 git log 子进程会话(流式 stdout + 读线程)。为防进程/线程泄漏,会话有三种回收:空闲 120 秒 TTL(HISTORY_CURSOR_IDLE_TTL,后台 reaper 每秒扫描)、并发会话上限 8 个按 LRU 驱逐(MAX_HISTORY_SESSIONS)、显式关闭
    2. 首屏加载后用户超过 120 秒未触发翻页,会话被 reaper 回收;下一次 loadMore 携带旧 cursor 请求,Core 返回 invalid_request: Invalid Git history cursor (git-history-cursor-N)
    3. 客户端两端的失败处理都没有恢复路径:Windows 端 getGitHistoryPage 失败被吞成 null,use-git-log-controller 将面板置为 failed 且游标已清空,loadMore 之后永远直接返回;macOS 端同样仅置 gitHistoryPageFailed = true
    4. 该失败请求没有真正启动过任何 git 子进程,Git 控制台 journal 为它生成了一条 arguments: [] 的"未确认"记录,显示为空命令 + "未收到已完成的命令记录",容易误导排查方向
  • 缓解条件:任何 git 变化事件(fetch/commit 等完成)会触发面板自动 refresh 而恢复;但慢速 fetch 挂起期间恰好没有任何事件,面板就停留在失败态,看起来像"查不到 Git 记录"
  • fetch 挂起/超时不是根因:任何让用户 2 分钟不滚动的情况都会触发;SSH post-quantum 警告只是 OpenSSH 的提示性输出,与本问题无关
  • 关联:#366(大项目 Git log 加载策略)催生了流式 cursor 分页方案,本问题可视为该方案引入的副作用;#788 已由 PR #882 修复(启动时争抢写租约,根因不同)
Logs or diagnostic output / 日志或诊断输出

Git 控制台记录(项目路径已替换为 <WORKSPACE>):

13:03:01.831: [<WORKSPACE>] git -c … --no-pager -c … fetch --progress --prune -- origin
** WARNING: connection is not using a post-quantum key exchange algorithm.
** This session may be vulnerable to "store now, decrypt later" attacks.
** The server may need to be upgraded. See https://openssh.com/pq.html
13:28:42.455: [<WORKSPACE>] git
Invalid Git history cursor
git-history-cursor-40
未收到已完成的命令记录

第二条记录即失败的加载更多请求(命令为空是因为它未启动任何 git 子进程)。

Screenshots or recordings / 截图或录屏

未提供(错误以控制台文本形式完整呈现,无界面截图需要补充时可再提供)

Checklist / 提交前检查
  • I searched existing issues for duplicates. / 我已搜索现有 Issue,确认没有重复报告。
  • I removed secrets and personal data from the report. / 我已从报告中移除敏感信息和个人数据。
主要言語
TypeScript
スター
1.8k
フォーク
151
平均マージ
12時間 6分
マージ済み PR(30日)
365

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

1lck/Lithe-IDEA のほかの issue

1lck/Lithe-IDEA の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。