TRAE 绿皮书
新手入门 / AI 通识方法论

万字干货|Agentic Coding 场景下的 Git 实践

新范式下 Agent 如何参与开发

在传统开发中,git 的工作单元是「一个开发者的一次有意图的决策」,但是 Agentic coding 打破了这个假设:

以上这些特征催生了一系列传统 Git 工作流难以应对的新挑战。那我们应该如何应对这些调整,我们将从核心痛点出发,为大家推荐更好的实践技巧。

核心痛点

2.1 Git 只记录 diff,不记录意图与推理过程

图片展示了Git操作流程。左侧显示了分支、提交等Git操作界面,有绿色和红色的代码对比区域。右侧是代码仓库的复杂网络图,包含多个代码文件和分支节点,用箭头连接,形成网络结构。图片与上下文紧密相关,直观呈现了Git只记录diff不记录意图与推理过程的场景,帮助理解传统开发中commit message补充上下文的局限性,以及agent执行过程的复杂性。
img-132 · 图片展示了Git操作流程。左侧显示了分支、提交等Git操作界面,有绿色和红色的代码对比区域。右侧是代码仓库的复杂网络图,

Git commit 可以精确告诉你「改了什么」,却很难说清 agent 为什么这样改、它依据了哪个 prompt、是否误解了需求。传统开发中,commit message 往往能补充一部分上下文;但 agent 的执行过程完全不同:它可能跨多个模块探索、试错、改写、回滚,最终留下一个看似合理但意图不清的 diff。

这带来的典型问题是:PR 看起来完整,实际解决的却是一些相关的问题而非原始需求;或者 agent 在修 bug 时顺手重构、改依赖、改配置,导致 reviewer 很难判断哪些变更是必要的,哪些只是副作用。

Agent 倾向于产生两种极端的提交模式,进一步加剧了这一问题:

「为什么这样做」「权衡了哪些方案」「有哪些已知限制」,这些对未来维护至关重要的信息,agent 不会主动写进提交历史。

2.2 脏工作区难以管控,变更噪声大

图片展示了Agentic Coding场景下的Git实践相关概念。画面中有多个带有编号的卡片,卡片上有代码、进度条等元素,部分卡片被红色、绿色边框突出显示。卡片间通过线条连接,形成网络状结构。画面右侧有代码行数、提交记录等信息。左侧有文件夹图标,下方有“+”号。该图与文档中核心痛点部分相关,直观呈现了Agent的探索过程、变更噪声大等问题,辅助说明Agent覆盖开发者本地WIP、`git diff`混入噪声、误删文件等常见问题。
img-133 · 图片展示了Agentic Coding场景下的Git实践相关概念。画面中有多个带有编号的卡片,卡片上有代码、进度条等元素

Agent 的探索过程比人类更快、更分散,很容易造成工作区混乱。未提交的临时文件、格式化变更、测试 fixture 和真实业务修改混在一起,脏工作区(dirty worktree)一旦累积,审查和回滚都会变得困难。

常见问题包括:

2.3 Git merge 只是文本校验,但不保证语义正确

图片展示了Agentic Coding场景下Git实践中的变更流程。上方为变更提交流程,从代码提交开始,经Agent处理,再由Git进行合并,最后通过CI/CD验证。下方为变更验证流程,从代码提交开始,经Agent处理,再由CI/CD进行验证,若验证通过则显示绿色对勾,若不通过则显示红色感叹号。该图与上下文紧密相关,直观呈现了变更从提交到验证的完整流程,帮助理解Git实践中的常见问题及解决思路。
img-134 · 图片展示了Agentic Coding场景下Git实践中的变更流程。上方为变更提交流程,从代码提交开始,经Agent处理

LLM agent 会做跨文件、跨抽象层的修改。Git 的 merge 机制是文本层面的:只要没有行级冲突,就认为合并成功。但「无冲突合并」并不等于「语义正确」。

典型场景是:一个 agent 修改了某个接口的语义,另一个 agent 同时在旧语义下新增了调用点。两个 branch 各自通过测试,合并时也没有冲突,但运行时行为已经被破坏。多 agent 并发时,这种问题还会因为彼此不了解对方的修改意图而加剧:

不能把「分支能 merge」等同于「可以发布」,这一点在 agent 并发开发场景中尤为重要。

2.4 巨型提交让审查、回滚与定位全部失效

图片展示了Git版本控制系统中问题定位的流程。左侧放大镜下有代码文件,中间是复杂的代码网络图,右侧有代码文件、测试文件等。中间代码网络图中有一个红色感叹号标识的问题commit,其后有“git bisect”标识的二分搜索操作,右侧还有“git revert”标识的回滚操作。该图与上下文紧密相关,直观呈现了巨型提交导致问题定位困难,以及Git工具如`git bisect`和`git revert`在其中的应用场景。
img-135 · 图片展示了Git版本控制系统中问题定位的流程。左侧放大镜下有代码文件,中间是复杂的代码网络图,右侧有代码文件、测试文件等

