第 3 课:Git staging / commit / merge conflict——让 Agent 的代码修改“可审查、可回滚、可合并”
今天解决一个非常实际的问题:Agent 已经会修改代码了,但怎样避免它“一把梭”把不该提交的文件、错误修改、甚至密钥一起提交?
核心答案是:
Working Tree → Staging Area → Commit → Merge/PR
Git 官方把 index 也就是 staging area 定义为“准备下一次 commit 内容的地方”;普通 git commit 只会记录已经 staged 的变化。citeturn143430search4turn143430search8
先建立这个心智模型:
HEAD
│
│ 上一次提交
▼
Repository
│
│
├───────────────┐
│ │
▼ ▼
Index Working Tree
暂存区 当前文件
你修改代码后:
Working Tree:
Program.cs 已修改
Index:
还没有修改
HEAD:
旧版本
执行:
git add Program.cs
变成:
Working Tree:
Program.cs 新版本
Index:
Program.cs 新版本
HEAD:
旧版本
再:
git commit -m "fix timeout"
才真正形成新的版本。
为什么 Agent 特别需要 staging area
假设 Coding Agent 完成任务后,项目状态是:
modified:
src/App.cs
modified:
src/HttpClient.cs
modified:
README.md
untracked:
.env
untracked:
debug.log
如果 Agent 直接:
git add .
可能把:
.env
debug.log
也放入 staging area。
其中 .env 甚至可能包含:
OPENAI_API_KEY=...
DATABASE_PASSWORD=...
因此企业 Agent 不应该把:
git add .
当成默认提交策略。
更安全的是:
Agent完成代码修改
↓
git status
↓
检查 changed files
↓
git diff
↓
测试
↓
只 stage 允许的文件
↓
git diff --cached
↓
再次审查
↓
commit
这里第一次遇到:
git diff
和:
git diff --cached
Git 官方文档说明,普通 git diff 主要看 working tree 相对 staging area 的变化;git diff --cached 则可用来检查已经进入 index、准备提交的内容。citeturn143430search12
所以以后你可以把:
git diff
理解成:
“还有哪些修改没 stage?”
而:
git diff --cached
理解成:
“如果现在 commit,到底要提交什么?”
后者对 Coding Agent 特别重要。
一个企业 Agent 的正确提交闭环
以后我们的 Mini Agent Platform 会近似这样设计:
changes = git_status()
safe_files = policy_filter(changes)
for file in safe_files:
git_add(file)
staged_diff = git_diff_cached()
decision = reviewer.review(staged_diff)
if decision.safe:
run_tests()
if tests_pass:
git_commit()
注意这里有 两个 Agent 角色:
Coder Agent
↓
修改代码
Reviewer Agent
↓
审查 staged diff
以后进入 multi-agent 时,这就是最简单的一种:
Writer
+
Reviewer
结构。
Claude Code 为什么也强调 Git diff
Claude Code 官方目前明确支持直接使用 Git,可以 staging、生成 commit message、创建 branch 和 PR。citeturn372191search19
更有意思的是,Anthropic 官方的 Skills 示例专门展示了:
获取 repository 当前真实 diff,然后让 Claude 总结未提交变化并标记风险。
这样做的意义是让 Agent 依据 实际 working tree,而不是凭上下文猜测“自己刚才改过什么”。citeturn143430search27
也就是说:
LLM memory
↓
可能不准确
git diff
↓
实际状态
这又出现一个以后非常重要的 Agent 工程原则:
能通过工具获得事实,就不要让模型依赖记忆猜事实。
Codex 中 Git 为什么会和 Sandbox 冲突
现在进入一个非常典型的部署工程问题。
执行:
git add src/App.cs
看起来只是“暂存文件”。
实际上 Git 还需要修改 repository metadata,例如:
.git/index
或者 linked worktree 中的:
main-repo/.git/worktrees/<worktree>/index
并创建类似:
index.lock
这样的锁文件。
2026 年 Codex 的公开 issue 中就出现了 linked worktree 下 git add 失败:sandbox 允许写 worktree 文件,却没有允许写主 repository 下对应的 .git/worktrees/.../index.lock。citeturn143430search22
于是:
Agent:
git add app.py
↓
文件本身可写
↓
Git需要写:
.git/worktrees/agent/index.lock
↓
Sandbox禁止
↓
git add失败
这非常关键。
看到:
Unable to create index.lock
Permission denied
不要马上判断:
Git 坏了。
也不要判断:
Agent 不会 Git。
应该检查:
Git metadata path
sandbox writable roots
worktree类型
文件权限
Codex 在 Windows 上也出现过类似问题:workspace 本身可写,但 .git 写入被 sandbox 拦截,导致 worktree、commit、merge 等操作反复需要人工批准。citeturn143430search6
这就是企业岗位里的:
应用故障 ≠ 模型故障。
Approval 与 Git side effect
现在比较:
git diff
和:
git push
它们风险完全不同。
git diff:
只读
本地
几乎无副作用
git push:
写远程repository
影响别人
可能触发CI/CD
甚至触发部署
因此企业 Agent 权限策略一般应该不同。
Claude Code 官方权限系统支持细粒度规则;官方示例里就能分别控制类似:
Bash(git diff *)
Bash(git push *)
这样的命令。citeturn143430search3turn143430search23
你可以把策略想成:
git status → Allow
git diff → Allow
git log → Allow
git add → Ask / Policy controlled
git commit → Ask
git push → Ask
git reset --hard → Deny / Strong Ask
这比单纯:
Allow Shell
安全得多。
因为 Shell 并不是一个风险等级。
Shell 里面可能是:
pwd
也可能是:
rm -rf /
还可能是:
git push --force
Kimi Code 的同类问题
Kimi CLI 生态中也已经出现针对 granular auto-approval 的需求,例如:
git * → allow
rm * → ask
这说明实际 Coding Agent 使用中,“Shell 是否允许”已经不够,而需要进入 命令级策略。citeturn372191search3
这里你应该开始建立一个企业安全模型:
Tool
↓
Command
↓
Arguments
↓
Target resource
↓
Side effect
↓
Approval policy
例如:
Shell
↓
git
↓
push
↓
origin/main
↓
remote write
↓
human approval
这就是以后 RBAC、Policy Engine、OPA 等概念的前身。
Commit 到底是什么
很多初学者把:
git commit
理解成:
“保存一下文件。”
不准确。
更准确是:
为当前 staging area 创建一个新的 Git 历史节点。
例如:
A -- B -- C
你提交:
git commit -m "fix timeout"
变成:
A -- B -- C -- D
其中 D 包含:
父commit
tree快照
author
时间
commit message
所以 Coding Agent 做 commit 的价值并不是“让修改生效”。
真正价值是:
形成可追踪版本
便于review
便于rollback
便于merge
便于PR
为什么 Agent 自动 commit 要谨慎
假设 Agent 任务:
修复登录 timeout。
但它修改:
auth.cs
http.cs
database.cs
README.md
Dockerfile
如果 Agent直接:
git commit -am "fix timeout"
你会得到一个语义混乱的 commit。
好的企业代码习惯要求:
一个commit
≈
一个逻辑修改
所以 Agent 以后应该能够判断:
这些修改是不是同一个任务?
必要时拆分:
commit 1:
fix HTTP timeout
commit 2:
add regression test
这叫:
atomic commits
后面 CI/CD 和代码审查会非常依赖这种习惯。
Merge 是什么
现在有:
main:
A -- B -- C
agent:
└── D -- E
Agent 完成任务以后,可以把 agent branch 合回 main。
Git 官方定义 git merge 是把已经发生分叉的提交历史合并到当前 branch。citeturn143430search0
理想情况:
A -- B -- C ------- M
\ /
D -- E ----
M 是 merge commit。
为什么会产生 Merge Conflict
假设 main 修改:
int timeout = 20;
Agent branch 修改同一行:
int timeout = 30;
Git 无法自动知道:
到底应该 20 还是 30?
于是:
CONFLICT
文件中可能出现:
<<<<<<< HEAD
int timeout = 20;
=======
int timeout = 30;
>>>>>>> agent/timeout
这三个 marker 必须认识:
<<<<<<<
=======
>>>>>>>
Git status 也会把这种路径显示为 unmerged 状态。citeturn143430search16
Agent 为什么特别容易制造 Conflict
人的开发过程通常是:
修改
commit
pull/rebase
继续开发
Agent 有时会:
长时间执行
↓
修改几十个文件
↓
期间main已经发生变化
↓
最后一次性merge
冲突概率明显增加。
更糟糕的是,多 Agent:
Agent A → 修改 API
Agent B → 修改 API
Agent C → 修改 API
都基于旧 commit。
于是出现:
stale branch
也就是“分支基线已经过时”。
以后企业 Agent 调度器需要做:
任务启动前:
记录 base SHA
任务结束前:
检查 main HEAD
如果main已变化:
rebase / merge / restart / human review
这已经是 Agent orchestration 的一部分。
一个简单的 Agent merge 策略
可以设计:
Agent完成
↓
git status必须clean except task changes
↓
run tests
↓
commit
↓
fetch latest main
↓
尝试merge/rebase
↓
没有冲突
├─ test
└─ PR
↓
有冲突
↓
进入Conflict Resolver
↓
再次测试
↓
人工review
注意:
能自动解决 conflict ≠ 应该永远自动解决。
如果冲突涉及:
数据库migration
安全权限
支付逻辑
生产配置
deployment
最好升级人工审批。
Patch 与直接改文件
Git 官方还有:
git apply
它可以应用 patch,但不会自动创建 commit。citeturn143430search20
Coding Agent 经常更偏向:
生成patch
↓
apply
↓
验证diff
而不是:
直接把整个文件重写一遍
原因是 patch 更容易:
审查
追踪
限制修改范围
检测context mismatch
以后我们会真正自己实现:
read_file
↓
generate patch
↓
apply patch
↓
verify diff
这是 Coding Agent 文件编辑器的核心之一。
Hooks:从“希望 Agent 记得”变成“系统强制执行”
假设团队规定:
每次 Agent 修改 Python 文件后必须执行 formatter。
差的做法:
Prompt:
“记得运行 black。”
因为模型可能忘。
更可靠的是:
Hook:
文件修改结束
↓
自动执行 formatter
Claude Code 官方 Hooks 就是用来在生命周期节点运行确定性 shell 命令,例如自动检查或执行项目规则;Anthropic 明确说明 hooks 是用户定义的 shell command。citeturn143430search11
这说明:
LLM instruction
与:
deterministic automation
是两种东西。
企业系统里必须知道什么时候用哪一种。
例如:
判断代码设计是否合理
→ LLM
确保每次都运行 lint
→ hook / CI
但要特别注意:Claude Code 官方警告 command hook 使用当前系统用户权限执行,可以修改或删除该用户能访问的文件。citeturn143430search7
所以:
Hook ≠ 天然安全
今天的 PowerShell 实验
继续使用你的测试 repository。
先创建文件:
"version 1" | Out-File agent-test.txt
查看:
git status
git diff
stage:
git add agent-test.txt
再:
git status
git diff
git diff --cached
重点观察:
为什么普通 git diff 现在变化了,而 git diff --cached 出现内容。
然后:
git commit -m "add agent test file"
再:
git status
git log --oneline -3
接下来制造一个非常小的 conflict。
git switch -c agent/conflict
"agent version" | Out-File agent-test.txt
git add agent-test.txt
git commit -m "agent change"
切回 main:
git switch main
"main version" | Out-File agent-test.txt
git add agent-test.txt
git commit -m "main change"
然后:
git merge agent/conflict
这次很可能得到:
CONFLICT
执行:
git status
Get-Content agent-test.txt
找:
<<<<<<<
=======
>>>>>>>
今天不需要追求熟练解决 conflict。
只要真正看到一次即可。
一个企业级故障排查案例
假设日志:
Agent:
git add src/app.ts
Error:
fatal: Unable to create '.git/index.lock':
Permission denied
排查不要直接删除 .git/index.lock。
先问:
① 当前cwd是什么?
② 是普通repo还是linked worktree?
③ git rev-parse --git-dir 输出什么?
④ git rev-parse --git-common-dir 输出什么?
⑤ sandbox是否允许写那里?
⑥ 是否真的存在另一个Git进程持有锁?
这里尤其重要:
看到 lock 文件错误,不等于 lock 文件一定是残留垃圾。
可能实际上是:
Sandbox denied write
2026 年 Codex 的 linked-worktree 问题就是这样的典型案例。citeturn143430search22
这就是工程师的排错方式:
现象
↓
验证假设
↓
定位layer
而不是:
看到报错
↓
Google一个删除命令
↓
直接执行
今天需要形成的 Agent 安全模型
把前 3 课连起来,现在一个成熟的 Coding Agent 最低应该有:
User Task
↓
LLM
↓
Tool Call
↓
Permission Policy
↓
Git Worktree
↓
File Edit / Patch
↓
git status
↓
git diff
↓
Selective staging
↓
git diff --cached
↓
Test
↓
Review
↓
Commit
↓
Merge / PR
再往后才是:
Docker
CI/CD
Kubernetes
Deployment
也就是说:
Git 是 Agent 从“会改代码”进入“工程化改代码”的第一道基础设施。
今天对应的企业岗位能力
你今天已经接触到:
Git index/staging、atomic commit、merge conflict、patch、approval、hooks、sandbox 与 Git metadata。
这些内容以后对应的真实工作包括:
Coding Agent平台开发
DevOps
CI/CD
代码审查自动化
Agent安全治理
多Agent并发workspace
故障排查
今日检查题
- 为什么
git add .对自动化 Agent 风险比较高? git diff与git diff --cached最大区别是什么?- 为什么 Codex 在 worktree 中可能“文件能写,但 git add 失败”?
- Merge conflict 本质上为什么产生?
- 为什么 lint 更适合 Hook/CI,而“判断架构设计是否合理”更适合 LLM?
参考答案核心:
1. 容易stage不属于任务甚至敏感文件。
2. 一个主要看未stage修改,一个检查准备commit的staged修改。
3. Git还需要写.git/worktrees等metadata,而sandbox可能没授权。
4. 不同branch修改了Git无法自动决定如何合并的内容。
5. lint是确定性规则;设计判断需要语义推理。
下一课进入 Bash / PowerShell 的真正核心:进程、管道、重定向、环境变量、PATH、cwd,以及为什么同一条 Agent 命令在 Windows、macOS、Linux、Docker 中会产生完全不同的结果。