开工前先对基线律
首次记录:2026-08-02 来源:LiveLink 迭代 —— 在落后 origin 13 个提交的旧检出上开发了整轮, 发布前才发现,差点用一个「修复版」覆盖掉 13 个提交的全部功能 状态:⭐⭐⭐ 三次验证 · 铁律 —— 前两次同日同会话(见下);第三次在 2026-08-21,且是新形态: 不是「在旧检出上开发」,而是拿陈旧的 ref 去做风险判断。站点仓库
git status显示ahead 44,我据此给出「44 个提交、三周工作会一起上线,其中 6 个会重启线上后端服务」的评估,并按这个等级设计了整套绕行方案;git fetch之后真正没推的只有 2 个。 前两次的代价是「白干」,这一次的代价是「判断错」——陈旧的 ahead/behind 不只误导你的工作量估计,它会直接污染你给别人的风险结论。 新增动作:git status的 ahead/behind 在git fetch之前不作数,凡是要拿它下结论(尤其是风险结论)的场合,先 fetch。 见 2026-08-21_一小时分享会_从设计到投影现场_全链路复盘_v1
一句话
动第一行代码之前先对基线,别把这个检查留到发布前。
git fetch + 比对本地与远端的领先/落后数,是开工动作,不是收尾动作。
事故形态
本地 main 停在 v1.2.0,线上早已是 v1.4.1 —— 中间隔着 13 个提交
(宠物系统、AI 回复、overlay 主题、赛马押注、装修预览)。
我在这个旧检出上完成了整轮开发:改代码、跑测试、写发布说明、 把版本号定成 1.2.1。如果直接发布,这个「修复版」会把那 13 个提交的功能全部抹掉。
没出事只是因为发布前习惯性查了一下远端。这是侥幸,不是流程。
第二次(同一天,知识库仓库):落后的检出让我「搜不到」本该用的 skill
写完上面这条律之后不到一小时,同一个会话里又栽了一次 —— 这次是知识库仓库。
作者说「更新报告有专门的 skill,从知识库中找」。我把 07_skill存档/(20 个 skill)、
SKILL_INDEX.md、部署手册、~/.claude/skills/、两处项目级 .agent/skills/ 全翻了一遍,
又全库 grep 了「更新报告 / 版本更新图 / 发版报告 / 迭代报告」—— 零命中,
于是我向作者报告「库里没有这个 skill」,还列出了候选让他选。
真相:本地知识库检出落后 origin 14 个提交,而 report-longimage skill 正是在
其中一个提交里(20e5b84 新Skill: opportunity-due-diligence + report-longimage)。
git fetch 之后一秒就找到了。
这次的形态比第一次更阴:第一次是「我改的东西会覆盖别人的」,看得见后果; 这次是「我搜不到的东西,我报告成不存在」—— 一次穷尽式搜索 + 零命中,读起来像强证据,实际只是检出旧。 代价:白做了一版不合规的长图(自搭深色版式 + 自写渲染脚本), 还差点让作者以为自己记错了。
推论:grep / find 搜不到,不等于不存在 —— 先确认索引(检出)是新的。
在 git 仓库里做「全库搜索」之前,git fetch 是和 grep 同等必要的一步。
第三次(2026-08-10,pb-arena 仓库):搜索工具的默认范围限制让我「搜不到」
按 feishu-doc-publish skill 的指引,「主力机用 Glob 找 **/tools/feishu-doc-sync/sync.mjs」。我跑 Glob——零命中,接着在 E:\vacat-2026 工作区、~/.workbuddy/skills/、C:\Users\Administrator\ 几个常见位置都搜了一遍——全库穷尽搜索零命中,差点要按 skill 兜底条款向用户要 App ID/Secret 重建配置。
真相:pb-arena 仓库在 E:\pb-arena(E 盘根目录下、不在任何当前工作区下),用 find /e -name sync.mjs -path '*feishu*' 一秒命中。Glob 工具的默认搜索范围不带 E 盘根目录这一层,而 feishu-doc-publish skill 里那句”用 Glob 找”是按惯例写的指引,没考虑工具默认范围的边界。
这次的形态比第二次还阴一层:第二次是「检出版本旧,内容真的不存在于本地」(根因在自己),这次是「工具默认范围看不见,内容真的存在但工具看不见」(根因在工具)。两次的”现象”一样——穷尽搜索 + 零命中;判据不一样——第二次 git fetch 后再搜能命中,这次 git fetch 后还是搜不到,因为根本不是 git 检出问题。
推论升级:grep / find / Glob 搜不到,不等于不存在 —— 先确认「索引是新的」+「搜索范围覆盖到了目标位置」。 两个判据都要满足。单一穷尽搜索 + 零命中读起来像强证据,但在跨盘符、跨工作区、跨工具的 Windows 工作环境里,搜索工具的默认范围限制可能恰好不覆盖你要找的位置。
同一天的姊妹教训:Windows下编码与DPI的所见非真相 第六次形态——Bash 的
ls能看见文件,但 Node 解析同一路径会报MODULE_NOT_FOUND,因为 MSYS 路径转换层污染了传给 Node 的路径。两次都是「Bash 自己处理路径时按 POSIX 规则做兼容,但传给非 Bash 程序时路径会被改写」,根因不一样(Bash 兼容性 vs 工具默认范围),现象都是「搜不到≠不存在」。
为什么这个坑特别隐蔽
- 本地一切正常:代码能跑、测试全过、build 成功 —— 没有任何信号提示你基线是旧的。
- 版本号会撒谎:
package.json写着 1.2.0,你自然按 1.2.1 递增, 完全想不到线上已经 1.4.1。 - 越是”直接开干”越危险:需求描述得越具体(“修 X bug”),越容易跳过环境确认直接进代码。
- 多机 / 多 worktree / 多 agent 并行时,本地落后是常态而非异常。
操作规则
- 凡是要在 git 仓库里做「全库搜索」并据此下结论(尤其是「库里没有 X」这种否定结论),
先
git fetch再搜。 搜不到 ≠ 不存在,很可能只是检出旧。 - 开工第一条命令(在读任何业务代码之前):
git fetch origin
git rev-list --left-right --count origin/main...main # 左=远端独有 右=本地独有
git log --oneline main..origin/main # 落后了哪些
- 左边不为 0 → 先决定怎么处理再动手:能快进就快进,不能就明确说明”本次基于旧基线”。
- 版本号一律以远端最新 tag / release 为准,不以本地
package.json为准。 - 若已在旧基线上做完工作:不要直接提交。先把改动存成可恢复状态(
git stash或复制文件), 快进到最新,再重新应用 —— 并逐个确认上游是否已改动同一批文件。
自动化形态(2026-08-15)
这条律可以从”自律动作”升级成”机器动作”:在仓库 .claude/settings.json 配 SessionStart hook,会话一开就自动比对本地/远程并把结果注入上下文。
关键:hook 里用 git ls-remote,不用 git fetch。 素材型大仓库 fetch 要 2 分钟起步会卡死会话启动;ls-remote 只取引用哈希,秒回。检查发现不一致时再由人决定 fetch/pull。落地实例见 忘提交的机器兜底_refs-wip快照三件套_v1(该档第三层)。
姊妹律:当”看不见”的根因在我自己写的文档里
本律的三种形态,根因都在工具或检出(索引旧 / 范围不够)——共同点是”我还在找,只是找不到”。 另有一种更隐蔽的形态:连找的动作都被省掉了,因为文档里已经写了答案。 见 约束型结论先复核律_文档写的不可能会过期_v1(2026-08-20, 一句”没有公网服务器”挡了两个月,而服务器早就部署好并跑了 23 天)。
反例 / 边界
- 明确要在历史版本上出 hotfix 时不适用 —— 但那时应该显式从对应 tag 开分支, 而不是”碰巧本地就是旧的”。
- 纯本地实验、不打算发布的探索,可以放宽。
关联文档
- 事故来源:2026-08-02_LiveLink断线重连重做与视觉系统_迭代复盘_v1
- 同族「先确认再动手」:交付前实测证伪律_v1 · 可行性生死线前置律_移植先探一票否决约束_v1
- 自动化形态:忘提交的机器兜底_refs-wip快照三件套_v1(SessionStart hook 用 ls-remote 对基线,本律的机器化)
- 视角错位的另一种形态:Claude_Code_Worktree隔离的协作陷阱(在错的工作树里 self-verify)