Agent 一次性产出「巨型 diff」是最常见的问题之一:功能实现、测试、重构、格式化、文档、依赖升级全混在一起,几十个文件同时改动。这会导致一系列连锁问题:

git bisect 的价值在于用二分搜索快速找到引入问题的提交节点,但如果每个 commit 本身都包含大量无关变更,即便定位到了问题 commit,排查工作仍然没有彻底完成。

3. 最佳实践

3.1 建立 Agent-Aware 的 Commit 规范

界面截图
img-136 · 界面截图

核心原则:每个 commit 应当能独立描述「做了什么、为什么、上下文是什么」。

推荐的 commit message 格式:

PLAIN TEXT
<type>(<scope>): <summary>

<正文:描述本次变更的背景与动机>

Agent-Task: <原始任务描述或任务 ID>
Agent-Model: <使用的模型,如 gpt-4o、gemini-2.5-pro>
Agent-Decision: <关键设计决策及理由>
Agent-Limitation: <已知局限或后续 TODO>

示例:

PLAIN TEXT
feat(auth): implement JWT refresh token rotation

Add sliding-window refresh token support to reduce re-login friction
while maintaining session security.

Agent-Task: PROJ-234 - Add refresh token support to auth service
Agent-Model: gpt-4o
Agent-Decision: Used 7-day sliding window over fixed expiry for better UX;
  refresh tokens stored in httpOnly cookie to prevent XSS access
Agent-Limitation: Redis TTL not yet aligned with token expiry on logout

关于 Git Commit Trailer

上述 Agent-Task:Agent-Model: 等字段使用的是 Git 内置的 commit trailer 机制。Trailer 是附加在 commit message 末尾(与正文之间有一个空行)的结构化键值对,格式为 Key: Value,由 git 原生解析,无需额外工具。

Git 生态中已有大量使用 trailer 的先例,例如:

PLAIN TEXT
Signed-off-by: Alice <alice@example.com>
Co-authored-by: Bob <bob@example.com>
Fixes: #1234

你可以用标准 git 命令查询 trailer:

BASH
# 列出所有包含 Agent-Task trailer 的提交
git log --format='%(trailers:key=Agent-Task,valueonly)'

按 trailer 过滤提交历史

git log --grep="^Agent-Task:" --all

工程实施建议:

3.2 小步提交:Checkpoint Commit 策略

图片展示了Agent coding journey中Checkpoint Commit策略的流程。从CPI开始,每完成一小步提交(如a1b2c3d等),即进行测试并标记为已测试,若通过测试则标记为可回滚至该状态。在关键节点(如CP4、CP6)进行检查点提交(Checkpoint commit),可回滚至该状态。若实验(如exp1、exp2)失败,则回滚至最近的检查点提交。该图与上下文紧密相关,直观呈现了小步提交、检查点提交等关键操作及回滚机制。
img-137 · 图片展示了Agent coding journey中Checkpoint Commit策略的流程。从CPI开始,每完成一

对于耗时较长的 agent 任务,应要求 agent 在关键节点进行「检查点提交」,而不是等任务全部完成再提交。

指令示例:

PLAIN TEXT
在完成以下关键节点时,执行一次 git commit:
1. 完成数据模型/接口定义
2. 完成核心逻辑实现
3. 完成测试编写
4. 完成文档更新

每个 checkpoint commit 的 message 以 [WIP] 开头,最终完成后执行 git commit --amend 或通过 rebase 整理历史。

好处:


3.3 使用 Interactive Rebase 整理 Agent 历史

界面截图
img-138 · 界面截图

Agent 工作完成后,在合并前对 branch 历史进行整理是一个良好习惯。

BASH
# 查看当前 branch 的提交历史
git log --oneline main..HEAD

交互式 rebase 整理最近 N 个提交

git rebase -i main

常用操作:

pick - 保留该提交

squash/s - 合并到上一个提交

reword/r - 修改 commit message

drop/d - 删除该提交

fixup/f - 合并到上一个提交,丢弃本提交 message

建议的整理策略:

让 Agent 辅助完成历史整理

整理提交历史这件事本身也可以交给 agent 来做,以下是一个简洁的 prompt,可以在任务完成后直接发给 agent:

PLAIN TEXT
请帮我整理当前分支相对于 main 的提交历史,准备开 PR。

步骤:
运行 git log --oneline main..HEAD 查看当前所有提交
分析哪些提交属于同一个逻辑变更(尤其是 [WIP] 前缀的检查点提交)
给我一份整理方案:哪些应该 squash、哪些保留、message 应该改成什么
等我确认方案后,执行 git rebase -i main 完成整理
整理完成后再次运行 git log --oneline main..HEAD 展示最终结果

