返回博客

功能明明「以前有」,现在代码里找不到——用 git pickaxe 反查被静默删除的历史

用户反馈:"搜索历史记录这个功能以前有的,现在怎么没了?"

我第一反应是直接 grep 关键词——结果全仓库 0 命中。git log --grep "搜索历史" 也只有一条不相关的 PR 描述。难道是用户记错了?仔细一想不对:如果从来没有过,CSS 文件里不会留着 .search-history-item.search-section-clear 这几个孤立的 class。

这是典型的「半删」——功能被顺手埋进某次 UI 整理 commit,commit message 完全没提,但后端 API 和样式没来得及清理干净。

现象

  • 当前代码 grep 功能关键字段(方法名、storage key、文案):0 命中
  • git log --grep "关键词" 搜 commit message:0 命中
  • 但能看到「半身残留」:CSS 里还有对应的 class,后端 API 定义文件里还有接口声明

这三条加在一起就可以确认:功能曾经存在,且被不完整地删掉了。

根因

git log --grep 只搜索 commit message 文本,而功能删除往往发生在泛化描述的 UI 整理类 commit 里,比如 fix(ui): refine scrolling and page interactions——作者自己可能都没意识到顺手删掉了一整块 feature。

坑:commit message 和实际内容严重脱节

「删了搜索历史功能」的那个 commit,它的 message 是 fix(ui): refine scrolling and page interactions。你永远不可能用 git log --grep "搜索历史" 找到它。

更糟的是,如果此时选择「凭经验重新实现」,字段名、方法签名、后端接口约定必然发生漂移,埋下未来的兼容 bug——而后端其实根本没动,接口还活着。

正解

第一步:用 pickaxe 精确定位「把功能删掉的 commit」

git log -S 是 git 的 pickaxe 模式,它不搜 message,而是搜 diff 内容:只列出某个字符串在 diff 中「出现过或消失过」的 commit。

# 全仓库搜,找到哪个 commit 改动了包含该符号的文件
git log --all --oneline -S "searchHistory"
 
# 限定目录,加速搜索
git log --all --oneline -S "searchHistory" -- pages/home/
 
# 直接看 diff,确认是哪次 commit 删的(- 侧是被删内容)
git log --all -p -S "addSearchHistory" -- pages/home/maps.js

关键字选择原则:选最独特的符号(storage key、自定义方法名、独特 API path),避免 searchhistory 这类太泛的词误伤大量不相关 commit。

命中最新的那个 commit 通常就是「删除方」,用 git show <sha> --stat 验证改了哪些文件,用 git show <sha> -- <path> 看具体 diff 的 - 侧确认。

第二步:三路交叉验证「曾经存在 + 未彻底下线」

找到 commit 之后,再横向确认残留情况:

| 层 | 检查命令 | 意义 | |---|---|---| | 后端 API | grep -n "<endpoint>" <api-client-file> | 接口还在 → 直接复用,无需重写后端 | | CSS/WXSS | grep -n "\.<class>" <css-file> | 样式还在 → 恢复 WXML 后立即生效 | | i18n/文案 | grep -n "<text>" <locale-file> | 文案还在 → 产品未明确下线 |

三路都有残留 = 确认「半删」,可安全恢复;若后端/DB 已清理 = 重建工作量大,先和产品重新对齐需求。

第三步:从历史快照拉「删除前源码」

不要凭记忆重写,直接从删除前的父提交拉快照:

# <sha>^ 表示该 commit 的父提交,即删除前的最后一个版本
git show <sha>^:pages/home/maps.js   > /tmp/maps_before.js
git show <sha>^:pages/home/maps.wxml > /tmp/maps_before.wxml

拿到快照后,以它为唯一事实源做恢复:

  • 原样抄函数体,不重构、不简化、不加 log
  • 字段命名、调用签名、data flow 一字不改
  • 如有新增需求(如「有缓存时优先缓存,无缓存时展示历史」),在复原基础上增量追加,不要和复原逻辑混写成「重新设计」
正解:pickaxe + 三路交叉 + 快照复原
  1. git log -S "<最独特符号>" 找到删除方 commit(10 分钟内命中)
  2. API / CSS / i18n 三路验证残留层,判断恢复工作量
  3. git show <sha>^:<path> 拉删除前快照作为唯一实现参考
  4. 原样复原 + 增量追加,杜绝签名漂移
半删 commit 也是技术债

本次排查顺手发现:后端 API 定义文件里留了 4 个「死接口」声明,CSS 里留了 5 个「死 class」——这些是上次不彻底删除留下的技术债。如果不顺手记录,下次再有人误删会重复踩同一个坑。

一句话外卖

git log --grep 搜 message,git log -S 搜内容——功能被静默删除时,只有 pickaxe 能找到真正的祸首 commit。