就此AI就此AI

当 Agent 接管操作后,Git 还教会我们什么?——南京大学《生成式软件工程》第三讲

2026-09-10 · 就此AI

当 Agent 接管操作后,Git 还教会我们什么?——南京大学《生成式软件工程》第三讲

课程页面:2026 南京大学《生成式软件工程》第三讲

第三讲核心内容总览

一、模型更会执行以后,软件工程的问题反而更清楚了

生成式 AI 已经能把许多生活和开发中的麻烦变成可执行任务:描述真实意图,让 Agent 操作工具、处理细节,再把一次成功的过程沉淀成可复用的 Skill。模型的能力提升会不断扩大这类任务的范围,但“能完成”并不自动等于“做得对”。

原因仍然是软件工程中那组开放的空间:Intention 是真正想解决的问题,Specification 是什么结果才算满足要求,Implementation 才是具体的代码、资源和运行环境。只说“做一个国民级应用”时,即使由经验丰富的人来实现,脑中也可能对应完全不同的产品;模型只能在这个巨大解空间里选择自己的理解,于是结果自然可能偏离人的意图。

模型可以替人把代码写得更快,也能处理视觉、空间和工具操作等过去更困难的任务,但人仍需要理解基本概念、判断产物质量,并把“给全世界人使用”这样的真正约束写进需求。一个只能在 localhost 打开的原型和一个可部署、可维护的产品,差异不在于页面有没有出现,而在于项目是否被组织成了完整的交付物。

软件不是孤立的一段代码。代码、文档、需求、测试、构建配置和发布方式共同构成了信息世界对现实需求的投影。一个目录之所以成为工程项目,正是因为其中的对象能够一起被运行、检查、协作和继续演化。

二、Git 的第一性原理:为整个项目保留可回退的快照

早期的项目管理常常靠复制目录:作业 V1、作业 V2、最终版,再把压缩包通过邮件发给别人。它确实解决了“改错后能不能回去”的问题,但版本一多,哪些文件变过、两个副本如何合并、谁引入了错误都会变得难以回答。

Git 把这个朴素需求变成了更干净的模型:它管理的不是单个文件,而是一个目录树在某一时刻的完整状态,并让项目可以随时回到任意一次保存的状态。Git 的底层对象可以用三种基本类型理解:

对象 保存的内容 在项目历史中的角色
Blob 一段字节序列,例如一个文件内容 保存文件本身
Tree 文件名、权限和指向 Blob 或子 Tree 的引用 保存目录结构
Commit 指向一个 Tree、父提交和提交说明等元数据 标识一次项目快照

这是一种持久化数据结构。修改一个文件不需要复制整个项目;Git 只创建发生变化的文件对象,以及从该文件回到根目录路径上必要的新 Tree,未变的部分继续引用旧对象。项目即使很大,一次小改动也可以用很小的增量形成一个新快照。

这也解释了分支的本质:它不是神秘的平行世界,而是指向某次提交的引用。不同分支可以从同一祖先出发,各自保存不同快照;合并时,Git 尝试把两边的变化放回同一棵目录树。若两人改了同一处且无法自动判断取舍,冲突不会被魔法消除,仍需要人理解两段变化各自代表的意图并作出裁决。

三、原子提交不是形式主义,而是给未来留下解释能力

Git 允许把很多文件一次性提交,也允许提交没有信息量的说明,但工程实践并不鼓励这么做。一个好的提交应当是单一、完整、可解释的变化:修复一个问题、增加一个功能、调整一项配置或完成一段自洽的重构。提交说明应描述这次变化做了什么,而不是留下“做了一些很酷的事”之类无法帮助后人的句子。

这样的粒度带来三层价值:

  1. 每个快照应能构建并通过相应测试。把无法编译的中间状态放进主历史,会让后来的人无法区分问题本身和暂存的半成品。
  2. 问题发生后可以用 git bisect 在提交历史中二分定位引入错误的变化;通过 git blame 可以追溯某一行代码来自哪次提交,并回到当时的修改语境。
  3. 修复与引入问题的提交可以形成明确对应。一次跨越数千行、混合多个目标的大提交若引入许多问题,后续难以审计;一连串小的原子提交则让责任、回退和复查都有清楚边界。

及时提交并及时推送还有一层朴素意义:它是远端备份。设备损坏、误操作或本地环境变化都不应该让尚未同步的工作直接消失。

“所有生成文件都不该提交”同样不是绝对规则。编译产物、日志、个人编辑器配置、操作系统索引文件以及仍处于有效状态的密钥,通常不应进入版本库:前几类会制造无意义差异或冲突,密钥则可能直接造成安全事件。另一方面,某些锁文件或预生成头文件可能是复现构建所必需的。关键不是机械执行 git add .,而是理解每个文件是否应当成为项目可共享状态的一部分,并用 .gitignore、预提交检查和审查流程表达这个判断。