要求:每个保留的 commit 需符合 Conventional Commits 格式,并包含 Agent-Task、Agent-Decision trailer。

3.4 Atomic Commit:以原子粒度组织变更

界面截图
img-139 · 界面截图

Atomic commit 的核心定义是:一个 commit 只表达一个可解释、可回滚、可验证的语义变化,且在该 commit 节点上代码可以编译、测试可以通过。这一原则在人工开发中已被广泛推崇,在 agentic coding 中更显关键。

为什么 agent 场景更需要 atomic commit:

实践指南:

这里的 atomic 不是「一行一提交」,而是按逻辑关注点切分。以 refresh token 功能为例:

PLAIN TEXT
# 好的切分:每个 commit 对应一个独立关注点
feat(auth): add RefreshToken domain model and repository interface
feat(auth): implement JWT refresh token issuance in AuthService
feat(auth): expose POST /auth/refresh endpoint
test(auth): add unit tests for refresh token rotation logic

而不是:

PLAIN TEXT
# 反例:所有改动压成一个 commit
feat(auth): implement refresh token

在系统提示中引导 agent 遵守 atomic commit:

PLAIN TEXT
When implementing a feature, break your work into atomic commits:
- Each commit must represent exactly one logical change
- Each commit must leave the codebase in a buildable, testable state
- Do not mix refactoring with feature changes in the same commit
- Do not mix changes to multiple unrelated modules in the same commit

与 Checkpoint Commit 的关系:

Atomic commit 关注的是语义边界(一个 commit 做一件事),Checkpoint commit(见 3.3 小节)关注的是进度记录(长任务中的阶段性存档)。两者互补:checkpoint commit 在任务进行中保存现场,最终通过 interactive rebase 整理为一组语义清晰的 atomic commit 再合并。

3.5 强制使用 Feature Branch,禁止直接 push main 分支

这是最基础也最重要的保护:任何 agent 都不应该有权限直接推送到 main 或 master

分支命名规范:

PLAIN TEXT
agent/<task-id>-<brief-description>

示例

agent/PROJ-234-refresh-token-rotation agent/PROJ-301-migrate-postgres-schema

配置 branch protection rules(以 GitHub 为例):

PLAIN TEXT
- Require pull request before merging: 
- Require approvals: 1(至少一个人工审查通过)
- Dismiss stale pull request approvals when new commits are pushed: 
- Require status checks to pass before merging: 
- Restrict who can push to matching branches: 仅允许 CI bot 和指定人员

操作规范:

3.6 使用 git worktree 隔离并发 Agent

图片展示了使用`git worktree`隔离并发Agent的流程。从Repo开始,分支有main、feature等。Agent在worktree A、B、C、D中执行任务,如pytest、npm test等,任务完成后由Agent开PR,经Review和Merge后,最终合并到main分支。每个worktree为独立工作空间,可并行执行不同任务,避免在同一分支上执行多个不相关的agent任务,体现了分支隔离和并行执行的特点。
img-140 · 图片展示了使用`git worktree`隔离并发Agent的流程。从Repo开始,分支有main、feature等。A

当多个 agent 并行工作时,git worktree 是比多个 clone 更轻量的隔离手段。每个 agent 获得独立的工作目录,脏工作区的问题被天然隔离,同时所有 worktree 共享同一个 .git 目录,分支管理统一。

BASH
# 为每个 agent 任务创建独立 worktree
git worktree add ../agent-task-234 -b agent/PROJ-234-refresh-token
git worktree add ../agent-task-301 -b agent/PROJ-301-pg-migration

查看当前所有 worktree

git worktree list

任务完成后清理

git worktree remove ../agent-task-234

优势:

在多 agent 编排脚本中,为每个子任务指定工作目录参数指向对应 worktree 路径,确保 agent 的文件操作被限制在隔离目录内。


3.7 结构化 PR 模板,补充 Agent 上下文

PR 是人机交接的关键界面。应为 agent 生成的 PR 设计专用模板,要求其填写人类 reviewer 需要的上下文。

.github/pull_request_template/agent.md 示例:

MARKDOWN
## Task Description
<!-- 原始任务描述 -->

What Changed

<!-- 核心变更摘要,聚焦「做了什么」而非「改了哪些文件」 -->

Key Design Decisions

<!-- Agent 做出的关键设计决策及理由 --> - Decision 1: ... because ... - Decision 2: ... because ...

Alternatives Considered

<!-- 考虑过但未采用的方案 -->

Test Coverage

- [ ] Unit tests added/updated - [ ] Integration tests added/updated - [ ] Manual testing performed: <描述>

Known Limitations / Follow-up Tasks

<!-- 当前实现的局限,后续需要跟进的工作 -->

Review Guidance

