git-annex 的维护者上个月花了大概 100 个小时,只为了一件事:让这个项目能在一个不含 LLM 生成代码的依赖树里构建起来。100 个小时。我读到这条记录的时候,第一反应是——审查依赖树,到底累在哪?
他列出来的几件事,搁一起看特别有意思。一条提交信息写了 1489 行,对应的改动大概一万行,整个代码库才两万六千行。一段 LLM 生成的改动,在下一版本里被无解释地回退掉了。还有一条 prompt 让模型去别的项目复制代码——要不是运气好,这已经构成版权侵权了。
这些问题的共同点,其实不是"AI 写代码烂"。AI 写出的烂代码,跟人写出的烂代码一样,都好修。真正的共同点是:"为什么"不见了。一万行改动,提交信息不解释为什么;一段改动被回退,没人说明为什么;一条 prompt 让模型抄代码,没人问过为什么不能抄。
与其在这儿复述他的遭遇,不如我们搓一个小工具,亲手摸一下"为什么没了"长什么样。我们先来搓个最简版的:扫一遍你仓库的提交历史,把提交信息长得离谱的挑出来。
import subprocess
raw = subprocess.run(
["git", "log", "-100", "--pretty=format:%H|%s|%b|====="],
capture_output=True, text=True
).stdout
for block in raw.split("|====="):
parts = block.strip().split("|", 2)
if len(parts) < 2:
continue
h, subject = parts[0][:8], parts[1]
body = parts[2] if len(parts) > 2 else ""
# 这一行干这件事:把提交信息超过 10 行的拎出来
if len(body.splitlines()) > 10:
print(f"{h} 提交信息 {len(body.splitlines())} 行 {subject[:40]}")
跑一下,看看出来啥。你自己的仓库里可能一条都扫不出来,也可能扫出一两条几十行的。git-annex 那边扫出来的记录是一条 1489 行的提交信息——它对应的改动加起来约一万行,整个仓库才两万六千行。提交信息写成这样,读完了你也不知道它到底想干嘛。
这版糙得很:只按行数扫,不按内容扫。但不能怪它——"超长提交信息"本就是一个信号,背后通常是两种情况:要么改的东西太多、作者懒得逐条解释;要么作者根本没有解释的能力。无论哪种,审查者都得先把这一万行读了,才知道问题在哪。
接下来搓第二版:扫死代码。"无解释回退"的本质,就是上一版还存在的逻辑,这一版被删了,没人告诉你它当初为什么要存在。全自动扫回退我们后面再说;先搓一个能标记"条件可疑"的:
import ast
def scan(path):
tree = ast.parse(open(path).read())
for node in ast.walk(tree):
if isinstance(node, ast.If):
cond = {n.id for n in ast.walk(node.test) if isinstance(n, ast.Name)}
used = {n.id for n in ast.walk(node.body) if isinstance(n, ast.Name)}
if cond and not (cond & used):
print(f"{path}:{node.lineno} if 条件里的变量在分支里从没被用过")
scan("some_module.py") # 换成你自己的文件再跑
跑一下。你大概率会看到一屏输出,但仔细一查,大半是误报——if self.debug: 这种,条件变量不出现太正常了。这说明什么?说明"死代码"这个词,语义上比"条件变量没被用到"宽得多,宽到这种启发式只能标出"可疑",标不出"确定"。而人审查的时候,得在这一堆误报里挑出真正有问题的几条。100 个小时,就是这么烧掉的。
第三件事,无解释回退。这个我试过写成脚本——对比两个版本,把上一版存在、这一版被删的行拎出来。写到一半停手了。因为"回退"要论语义,行级 diff 只能告诉你"这几行没了",回答不了"为什么没了"。而"为什么"恰恰是被吞掉的那一层。
所以你看,搓完这两个小工具,我们摸着的东西是:代码层能自动化的——超长提交信息、可疑死代码——都便宜,几十行 Python 的事。真正贵的是"为什么"那一层。那一层不在代码里,在提交信息里、在 review 记录里、在人的脑子里。LLM 生成代码之所以让审查变得这么累,不是因为它写错了多少逻辑,而是它生成的时候,脑子里没有"为什么"这个东西。于是审查者就得替它把这一层补上。
我特别记得他举的一个例子:有人用"Add fourmolu config and restyled neat format a module"这种 prompt 生成了一坨改动提交上去,自称高效开发者——这个项目从此再也没有收到过他的后续提交。高效。对,高效地消耗掉了自己的信用。
那位维护者说,这 100 个小时唯一的好处,是摸清了自己这棵依赖树的成色,以后做决定心里有数。他也承认,自己可能就是在挡趋势——Software Freedom Conservancy 都把这事放弃了,FSF 他也没抱太大希望。但他还在干活,还在支持用户。我懂他为什么接着干:"为什么"这层要是没人管,就真的没人管了。
这版工具只是用来懂的,不是用来跑真活的。生产里请用你自己攒的评审流程和提交规范——工具永远只能标出可疑,"为什么"这层,工具死了也顶不了。