四、Agent 可以代替重复操作,但不能代替注意力

当 Agent 已能调用 Git、修复冲突、生成提交说明甚至重写本地历史时,记住每一条命令不再是最重要的能力。更重要的是知道项目管理要解决什么:哪些文件变了,是否混入了生成物或敏感信息,提交是否仍可构建和测试,修改是否保持在约定的范围内。

这不是要求人重新回到纯手工操作,而是要求把注意力放在能改变结果的地方。面对成熟项目时,README 的长度和链接安排、目录结构、提交历史的粒度、界面在不确定处是否给出提示,都会暴露出长期维护中积累的判断。把这些具体差异和自己原本会怎样做进行比较,再追问“它为什么更好”,可以把浏览项目从被动接收信息变成主动学习。

AI 让这种学习循环更短:遇到新概念时可以立即要求解释,看到一项实践时可以追问其适用条件和反例,发现不确定的选择时可以请求列举一致性、可维护性和团队协作上的取舍。它降低了探索和请教的成本,却没有取消“理解之后再决定是否采纳”的责任。

五、把规则放在能够阻止错误的位置

工程项目的约束可以由人手动遵循,也可以在发生关键动作时自动执行。Git 的 pre-commit hook 能在提交前检查格式、文件类型、密钥和测试状态;Agent 的 hook 则可在任务完成、需要输入或发生某类工具操作时触发提醒与检查。两者的共同点是:把容易被遗忘的规则放到它真正会影响结果的位置。

这类规则需要足够具体。统一命名、提交格式、文档排版和文件收录范围看似细小,却会在项目增长、多人协作和长时间维护后累积成巨大的理解成本。约定可以采用 Conventional Commits 等已有规范,也可以按项目需要制定;真正重要的是同一项目内保持一致,并让规则能够被自动检查或明确审查。

大模型尤其适合承担耐心而重复的检查:逐项阅读变更、解释风险、给出修正建议、在可验证条件下反复尝试。但模型会沿着给定目标认真优化,因此错误的规则也可能把它引向错误方向。把“每次提交都必须通过构建和测试”“不得纳入有效密钥”写清楚,比笼统要求“像专家一样认真”更能形成可靠约束。

六、Agent Native 的工作流:先收窄结构,再扩大并行执行

AI 加速并不意味着架构可以后置。多个 Agent 同时修改一个缺乏边界的系统,只会把混乱更快地放大。更稳妥的顺序是先用能力较强的模型和人一起讨论架构:定义核心接口、确定哪些状态应共享、把能做成纯函数的部分尽量做成纯函数,再让 Agent 在小而清晰的范围内实现。

当接口和状态边界稳定后,项目可以拆成多个可独立审计的任务。每个任务沿着自己的分支小步提交;失败的探索可以安全丢弃,成功的变化再经测试、审查和合并进入主线。线性历史、rebase、cherry-pick 或合并提交各有取舍,但它们服务于同一个目标:让后来的人和 Agent 能以较低成本读懂变化来自哪里、影响了什么、能否被安全复用。

这也是 Agent Native 软件工程的分工方式:

人的高杠杆工作 Agent 擅长承担的工作
澄清真实意图,定义架构、接口、共享状态和验收标准 执行重复操作,阅读变更,生成候选实现和提交说明
判断设计是否仍然简洁、可维护且符合产品品位 在明确规则内构建、测试、检查、修复和迭代
决定冲突两侧真正应保留的语义,选择何时停止一条错误路线 把任务拆成小步骤,保留可比较的过程记录

模型越快,版本控制和工程结构越不是过时的负担,反而越是协调高速变化的基础设施。一个混沌项目无法靠更多 Token 自动变得清晰;清楚的架构、原子变化和可验证的历史,才能把持续增长的执行力转化为可靠的软件。

七、第三讲留下的结论

Git 的价值不止是下载、上传或处理冲突。它提供了一种组织复杂性的基本方法:把项目写成一连串可以理解、可以构建、可以审计、可以回退的快照。分支让探索可以并行,合并让成功的变化重新汇合,提交历史让错误和责任能够被追溯。

在 Agent 能替人完成越来越多操作的时代,这套方法的重点从“亲手敲过所有命令”转向“能否提出正确的工程约束”。人需要把精力留给意图、架构、质量标准和关键判断;Agent 则在这些边界内持续执行、检查和迭代。软件工程并没有因为自动化而消失,它正在成为管理自动化本身的能力。

查看更多文章 →

正在加载完整版…