<!-- 建议 reviewer 重点关注的部分 -->

工程实施建议:


3.8 维护 AGENT.md:Agent 的「团队规范手册」

图片展示了Agent在代码管理中的角色及流程。Agent通过咨询/更新与代码库交互,获取指导。Agent遵循手册中的编码风格、工作流、测试、提交规则等规范,确保一致的提交、可靠的测试和准备就绪的PR。手册还涉及安全边界、审查和项目约定等内容,团队更新时可获取手册。该图与文档中“维护AGENT.md:Agent的「团队规范手册」”部分相关,直观呈现手册在Agent工作中的作用。
img-141 · 图片展示了Agent在代码管理中的角色及流程。Agent通过咨询/更新与代码库交互,获取指导。Agent遵循手册中的编码

AGENT.md是 agent 的行为规范入口,应当包含所有 VCS 相关约定。将规范写入 AGENT.md,agent 在每次任务开始时都会读取并遵循,是让团队规范真正生效的最低成本方式。

推荐包含的 Git 相关内容:

MARKDOWN
## Git Workflow

Branch Naming

- Use `agent/<task-id>-<description>` for all agent-initiated branches - Never commit directly to `main` or `develop`

Commit Guidelines

- Follow Conventional Commits: https://www.conventionalcommits.org - Each commit must be atomic: one logical change, buildable and testable in isolation - Include Agent-Task, Agent-Decision trailers in commit body

PR Process

- Open PR against `main` using the agent PR template - Ensure all CI checks pass before requesting review - Do not merge your own PRs

What NOT to Commit

- API keys, tokens, passwords (use environment variables) - Build artifacts, `node_modules`, `__pycache__` - Local config files (`.env`, `*.local`) - Large binary files (use Git LFS if necessary)

Checkpoint Commits

For tasks expected to take more than 15 minutes: - Commit after completing each major logical unit - Use `[WIP]` prefix in message - Clean up history with interactive rebase before opening PR

3.9 建立 Agent 任务的可追溯性链路

图片展示了Agentic Coding场景下代码生成任务的可追溯性链路。从任务开始,经意图、Agent会话、计划、差异等环节,最终到部署。每个环节有时间戳、相关标识及证据,如PR、Commit等。关键部分有“Trace ID”贯穿始终,连接各环节。该图与文档中“建立Agent任务的可追溯性链路”内容相关,直观呈现了追溯链路设计的实践建议,帮助理解在出现问题时追溯代码生成过程的方法。
img-142 · 图片展示了Agentic Coding场景下代码生成任务的可追溯性链路。从任务开始,经意图、Agent会话、计划、差异等

当出现问题时,需要能够追溯「是哪个任务、用什么 prompt、在什么时候」产生了这段代码。

追溯链路设计:

PLAIN TEXT
任务系统(Jira/Linear)
    ↓ task-id
Git Branch / PR
    ↓ commit message 中的 Agent-Task trailer
Agent Session Log(可选:存储在 .agent-logs/ 目录,加入 .gitignore)
    ↓ 包含完整的 prompt 和 agent reasoning
代码变更

实践建议:

现有工具

上述链路目前需要靠规范和手动维护来保证,已有一些专门针对这一痛点的产品出现:

git-ai 是一个开源的 Git 扩展(Rust 实现,Apache-2.0 授权),定位为追踪 AI 生成代码的开放标准。它的核心机制是行级归因:支持的编码 agent 在写入代码时调用 git-ai 的 hook,将每一行代码标记为 AI 生成并关联到具体的 prompt 和模型。提交时,归因信息以 Git Notes 的形式附加到 commit 对象上,在 rebase、squash、cherry-pick 等操作后仍能保持正确追踪。整个过程不改变现有的提交工作流,.git/ai 目录存储的临时 checkpoint 在提交完成后自动清理,不会污染提交历史。

Entire 由前 GitHub CEO Thomas Dohmke 创立,定位更为激进:它不替换 Git,而是在 Git 之上构建一个语义推理层,将 agent 的完整决策过程(prompt、推理链、上下文)作为一等公民纳入版本控制。其核心机制是 Shadow Branch:每次 agent 提交时,Entire CLI 将结构化的 checkpoint 对象推送到一个独立的影子分支(entire/checkpoints/v1),主分支完全不受影响。这条影子分支构成一份只追加不修改的审计日志,可以追溯任意提交背后的完整 agent 推理过程,并通过 entire rewind 命令快速回滚到任意 checkpoint 节点。


3.10 关于 Monorepo

界面截图
img-143 · 界面截图

为什么 Monorepo 更适合 Agent

当 agent 实现一个跨越前后端的功能时,它需要同时理解 React 组件如何调用 API 接口、API 接口对应的数据库 schema 是什么、共享类型定义在哪里。在 polyrepo 架构下,这些信息散落在多个仓库中,agent 要么依赖开发者手动把相关代码粘贴进 context,要么在跨仓库调用中做出错误假设,导致接口不匹配或重复实现。

