30 天提交 51.8 万行,生产环境只留下 23.5 万行

· 7 分钟 · engineering aigitdevopstestingrefactoring

上周我做了一件平时几乎不会做的事:数了数自己的提交。不是数我记得写过的那些,而是数仓库里真实记录下来的那些。自建 Gitea 上 5 个生产仓库、三十天、一个人:865 次 Commit、新增 518,233 行、删除 130,892 行。

然后我数了数活下来的部分。对主生产项目的最新版本跑一次干净扫描,有效代码总量是 234,976 行;同一时间窗口里净增 58,240 行的视频转码器,今天整个仓库只有 43,050 行。

那 28 万行进哪儿去了?没有丢。它们被写出来、跑过测试、被判为不对,然后删掉——或者被一个更小、做同一件事的东西替换掉。我想把这条循环记下来,因为它这一年对我工作方式的影响,比任何一次模型升级都大。

一开始我不信的这几个数字

以下是 2026 年 9 月 17 日至 10 月 17 日,名下 5 个活跃仓库的精确 Git 统计:

仓库名称30 天 Commit累计新增 (+Add)累计删除 (-Del)净变动 (Net)当前存量有效代码/文本核心技术栈
numerology-report432+331,672-98,937+232,735234,976PHP, Markdown, JSON
hevc-transcode187+58,240-15,508+42,73243,050Python, HTML, Shell
dsm-resource-management132+58,234-14,076+44,158368,793Python, TypeScript, Astro
hoelee-blog88+23,603-709+22,89455,933Astro, TypeScript, Markdown
hoelee-agent-dist26+46,484-1,662+44,822(Dist)Python, Shell, Markdown
合计865+518,233-130,892+387,341——

其中两行你可以自己复算,这就是完整的量法:

git -C numerology-report log --since=2026-09-17 --until=2026-10-17 \
  --numstat --pretty=format: | awk '{add+=$1; del+=$2} END {print add, del}'

在人类团队里,这样的更替量通常意味着出事了:需求在代码底下不停移动、有人偷偷在重写、架构反复塌陷。这几种情况我一条都不占——这 5 个仓库都是我每天在跑、离不开的东西,每一次提交都发生在能读到 diff 的会话里。

生成成本变低之后,这种更替量就是重构的样子:Agent 起草一段改动,我跑闸门,闸门不同意,这段就被丢掉或者改小重写。凡是闸门写对的那几天,代码总量往下掉得比功能上来的速度还快。

Agent 实际接手的是什么

大多数人第一次让 AI 写代码,是在一个浏览器标签页里:把函数粘进对话框,再把答案拷回编辑器。这条路的瓶颈是剪贴板,而且模型离真正重要的两样东西都很远——仓库自己的约定,以及运行它刚写出来的东西的能力。

所以我的是跑在终端里、跑在这台机器上的,手里有真工具:

  1. 文件与语法工具:直接读已有模块,用模糊匹配打补丁而不是整文件覆盖,保存前先过语法与 AST 校验。
  2. 测试与执行器:PHPUnit 单元测试、pytest 套件、无头 Chrome 探针,在前台跑起来并把输出读回来。
  3. 版本控制上下文:读 git diff、显式暂存指定路径、翻一个文件的历史看上一个决定为什么这么做。

这套组合很快,比我亲手打第一版快一个数量级;但它本身也是让代码库腐烂得更快的方法——这一半通常没人提醒。

臃肿是从哪里长出来的

不受约束的模型天生爱写代码。给它一个细小的边界情况,它的第一反应是新建一个私有辅助类、把一个已有工具函数复制一份改个参数,或者给一个库套上三层抽象——那三层只有在这段 diff 里才讲得通。放它自己跑一周,就是几千行语气笃定、看起来合理、其实没必要的代码。

我这么讲是因为我自己的历史里就有那一周。每天读这些 diff,最后落成两条规矩:

真正把代码删掉的是三道闸门

在最近一次主生产系统的 V2 架构重构中,三十天里删掉了 98,000 多行。这些几乎不是我坐下来专门去删的,而是三道闸门不断把回来的东西打回,最后留下的就是更小的版本:

1. 用确定性脚手架,而不是问「这段看着对不对」

让模型审查自己写的代码,多数时候产出的是自信,不是正确。有用的做法是把它接到一个没法被说服成绿灯的东西上:

闸门红了,Agent 要么改到过,要么把这段撤掉。没有任何东西能豁免。

2. 把剪枝当成日常动作,而不是一次大扫除

每次会话都会分出一段时间专门删东西:这个 200 行的辅助类,能不能换成一行已有的原生调用?这个新的映射层,是不是在重复 app/Libraries/ 里放了一年的某个函数?上面那 13 万行删除不是重写的副产品,而是活过头了的脚手架、只有一个调用方的迁移层,以及换了名字出现两遍的同一段逻辑。

3. 确定性的活留给确定性代码

我在 AI 项目里反复看到的坑,是让模型去做它根本不该碰的计算。如果一条 Shell 管道、一个 SQL 约束、一个幂等脚本或者一个 Cron 任务就能给出答案,那 LLM 就不该出现在那里。

模型擅长起草初始实现、生成三语词库、摸清三方 API 的脾气;但状态流转、钱、队列调度,我不会交给它——一个确定性问题上概率性的答案,是一颗带延时引信的 bug。

我的工作方式变了什么

我职业生涯的大部分时间里,物理瓶颈是打字速度和记语法。产出就是指标,一个高效的一周看起来就是新建了很多文件。

现在语法是免费的。我可以一边读上一次改动的 diff,一边让 Agent 起草一份带单元测试的 500 行迁移。于是瓶颈转移到了模型替我看不了的三件事上:

所以我现在不再把提交曲线当生产率图表看。一个月新增 50 万行,只能说明工具在转;真正说明这一个月值不值的是那删掉的 13 万行、底下的重构,和一套仍然全绿的测试。

需要一套能长期不倒的系统?

我运营 Hoelee Enterprise,为马来西亚中小企业做网站设计与系统开发。上面这套 Agent 工作流、测试脚手架和自托管基础设施,就是我给客户交付并长期维护系统时用的同一套东西。

如果你需要全栈系统研发、业务流程自动化,或者能扛住自己维护周期的自建基础设施:

Lee Teong Hoe

Lee Teong Hoe · Mr Hoelee

Full-stack developer & DevOps engineer based in Malaysia. I run my own production infrastructure and build web systems for small businesses — this blog is the living record.

Hiring? Profile & stack · Malaysian SME? Website design & development ↗ · All posts