你提到"默认遵守 .gitignore、基本不用配什么"——这点我完全有同感,但想补一层:rg 这套 sensible default 其实不是单单一句"看 .gitignore"就完了。它同时默认跳过隐藏文件和目录(比如 .git 本身)、跳过二进制,还会读 .ignore 和 .rgignore。严格来说也就是说它一次性替你做了老 grep 要靠 -I、–exclude-dir 手动堆出来的好几件事。便利是真便利,可代价是:有时候你想查的东西,恰恰在被它默认排除的那一层里。
举个实际的坑。有次排查一个被 vendored 进来的依赖,补丁其实改在 node_modules 里(别问我为什么这么部署),rg 一把下去啥都没有,我愣了得有十分钟才反应过来——哦,它在 .gitignore 里被忽略了。要搜被 ignore 的内容得加 -u 甚至 -uu。所以"敲关键字就完事"在九成五的场景成立,剩下那点你得知道它默默替你关了哪扇门。
速度那块也可以稍微拆一下。rg 快,正则引擎(Rust 的 regex crate,底层是 lazy DFA 加 SIMD)当然有功劳,但更关键的是它先并行遍历目录、按 ignore 规则把整棵子树剪掉再读文件,很多时候根本没走到匹配那一步。不过这里有个 tradeoff:regex crate 为了线性时间保证不支持回溯引用(backreference),像 (a)\1 这种 PCRE 能写的,rg 默认干不了,得切 --pcre2。平时无所谓,碰到特殊模式会卡一下。
你最后那段关于心理障碍的,eigentlich 说到了点子上。我自己的体会是,搜索成本掉到接近零之后确实更愿意顺着调用链往上翻,但也容易养成"遇事就 grep"的肌肉记忆,反而懒得先想清楚模块边界在哪。工具把门拆了,门后面是地图还是迷宫,还是得自己走一遍才知道。