Monorepo 将所有代码放在同一个仓库中,agent 可以在单次 context 窗口内完整追踪一个用户动作从 UI 到数据库的完整链路。这不只是方便,更是 agent 能否可靠执行跨服务任务的基础条件。

具体来说,monorepo 在 agentic coding 场景下有以下优势:

完整的跨服务上下文:agent 无需在多个仓库之间跳转,可以在一次任务中同步修改 API 定义和对应的客户端调用,保证接口一致性。这类修改在 polyrepo 中需要多个协调的 PR,agent 往往无法独立完成。

大规模重构与迁移:monorepo 让 agent 能够可靠地执行影响范围广的重构,例如将一个共享 utility 函数的签名改变后,同时更新所有调用方。在 polyrepo 中,这类任务需要跨仓库协调,而 agent 当前的能力边界还难以可靠处理这种情况。

依赖图可见性:monorepo 工具(如 Nx、Turborepo)通常提供结构化的项目依赖图。Agent 可以查询「修改了 package A 之后,哪些 package 受到影响」,从而精确决定需要运行哪些测试,而不是盲目运行所有测试套件。

Monorepo 下的 VCS 挑战与应对

Monorepo 并不是没有代价的,在 agentic coding 场景下,它引入了一些额外的 VCS 挑战:

并发冲突风险更高:所有 agent 共享同一个仓库,在 monorepo 中同时运行多个 agent 时,公共文件(如 package.json、共享类型定义、配置文件)的冲突概率远高于 polyrepo。git worktree 或 GitButler 虚拟分支是应对这个问题的关键手段,每个 agent 任务需要有独立的隔离工作区。

PR diff 更容易变大:即使是聚焦的功能开发,也可能因为涉及共享 package 的修改而产生较大的 diff 范围。Stacked PR(见 3.7 节)在 monorepo 中尤为有价值:将「修改共享 package」和「更新各消费方」拆成独立的 PR 层,可以显著降低每层的审查复杂度。

CI 范围界定:monorepo 中的全量 CI 成本高昂,需要配合依赖图工具实现「只跑受影响 package 的测试」,代码增量编译的能力和稳定性也非常重要。可以在 AGENT.md 中明确说明哪些 CI 命令适合 agent 在本地运行:

MARKDOWN
### CI Commands for Agents

只运行受当前变更影响的 package 的测试(需要 Nx 或 Turborepo)

nx affected --target=test turbo run test --filter='[HEAD^1]'

全量检查(在 PR 合并前由 CI 执行,不建议 agent 本地全量运行)

npm run test:all

Atomic commit 的边界:在 monorepo 中,atomic commit 的「一件事」需要更明确的定义。修改共享 library 的同时必须同步更新消费方,这算一个 commit 还是多个?推荐的做法是:一个 commit 表达一个完整的语义变化,即使它涉及多个 package,只要这些修改在逻辑上是不可分割的(例如接口变更加上对应的调用方更新),就可以放在同一个 commit 中。

3.11 Stacked PR:将大任务拆解为可审查的层叠单元

图片展示了Stacked PR(堆叠PR)的工作流程。大型任务被拆解为多个小任务,依次形成PR 1、PR 2、PR 3、PR 4。每个PR针对前一个PR的分支而非`main`,形成有序的依赖链。PR 1、PR 2、PR 3、PR 4分别经过Review后,依次合并到Mainline,最终完成大型任务。该图与上下文紧密相关,直观呈现了Stacked PR解决巨型PR审查质量低、依赖管理麻烦等问题的工作原理。
img-144 · 图片展示了Stacked PR(堆叠PR)的工作流程。大型任务被拆解为多个小任务,依次形成PR 1、PR 2、PR 3、

问题背景

Agent 往往能在一次任务中完成数量可观的工作:实现新接口、补充测试、更新文档、升级依赖,这些变更从语义上属于不同关注点,却全部堆进同一个 PR。巨型 PR 的审查质量很低,而简单地「多拆几个 PR」又面临依赖管理的麻烦:PR B 依赖 PR A,PR A 还没合并,reviewer 需要同时理解两个 PR 的上下文。

Stacked PR(堆叠 PR)是解决这一矛盾的工作流:每个 PR 针对前一个 PR 的分支而非 main,形成有序的依赖链。每层 PR 只展示当前层的 diff,reviewer 可以独立审查每一层,合并时按顺序从底部开始依次合入。

PLAIN TEXT
main
 └── PR #1:feat(auth): add RefreshToken domain model
       └── PR #2:feat(auth): implement token rotation in AuthService
             └── PR #3:feat(auth): expose POST /auth/refresh endpoint
                   └── PR #4:test(auth): add integration tests

