用命令行快速读懂一个陌生项目
今年七月我下载了一个两百多个文件的项目,想抄它的目录组织方式。一开始按老习惯从第一个文件往下读,两天基本白读——大半文件是我根本不关心的。后来我把读代码压成固定五步,全程只用命令行,一般一个多小时就能说出「它的骨架是什么、我想改的东西在哪一层」。环境是 Windows 11 加 Git Bash,搜索用 ripgrep 14.1。
我的固定五步
第一步:只读两个文件,README 和 package.json
我最早会犯的错是急着看源码。其实 README 回答「它要干什么」,清单文件回答「它怎么被跑起来」,后者价值大得多。带 package.json 的项目我只看四个字段:scripts 给入口命令,main 和 bin 给根文件,dependencies 说明骨架里有多少是别人拼的。我这个纯静态站换成直接看 index.html 和 archive.html,一眼就知道全站靠相对路径串起来,没有构建步骤。
第二步:tree 看目录,只看两层
tree -L 2 -a --dirsfirst -I 'node_modules|.git|dist'
# 想知道代码量时补一句
cloc .
目录结构是项目最强的自述。-L 2 是硬规矩:超过两层看到的就不是结构而是细节。那条 -I 把依赖和产物目录全排掉,一句省掉八成无效信息。cloc 我只看两行:文件数和注释比例,注释和代码同量级的项目通常值得细读。
第三步:用 rg 找入口,而不是猜
入口找错,后面全白读。我的做法是拿一组「一定出现在入口处」的词去搜,命中的文件按次数排,最靠前的那个基本就是:
rg -n --stats "createServer|app\.listen\(|render\(" .
# 静态页面项目的入口搜法完全不同
rg -n "<script|stylesheet" web
# 只要文件名时换成 -l
rg -l "sitemap" .
这几个参数我几乎每次带:-n 出行号方便跳过去;--stats 末尾给出匹配文件和总数,我用它判断一个词是核心概念还是打酱油;-l 只列文件名,适合先摸清范围。
第四步:顺调用链往下读,一层只读一个函数
找到入口后我不再横向看,只纵向追:入口做了什么,它调用的第一个自定义函数在哪,那个函数又调了谁。追的时候一条命令同时拿到定义和调用位置:
# 反向:这个函数被谁调用
rg -n --type-add 'web:*.{js,html}' -tw "buildIndex" .
# 正向:它在哪里定义
rg -n "function buildIndex|const buildIndex"
这里 -w 很关键,全词匹配能排掉 buildIndexForPage 这种同前缀的干扰。追到第三层我一般就停:再往下通常是工具函数,跟理解骨架没关系了。
第五步:手绘一张最小依赖图
这一步是我效率提升最大的。读的过程中我不写笔记,只在纸上画框和箭头,画完才打字存下来。像这个站的依赖图其实只有四行:
index.html ──┐
├─> assets/style.css ──> 变量 :root
blog/*.html ─┤
└─> archive.html ──> 全部条目
画完有两个直接好处:我知道改 style.css 会同时影响哪些页面,也就知道该在哪检查会不会改坏;下次再打开这个项目,靠它五分钟就能把上次的理解恢复出来。
顺手一张命令表
下面七个是我读陌生项目时反复用的,多了记不住,少了不够用:
| 命令 | 用途 | 我常加的参数 |
|---|---|---|
rg -n "关键词" . | 按内容定位在第几行 | -C 3 看上下文 |
rg -l "关键词" . | 只想知道哪些文件提到 | -g '!dist' 排产物 |
rg --stats "关键词" | 判断这个词是不是核心概念 | 配合 -c 按文件计数 |
rg -tw "函数名" | 查一个函数被谁调用 | --type-add 限定类型 |
git log --oneline -20 | 看改动集中在哪,判断哪块是活的 | -- 后接目录 |
git log --follow -- <file> | 单个文件的完整历史,含改名前 | -p 看改了什么 |
cloc . | 各类文件数量和代码量 | --exclude-dir 排依赖 |
一条经验:git log --follow 后面那个 -- 别省。文件名恰好和选项同名时,不加 -- 会被 Git 当成参数解析,报一句看不懂的错,我排查过才明白。
为什么不从第一个文件通读
通读失败的原因有三个,都很具体:文件在编辑器里的顺序和它被调用的顺序毫无关系,从第一个文件读等于按字母顺序理解一台机器;真正承载骨架的文件大概只有一两成,通读意味着用同样的精力去读剩下的边角;最要命的是,前面得到的结论往往在读到入口之后被推翻——我七月那次花两天读的,后来发现全是配置封装。
五步走完,我对一个项目的理解是「知道哪三个文件重要、其他该忽略」,而不是「我读了很多文件」。真要改东西的时候,需要的恰好是前者。
小结
这五步的共同点是把「读代码」变成「搜代码」:两个文件确定它在干什么,目录确定边界,rg 找入口,靠调用关系纵向追,最后用一张手绘图把理解固定下来。每个命令问的其实都是同一个问题——下一步该看哪里。纯静态站和带构建的项目都够用,只是第三步搜的词要换。
补一句:以上命令我都是在 Git Bash 里跑的,Windows 的 cmd 下引号和反斜杠规则不一样,直接照抄会报错。