拓冰建站拓冰建站
首页 / 资讯中心 / 正文

大型Code Review太痛苦?试试终端“分章”审查法,效率翻倍

大型 Code Review 太痛苦试试在终端里“一章一章”地看完整个变更之前在参与一个中大型项目时我最怕的不是写代码而是每周的 Code Review 环节一个 MRMerge Request动辄几十个文件、上千行改动浏览器里加载 diff 都要等半天从上往下翻还没有翻完已经忘记了前面几个文件到底改了什么。这种状态下的评审大概率只能给出“看起来没问题”这种低质量结论真正的问题反而被漏掉。后来我尝试调整工作流把大型代码变更拆成一个个“章节”直接在终端里完成审查。整个过程不再依赖浏览器的长页面滚动也没有来回切换文件的拉扯感审查效率和准确率都提升了很多。今天这篇教程就完整分享一下这套基于终端的“分章审查”思路以及如何从零实现一个小工具帮你把大型变更变成一段段可以消化的内容。适合读者经常需要评审大型 PR / MR 的后端开发、前端开发、测试工程师。对 Git、Terminal、命令行工具感兴趣的开发者。想用 LLM大语言模型辅助 Code Review又不希望离开终端环境的人。读完本文你将掌握大型 Code Review 效率低下的原因分析。终端审查的独特价值与适用场景。如何提取 git 变更、拆分成可独立审查的“章节”。如何写一个简单的终端审查工具并接入 AI 辅助分析。常见的报错排查思路与工程实践建议。1. 背景大型 Code Review 为什么这么痛苦1.1 大型代码变更的认知负担先思考一个很常见的问题一个 2000 行改动的 PR和 5 个 400 行改动的 PR哪个更好审直觉上答案很清晰5 个 400 行的 PR 更好审。原因在于人的工作记忆容量是有限的。心理学中经典的“7±2 法则”告诉我们人类同时处理的信息组块是有限的而大型 diff 会把你的工作记忆占满导致你无法同时记住“这个函数最初是什么样子”“中间第 3 个文件改了什么”“第 8 个文件的改动和开头的设计是否一致”。具体来说大型 Code Review 通常面临三个问题上下文丢失当你在浏览器审查时需要反复记住之前看过的内容。改动的文件越多上下文切换越频繁丢失概率越高。注意力稀释大型 diff 中往往夹杂着格式化改动、重命名、依赖版本变化等噪音真正的业务逻辑改动被淹没评审人容易陷入“逐行检查”但抓不住重点。评审疲态Review Fatigue一次性阅读超过 400 行代码变更后大脑开始疲劳后续审查质量明显下降。这也是很多团队把 review 时间拉得越来越长的原因——不是不想快点结束而是真的看不完。1.2 为什么需要“一次一个章节”地审查这里说的“章节”可以理解为一组逻辑上相关的变更块。它可以是一个功能模块涉及的所有文件改动。按业务语义分组的提交commit。按文件或 hunk 拆分的最小审查单元。把大型变更拆成章节本质上是把“一个大任务”变成“多个小任务”降低每一次审查的认知负荷。每看一个章节你只关注这一个完整的小逻辑变化看完后做一次结论通过/需要修改/不通过再进入下一章节。这种模式类似读书你不会一次性把整本小说塞进脑子而是按章节阅读、消化、暂停。代码审查也一样章节化之后你能记住每个部分在做什么也更容易发现跨文件的逻辑一致性问题。1.3 终端为什么适合做代码审查有人可能会问GitHub/GitLab 上已经有评论系统、文件树、讨论线程为什么还要在终端里做我的体验是终端审查有几个无法替代的优势轻量高效不需要等待浏览器渲染大量交互组件一个git diff命令直接输出纯文本速度极快尤其适合远程服务器、SSH 开发环境。离 Git 更近终端里可以直接运行测试、编译、静态检查命令看完一段代码马上验证不需要切换到另一个窗口。适合自动化终端的输出天然是文本适合脚本处理、管道处理pipe。把 diff 传给 AI、统计改动量、过滤噪音都可以用标准工具链完成。专注度高浏览器里有标签页、即时通讯、邮件提醒审查过程很容易被打断。终端全屏状态下反而更容易保持沉浸。值得注意的是终端审查并不排斥浏览器审查。实践中更常见的做法是先用终端快速走查一遍逻辑标记可疑点再回到 MR 页面针对具体位置评论。两者互补终端负责“读”浏览器负责“写评论和协作”。2. 环境准备与版本说明2.1 运行环境本文以 Linux / macOS 环境为例Windows 用户可以使用 WSL 2 或 Git Bash 获得接近 Unix 的体验。示例工具使用 Python 编写Python 3 是必须的运行环境。必要工具清单工具用途说明Git版本控制本文要求已初始化仓库并存在目标分支Python 3运行示例脚本建议 3.8 及以上版本pip安装 Python 依赖如果使用虚拟环境需要额外安装虚拟环境工具curl测试接口可选用于验证 AI 接口连通性Terminal执行命令macOS 用 Terminal/iTerm2Linux 用系统自带终端Windows 用 WSL版本需要根据你的项目实际情况调整本文示例以常见环境为例重点演示配置思路。核心逻辑不依赖特定 Git 版本只要支持git diff和git log即可。2.2 安装依赖示例工具需要调用 OpenAI 兼容的 API。这里先安装必需的 Python 依赖pip install requests如果你不希望污染全局 Python 环境可以用虚拟环境隔离python3 -m venv review-env source review-env/bin/activate # Windows 下执行 review-env\Scripts\activate pip install requests安装完成后创建一个工作目录用于存放后续的脚本和配置mkdir -p code-review-tool cd code-review-tool2.3 环境变量与 API Key调用 LLM 需要一个 API Key。常见做法是通过环境变量配置避免硬编码在代码中export OPENAI_API_KEYsk-xxxxxxxxxxxxxxxx export OPENAI_BASE_URLhttps://api.openai.com/v1如果你使用的是国内云厂商提供的兼容接口或者企业内部的推理服务只需调整OPENAI_BASE_URL即可。这里不限定具体厂商保持接口兼容即可。安全提示千万不要把 API Key 提交到 Git 仓库。建议在项目根目录添加.gitignore把环境文件或配置文件排除在外。3. 核心原理拆解把大型变更拆成“章节”3.1 理解 diff、patch 与变更块Git 中diff是表示代码变更的核心数据格式。每段差异由多个部分组成文件头file header形如diff --git a/src/main.py b/src/main.py表示变更涉及的文件。hunk 头hunk header形如 -10,6 10,7 表示原文件从第 10 行开始、共 6 行新文件从第 10 行开始、共 7 行。变更内容行以-开头表示删除的行以开头表示新增的行以空格开头表示上下文行。一个 hunk 是 diff 中的最小独立单元。如果你的变更很大一个文件可能有多个 hunk它们分布在不同位置。git diff --unified3--unified3参数控制上下文行数为 3这能让 AI 或人类评审者看到更多改动上下文但又不会太多导致噪音。3.2 如何划分“章节”“章节”的划分方式有很多种常见策略如下划分方式说明适用场景按文件划分每个文件当作一个章节文件数量少但单文件很大时不太合适按 hunk 划分每个 hunk 当作一个章节适合快速从 diff 中定位小改动按 commit 划分每个 commit 当作一个章节前提是开发者在提交时已经按逻辑提交而不是一次提交所有改动按目录 / 模块划分相同模块下的文件合并为一章适合大型项目模块边界清晰的情况按语义划分根据代码上下文把相关的多个改动合并成“功能章节”最灵活也最难自动化通常需要人工或 LLM 参与在简单工具中最稳妥的方式是“按文件 按 hunk”两级拆分先用git diff拿到全量变更。解析 diff 格式按文件分块。如果单个文件改动超过一定行数例如 100 行再按 hunk 拆分成子章节。拆分之后每个章节都带上文件路径、起始行号、变更内容方便后续逐章处理。3.3 在终端中展示审查上下文终端不是浏览器交互方式受限但也有自己的展示优势。可以使用 ANSI 颜色高亮新增行和删除行使用less或fzf等工具实现文本分页和搜索。例如用less查看 diffgit diff --coloralways | less -R-R参数让 less 保留颜色转义字符。如果你希望交互式选择文件可以使用 fzfgit diff --name-only | fzf选中文件后再单独查看该文件的 diff。这样配合起来就能在一定程度上实现“按章节浏览”。4. 完整实战终端分章审查工具的实现下面我们实现一个简化但可用的终端审查工具核心功能是读取当前工作区的变更。把变更按文件拆分。对每个文件单独调用 LLM 分析。在终端中显示分析结果。支持人工标记“下一章/跳过/退出”。4.1 创建项目结构code-review-tool/ ├── review.py ├── requirements.txt └── README.md先用touch创建文件touch review.py requirements.txt README.mdrequirements.txt里声明依赖requests4.2 提取代码变更在review.py中第一步是调用 Git 命令获取 diff。使用subprocess模块注意处理返回状态和编码。# 文件路径code-review-tool/review.py import subprocess def get_diff() - str: 获取当前工作区相对 HEAD 的全部变更内容。 result subprocess.run( [git, diff, HEAD, --unified3], capture_outputTrue, textTrue, encodingutf-8, ) if result.returncode ! 0: raise RuntimeError(fgit diff 执行失败: {result.stderr}) return result.stdout这里说明一下git diff HEAD对比的是当前工作区与 HEAD 的差异包含已暂存和未暂存的内容。如果你只想审查某两个分支之间的差异可以换成git diff main...feature-branch4.3 解析 diff 并按文件拆分解析 diff 文件最保险的方式是使用现成库例如unidiff但为了减少依赖我们先手动实现一个简单的解析函数。# 文件路径code-review-tool/review.py import re def split_diff_by_file(diff_text: str) - list[dict]: 把 diff 按文件拆分成多个章节。 返回格式: [ { file: src/main.py, content: diff --git a/src/main.py b/src/main.py\\n..., }, ] chapters [] current_file None current_lines [] for line in diff_text.splitlines(): if line.startswith(diff --git ): if current_file and current_lines: chapters.append({ file: current_file, content: \n.join(current_lines), }) match re.search(rdiff --git a/(.) b/(.), line) if match: current_file match.group(2) else: current_file unknown current_lines [line] else: if current_lines is not None: current_lines.append(line) if current_file and current_lines: chapters.append({ file: current_file, content: \n.join(current_lines), }) return chapters这个解析逻辑简单直接遇到diff --git行就开启新文件章节其余行追加到当前章节。在实际项目中你可以改成调用unidiff库能更稳妥地处理重命名、新增文件等边界情况。4.4 调用 LLM 分析变更拿到章节内容后就可以调用 LLM 生成审查意见。这里使用 OpenAI 兼容接口通过环境变量读取 Key。# 文件路径code-review-tool/review.py import os import requests def review_with_llm(file_path: str, diff_content: str) - str: 调用 LLM 审查单个文件的 diff。 api_key os.environ.get(OPENAI_API_KEY) base_url os.environ.get(OPENAI_BASE_URL, https://api.openai.com/v1) if not api_key: return 未配置 OPENAI_API_KEY跳过 AI 分析。 system_prompt ( 你是一名资深代码评审专家。请根据提供的 git diff 内容进行审查 重点关注1) 逻辑错误 2) 安全隐患 3) 性能问题 4) 可读性与命名规范 5) 缺少测试的边界场景。 请用中文输出每条问题附带严重程度高/中/低和建议改进方案。 如果变更没有明显问题请简洁地说明。 ) user_prompt f文件路径: {file_path}\n\ndiff\n{diff_content}\n resp requests.post( f{base_url}/chat/completions, headers{ Authorization: fBearer {api_key}, Content-Type: application/json, }, json{ model: gpt-4o-mini, messages: [ {role: system, content: system_prompt}, {role: user, content: user_prompt}, ], temperature: 0.2, }, timeout60, ) if resp.status_code ! 200: return f调用 LLM 失败HTTP {resp.status_code}: {resp.text[:200]} data resp.json() return data[choices][0][message][content]模型名称根据实际可用资源调整不一定使用gpt-4o-mini。这里采用 OpenAI 兼容格式很多国内模型服务也支持这种格式只需修改OPENAI_BASE_URL。4.5 终端交互主流程主流程的目标是“一章一章”地审查。每次显示一个章节询问用户是继续、跳过还是退出。# 文件路径code-review-tool/review.py def main(): diff_text get_diff() if not diff_text.strip(): print(没有检测到代码变更。) return chapters split_diff_by_file(diff_text) print(f共发现 {len(chapters)} 个变更文件开始逐章审查。\n) total_issues 0 for idx, chapter in enumerate(chapters, start1): print(f\n{*60}) print(f[章节 {idx}/{len(chapters)}] 文件: {chapter[file]}) print(f{*60}) # 先展示变更内容 print(\n--- 变更内容前 80 行---) diff_lines chapter[content].splitlines() preview_lines diff_lines[:80] print(\n.join(preview_lines)) if len(diff_lines) 80: print(f... 还有 {len(diff_lines) - 80} 行变更未显示) # 调用 LLM 分析 print(\n--- AI 审查意见 ---) review_result review_with_llm(chapter[file], chapter[content]) print(review_result) # 人工决定是否继续 while True: choice input(\n下一步 [n下一章, s跳过, q退出]: ).strip().lower() if choice in (n, next, ): break elif choice in (s, skip): print(已跳过当前章节。) break elif choice in (q, quit): print(审查结束。) return else: print(无效输入请输入 n / s / q。) print(\n全部章节审查完成。) print(f共审查 {len(chapters)} 个文件。) if total_issues: print(f估计问题数量{total_issues}) if __name__ __main__: main()这里total_issues变量目前只是一个占位实际项目中可以由 AI 返回的文本中提取问题数量或者由用户在人工确认后手动标记。4.6 运行与验证给脚本添加可执行权限后运行chmod x review.py python3 review.py预期输出大致如下共发现 3 个变更文件开始逐章审查。 [章节 1/3] 文件: src/utils/format.py --- 变更内容前 80 行--- diff --git a/src/utils/format.py b/src/utils/format.py index 1234567..89abcde 100644 --- a/src/utils/format.py b/src/utils/format.py -10,6 10,8 def format_number(value): if value is None: return 0 if value 0: return f({abs(value)}) return str(value) --- AI 审查意见 --- - [中] 当传入负数时返回格式为 (10)但调用方其他地方可能期望纯数字字符串建议搜索所有调用点确认格式约定。 - [低] 新增逻辑没有单元测试建议添加负数场景用例。 下一步 [n下一章, s跳过, q退出]: n这套工具虽然简单但已经具备了“分章审查”的核心能力。你可以把它看作一个最小可运行版本后续可以扩展很多功能例如支持按 hunk 拆分超大文件。使用rich库美化终端输出。把审查结果导出为 Markdown 报告。接入评论 API直接把问题发回 MR。下面是扩展后的实现思路片段使用rich高亮pip install richfrom rich.console import Console from rich.table import Table console Console() def print_summary(chapters: list[dict], verdicts: list[str]): table Table(title审查汇总) table.add_column(文件) table.add_column(结论) for ch, verdict in zip(chapters, verdicts): table.add_row(ch[file], verdict) console.print(table)5. 常见问题与排查思路在终端审查工具的使用过程中比较容易踩到下面几个问题整理成排查表供参考。问题现象常见原因解决思路git diff没有输出误以为当前目录不是 Git 仓库或工作区干净先执行git status确认仓库状态再确认是否在仓库根目录执行命令输出乱码终端编码不是 UTF-8或 diff 包含二进制文件设置export LANGen_US.UTF-8文本文件可执行git config core.quotepath false解析 diff 时漏掉文件简单的split_diff_by_file未处理重命名、新文件头部改用unidiff库解析或增加对rename to、new file mode的兼容判断API 调用超时网络不通、代理配置异常或模型响应过长先执行curl $OPENAI_BASE_URL/chat/completions测试连通性增大timeout参数确认 API Key 有效模型返回内容不可读temperature 过高导致输出发散提示词不清晰把temperature降低到 0.2 左右用系统提示词固定输出格式大文件 diff 太长单文件几十 MB或 diff 包含生成代码增加文件大小上限超过阈值时只分析前 N 行或跳过该文件并提示人工审查Windows 终端运行报错Python 路径或 shell 语法差异在 WSL 2 中运行或使用python代替python3视环境而定排查顺序建议先跑最小命令例如git diff HEAD | head -50确认 Git 输出正常。再跑python3 review.py观察脚本是否能读到 diff。如果 AI 分析失败单独用curl测试接口排除网络和 Key 问题。如果解析异常把diff内容保存到文件用测试脚本单独解析。6. 审查效率与工程最佳实践6.1 提交历史与 MR/PR 拆分工具只能辅助审查代码是否好审很大程度取决于开发者在提交阶段是否做了合理的拆分。这里给项目团队几条实际建议每个 commit 只做一件事一个 commit 尽量对应一个逻辑变更例如“修复登录接口的空指针”“新增订单导出功能”。不要把格式化、重构、业务改动混在一起。MR/PR 控制在可评审范围单次 MR 的代码变更尽量控制在 400 行以内。超过这个规模建议先合并父任务的分支分多次评审。用提交信息辅助审查者提交信息里写清楚“是什么”和“为什么”比代码注释更能帮助审查者快速进入状态。6.2 审查清单化人工审查时最怕的是凭感觉、抓到什么看什么。建议给自己准备一份固定的审查清单例如[ ] 本次变更是为了修复还是新增功能改动与描述一致吗[ ] 有没有改动公共接口却未更新调用方[ ] 边界条件是否覆盖空值、超长字符串、非法输入、并发场景[ ] 数据持久化是否有事务保证异常回滚是否安全[ ] 是否有日志输出日志中会不会泄露敏感信息[ ] 测试是否覆盖新增或修改逻辑[ ] 是否有循环依赖、重复代码、不合理的耦合当审查对象很大时把清单与章节结合每个章节至少核对三条与本章相关的条目避免遗漏。6.3 自动化与人工结合AI 辅助审查也不能完全替代人工。目前的 LLM 在单文件、小范围的逻辑审查上表现不错但在跨文件影响面、团队代码规范、历史上下文、架构约束等方面仍然存在盲区。建议的分层策略是静态扫描优先使用 ESLint、SonarQube、PyLint 等工具先扫一遍语法和常见问题。LLM 辅助初筛用终端工具按章节浏览先让 AI 给出初步意见。人工重点复核AI 标出的中/高风险问题必须人工确认AI 没有提示但改动密集的关键业务逻辑也要人工看一遍。评论归档把确认的问题以评论形式发回 MR保证有迹可循。6.4 安全与权限边界如果审查工具运行在 CI 或服务器上需要注意几个问题最小权限原则工具只需要读取代码的权限不要给整个仓库的写入权限。API Key 管理不要把密钥写入配置文件优先使用环境变量或密钥管理服务如 Vault、云厂商的 Secrets Manager。敏感信息过滤diff 中可能包含数据库连接串、密码、Token。在发送给 LLM 之前建议先扫描并替换敏感字段。生产环境变更如果审查的代码涉及生产数据库结构的变更切勿直接在测试环境或生产环境执行DROP、TRUNCATE、UPDATE一类高危 SQL。所有变更先在小范围测试环境验证并做好备份与回滚方案。6.5 性能优化当项目仓库历史庞大时需要注意终端审查的性能避免每次执行都拉取全仓库 diff用git diff HEAD~1或指定分支范围。大文件的 diff 生成可能较慢可以先git diff --stat查看变更统计再决定是否查看详情。若在 CI 中批量审查可以把章节分发给多个 worker并行调用 LLM缩短总耗时。7. 总结与下一步学习建议这套“终端分章审查”方案核心并不是某个具体工具而是一种审查思路把大型代码变更拆成可独立消化的小单元降低认知负荷再用终端和 AI 辅助提高效率。实现一个最小工具只需要几十行 Python但它带来的工作流变化是巨大的。值得继续深入的方向学习 Git 的高级 diff 和 patch 操作比如git apply、git format-patch、git log -p把终端审查和日常开发组合得更顺滑。研究 unidiff 等 diff 解析库把工具做得更健壮支持重命名、二进制文件、子模块等场景。把 LLM 审查看作一个“初筛助手”用提示词工程让输出更贴合团队规范例如自定义输出 JSON 结构方便程序化处理。把审查工具接入 Git Hook 或 CI 流程实现提交前自动检查把问题拦截在更早阶段。如果你想系统化提升 Code Review 技能可以从“如何写可评审的 MR 描述”“如何高效回复 review 意见”“如何做安全专项审查”这几个方向逐一学习。最后想提醒的是无论工具多方便Code Review 的核心仍然是“人”。终端能让你更快地读完代码AI 能帮你找到容易忽略的问题但最终决定代码是否合并、是否重构、是否补测试的还是你的判断力。把这些工具当作放大注意力的杠杆而不是替代思考的捷径才能长期受益。如果你在实际使用中踩到了不同的坑或者有其他好用的终端审查技巧欢迎在评论区分享。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门