GitHub Stacked PRs(gh-stack)

GitHub 正在以 gh-stack 的形式将 Stacked PR 作为原生特性引入(目前处于 private preview)。它的核心体验包括:

jj 和 GitButler 对 Stacked PR 的原生支持

使用原生 Git + gh-stack 的主要阻力在于:手动维护分支层叠关系、底层分支变化后需要逐层 rebase、以及在多个 branch 之间频繁切换。后续会介绍的 jj 和 GitButler 从设计上消除了这些摩擦:

Jujutsu:jj 的提交链天然就是 stacked PR 的工作单元。在 jj 中,你只需按顺序创建提交,每个提交对应一个 PR 层;修改任意一层后,jj 自动 rebase 所有后代,无需手动维护级联关系。配合 jj git push 和 gh-stack,可以做到本地改一层、远端整条 stack 自动更新:

BASH
# jj 的 stack 工作流:在提交链上直接操作,无需切分支
jj new -A ywnkulko   # 在某个提交后插入新的一层
jj describe -m "feat(auth): add token revocation endpoint"

jj 自动将后续所有提交 rebase 到新的提交链上

jj git push --all # 推送所有分支 gh stack submit # 在 GitHub 同步 stack 状态

GitButler:Stacked Branches 是 GitButler 的核心功能之一。通过 but branch -a 可以将新分支堆叠在现有分支之上,修改底层分支后上层自动 rebase,整个过程无需任何 rebase 命令:

BASH
# 创建 stack 结构
but branch -a feat/refresh-token feat/token-revocation
but branch -a feat/token-revocation feat/token-audit-log

修改底层分支的某个 commit 后,GitButler 自动级联 rebase 上层分支

无需手动执行任何 rebase 操作

推送并创建 PR

gh stack submit

GitButler 的 GUI 提供可视化的 stack 视图,可以通过拖拽在层之间移动 commit,是管理依赖性较强的多层 PR 的最低阻力路径。

4. 更适合 Agentic Coding 的 VCS 工具

上面所讨论的最佳实践,本质上是在 Git 现有约束内打补丁:通过规范、模板和 CI 来弥补工具本身的不足。但 Git 的部分局限性根植于其设计哲学,很难从外部彻底解决。

下面给大家介绍两个以不同心智模型重新设计版本控制体验的新兴工具,它们在 agentic coding 场景下更具优势。这些新工具对 Git 保持着不错的兼容性,同时 agent 也很擅长使用这些工具进行版本控制,你只需要对它们的核心概念和心智模型有一定的了解。

4.1 Jujutsu(jj):以变更为中心的版本控制

工具简介

Jujutsu(命令行工具为 jj)是由 Google 工程师 Martin von Zweigbergk 开发的版本控制系统,目前已在 Google 内部大规模使用。它以 Git 仓库作为存储后端,完全兼容 Git 生态,可以通过 jj git init --colocate 在已有 Git 仓库中启用,无需迁移。

心智模型

这张图展示了Jujutsu(jj)的心智模型,核心是说明其与Git的根本差异。图中明确标注了核心区别为“工作区即提交”,直观呈现了“Change/变更身份”是持续演化的意图单元,具有持续演化、保留历史与意图且身份稳定不变的特性;而“Commit/提交快照”是某一时刻的不可变记录,属于用于分享、审查与溯源的快照。图中以时间轴串联,清晰体现同一个Change可对应生成多个Commit的逻辑,还补充了变更的特点、Commit的用途,以及修改、检查点/审查的相关说明,完整阐释了Jujutsu以变更为中心的版本控制逻辑,与上下文里对jj核心差异的介绍形成对应,将抽象的心智模型可视化呈现。
img-145 · 这张图展示了Jujutsu(jj)的心智模型,核心是说明其与Git的根本差异。图中明确标注了核心区别为“工作区即提交”,

jj 和 Git 最根本的差异在于工作区即提交(working copy as a commit)。

在 Git 中,你需要手动 addcommit,工作区是一个独立的「暂存缓冲区」,未提交的内容随时可能丢失。在 jj 中,工作区本身始终是一个提交(标记为 @),任何文件改动都实时反映到这个提交上,永远不会丢失未保存的工作。

由此衍生出几个关键概念:

Change ID vs Commit ID:jj 为每个变更同时维护两种标识符,这是理解 jj 的关键。

用一个熟悉的类比来理解:change ID 就像 GitHub PR 的编号,commit ID 就像 PR 里每次 push 后的具体 commit SHA。当你对 PR #234 追加了新的提交,PR 编号还是 #234,但 commit SHA 已经变了。jj 用同样的逻辑管理本地变更:你可以反复修改一个变更的内容,change ID 始终是你引用它的稳定句柄。

jj log 的输出中,两种 ID 同时可见:

PLAIN TEXT
$ jj log
@  qpvuntsm 8f3a2b1c user@example.com 2025-04-27 16:42:11
│  feat(auth): implement JWT refresh token issuance
○  ywnkulko 3d91cc4a user@example.com 2025-04-27 14:10:00
│  feat(auth): add RefreshToken domain model

左侧较短的字母串(qpvuntsm)是 change ID,右侧的十六进制串(8f3a2b1c)是 commit ID。当你用 jj describe 修改提交信息或用 jj squash 整理内容后,commit ID 会变为新值,但 change ID qpvuntsm 保持不变,jj 借此追踪「这是同一个变更的新版本」并自动 rebase 所有后代,无需手动维护依赖链。

冲突是一等公民:jj 把冲突存储在提交对象中,而不是阻塞操作。jj rebase 在遇到冲突时不会中止,而是把冲突记录到提交里继续推进,你可以随时回来解决,也不需要 git rebase --continue 这类中间状态命令。

操作日志:每条 jj 命令都会在操作日志中留下记录,jj op undo 可以撤销任意操作,相当于整个工作流的无限 undo。

与 Git 的主要差异

维度

Git

Jujutsu

暂存区

有(index)

无,工作区即提交

标识符稳定性

commit hash 改写后变化

change ID 跨改写保持稳定

冲突处理

阻塞,需手动解决后 continue

冲突存入提交,不阻塞操作

历史改写

需手动 rebase 后代 commit

自动 rebase 所有后代 commit

操作撤销

reflog(有限)

完整操作日志,任意撤销

分支

必须先命名

匿名变更,按需添加 bookmark

解决的 Git 局限性

功能示例

jj log:直观的提交图

PLAIN TEXT
$ jj log
@  qpvuntsm 9c1e4f2a user@example.com 2025-04-27 16:42:11
│  (no description set)                       ← 工作区当前提交,随时可 describe
○  mrzxpkqs 7b30dc81 user@example.com 2025-04-27 15:30:00
│  feat(auth): expose POST /auth/refresh endpoint
○  ywnkulko 3d91cc4a user@example.com 2025-04-27 14:10:00
│  feat(auth): implement JWT refresh token issuance
◆  zzzzzzzz main@origin
   # ◆ 表示该提交已推送到远端,不可本地改写

jj split:将混杂的工作区拆分为独立提交

agent 常见情形:在修 bug 的同时顺手改了格式和配置,全混在一个工作区里。jj split 打开交互式 diff 编辑器,让你选择哪些 hunk 归入第一个提交,剩余的自动成为第二个:

BASH
$ jj split

交互式选择 hunk,将 bugfix 和格式化变更拆入两个独立提交

jj 自动将后代提交 rebase 到新的提交链上

jj absorb:将改动自动归并到最合适的历史提交

agent 对多个功能同时做了少量修改,散落在工作区中。jj absorb 会分析每个 hunk 的 git blame 信息,自动将其归入最合适的祖先提交,无需手动指定:

BASH
$ jj absorb

自动将 @ 中的改动分发到各个合适的祖先提交

等价于手动做多次 jj squash -i,但完全自动

jj op undo:撤销任意操作

BASH
$ jj op log

查看操作历史

@ abc123 (2025-04-27 16:45) rebase abc onto main ○ def456 (2025-04-27 16:40) squash xyz into parent ○ ghi789 (2025-04-27 16:30) describe commit "feat: add refresh token" $ jj op undo

撤销上一个操作,回到 rebase 之前的状态


4.2 GitButler:虚拟分支与并发 Agent 工作流

工具简介

GitButler 是一个构建在 Git 之上的版本控制客户端,提供桌面 GUI 和命令行工具 but。它最近获得 a16z 领投的 2200 万美元融资,明确定位为为 AI 驱动开发重新设计的版本控制界面。GitButler 不替换 Git,底层仍是标准 Git 仓库,兼容所有现有 Git 工具链。

心智模型

图片展示了GitButler的虚拟分支与并发Agent工作流。左侧是工作目录,有多个文件夹。中间是虚拟分支,每个分支有不同代码块,由Agent A、B、C分别处理。右侧是正式分支,有Stage、Review、Real branch等步骤,每个步骤对应不同意图(Intent A、B、C)。底部文字强调了无冲突并行工作、意图清晰分离、易于拖放重排、可有选择地组装等优势。该图直观呈现了GitButler工作流程,与上下文介绍的虚拟分支和Agent工作流相契合。
img-146 · 图片展示了GitButler的虚拟分支与并发Agent工作流。左侧是工作目录,有多个文件夹。中间是虚拟分支,每个分支有不

GitButler 最核心的创新是虚拟分支(Virtual Branches):多个分支可以同时处于活跃状态,共享同一个工作目录,而不需要 worktree。

传统 Git 的工作方式是「先切分支再做事」:你必须决定要在哪个分支上工作,然后 checkout,然后修改。GitButler 的工作方式是「先做事再分类」:你直接修改文件,然后将每个 hunk(代码块)分配给对应的虚拟分支。

这对 agentic coding 的意义是:多个 agent 可以同时向同一个工作目录写入,GitButler 按 hunk 粒度将变更归类到不同分支,避免了为每个 agent 单独维护 worktree 的运维负担。

与 Git 的主要差异

维度

Git

GitButler

并发分支

需要 worktree 或频繁切换

多个虚拟分支共享同一工作目录

变更归类

先切分支再修改

先修改再按 hunk 分配到分支

历史整理

git rebase -i

拖拽或 but commit,自动 rebase 上层

操作撤销

reflog(有限)

完整操作日志,but undo

Agent 集成

无原生支持

内置 hooks 和 MCP server

解决的 Git 局限性

功能示例

查看当前工作区状态(JSON 输出,适合 agent 消费)

BASH
$ but status --json
{
  "branches": [
    { "id": "fe", "name": "feat/refresh-token" },
    { "id": "do", "name": "fix/login-redirect" }
  ],
  "uncommitted": [
    { "id": "g0", "file": "src/auth/service.ts", "hunks": ["j0", "j1"] },
    { "id": "h0", "file": "src/auth/controller.ts", "hunks": ["k0"] }
  ]
}

GitButler 为每个分支、文件、hunk 生成短 ID(如 feg0j1),agent 可以直接通过这些 ID 操作,无需解析完整路径。

将特定文件/hunk 提交到指定分支

BASH
# 将 service.ts 提交到 refresh-token 分支
$ but commit fe -m "feat(auth): implement token rotation logic" --changes g0

将 controller.ts 提交到另一个分支

$ but commit do -m "fix(auth): redirect to original URL after login" --changes h0

but absorb:自动归并到最合适的提交

BASH
$ but absorb

分析每个 hunk 的上下文,自动吸收到最合适的现有提交中

类似 jj absorb,但在虚拟分支体系内操作

Stacked Branches:按依赖关系堆叠 PR

BASH
# 创建一个堆叠在 feat/refresh-token 之上的新分支
$ but branch -a feat/refresh-token feat/token-revocation

堆叠结构:

main

└── feat/refresh-token (PR #1)

└── feat/token-revocation (PR #2,依赖 PR #1)

修改底层分支时,GitButler 自动 rebase 上层所有分支,无需手动操作。

Agent Hook 集成

GitButler 提供内置 hooks,可以在 agent 工具调用前后自动触发提交管理。通过 MCP server 或者 Skill + CLI,agent 也可以直接调用 GitButler 的能力:读取当前虚拟分支状态、分配 hunk、创建提交,将 VCS 管理完全纳入 agent 的自动化流程。


4.3 工具选择建议

场景

推荐工具

理由

已有 Git 工作流,希望改善历史整理体验

Jujutsu

Git 兼容,学习曲线低,jj split / jj absorb 显著降低提交整理成本

多个 agent 并发、需要管理并行工作流

GitButler

虚拟分支原生支持多 agent 并发,无需 worktree 运维

团队规范严格,需要完整 CI/CD 集成

Git + 本文最佳实践

生态最成熟,工具链支持最完整

个人实验性项目或 solo agentic 开发

Jujutsu 或 GitButler

两者都提供比 Git 更流畅的 agentic 工作体验

值得注意的是,Jujutsu 和 GitButler 并不互斥,也不取代 Git 生态:它们都以 Git 仓库作为后端,与 GitHub、GitLab 及现有 CI/CD 管道完全兼容。在团队中,可以让更熟悉这些工具的成员选择使用,其他成员继续使用 Git,不会产生协作障碍。

5. 总结

LLM coding agent 带来的不是 git 的终结,而是对 git 使用纪律的更高要求。传统工作流中,版本控制的规范可以靠工程师的经验和团队文化来维持;在 agentic coding 中,这些规范必须被显式化、工具化、自动化,才能真正生效。

核心原则可以归纳为三点:

  1. 隔离:Branch protection + worktree,为每个 agent 任务提供独立、受保护的工作空间
  2. 透明:Atomic commit + commit trailer + PR 模板,让 agent 的决策过程在版本历史中可见
  3. 自动化:CI guardrails + branch protection required checks,用工具而非人工来守住质量底线

随着 agentic coding 工具的快速演进,具体的最佳实践也会持续更新,但「让版本历史成为可信的知识库」这一核心目标不会改变,无论代码是人写的还是 agent 写的。

如果你觉得本文不错,欢迎大家点赞、在看、转发三连呀!如果你想第一时间收到我们的最佳实践推送,可以给账号点个星标 ~