萬字乾貨|AI 時代的 Git 版本管理,你用對了嗎?
整理版優先睇
呢篇文章講 AI Agent 時代 Git 面臨嘅挑戰同埋一套完整嘅最佳實踐,從 Commit 規範到新工具選擇,幫助團隊應對 Agent 帶嚟嘅版本管理痛點。
本文由 TRAE 技術專家小夏撰寫,探討 AI Agent 時代 Git 版本管理嘅新挑戰。佢指出,傳統 Git 假設開發者係「有意圖嘅決策單元」,但 agent 可以自主執行、併發協作,導致巨型 commit、意圖丟失、工作區混亂同語義合併錯誤等問題。作者嘅整體結論係:Agent 並唔會終結 Git,但要求我哋將規範顯式化、工具化、自動化。
佢提出一系列最佳實踐,包括建立 Agent-Aware Commit 規範(使用 Git Trailer 記錄任務 ID、模型等)、小步提交策略(Checkpoint Commit)、用 Interactive Rebase 整理歷史、Atomic Commit 原則、強制 Feature Branch、用 git worktree 隔離併發 Agent、結構化 PR 模板、維護 AGENT.md、建立可追溯性鏈路,同埋 Monorepo 同 Stacked PR 嘅建議。
最後佢介紹咗兩個新工具:Jujutsu(jj)同 GitButler。jj 以「變更」為核心,工作區即提交,提供 change ID 穩定引用、自動 rebase、split/absorb 等能力;GitButler 引入「虛擬分支」,允許多個 agent 同時修改同一工作目錄,按 hunk 分配變更,自然解決髒工作區問題。兩個工具都兼容 Git 生態,可逐步引入。
- Agent 嘅自主執行同併發協作令 Git 傳統工作流失效,核心痛點包括巨型 commit、意圖丟失、工作區混亂同語義合併錯誤。
- 建立 Agent-Aware Commit 規範,喺 commit message 加入 Git Trailer(Agent-Task、Agent-Model、Agent-Decision、Agent-Limitation),保留推理上下文。
- 小步提交(Checkpoint Commit)同 Interactive Rebase 係對抗巨型 commit 嘅關鍵,長任務中應喺關鍵節點提交 [WIP] commit,最終整理為語義清晰嘅 atomic commit。
- Atomic Commit 要求每個 commit 只表達一個可驗證嘅語義變化,並保持編譯通過、測試通過,方便回滾同 bisect。
- 新工具 jj 同 GitButler 以不同心智模型解決 Git 侷限:jj 用 change ID 穩定追蹤變更,GitButler 用虛擬分支隔離併發 agent,兩者均兼容 Git 生態。
整理提交歷史嘅 prompt
請幫我整理當前分支相對於 main 嘅提交歷史,準備開 PR。步驟:1. 運行 git log --oneline main..HEAD 查看當前所有提交;2. 分析哪些提交屬於同一個邏輯變更;3. 俾我一份整理方案;4. 等我確認後執行 git rebase -i main;5. 展示最終結果。要求每個保留 commit 需符合 Conventional Commits 格式,並包含 Agent-Task、Agent-Decision trailer。
AGENT.md 範本(Git 相關部分)
包含 Branch Naming、Commit Guidelines、PR Process、What NOT to Commit、Checkpoint Commits 等規範,可放入倉庫根目錄俾 agent 閲讀。
Atomic Commit 實踐指南
以 refresh token 功能為例,好的切分係每個 commit 對應一個獨立關注點(domain model、service、endpoint、test),反例係所有改動壓成一個 commit。
Agent 帶嚟嘅 Git 挑戰
傳統 Git 假設開發者係「一個有意圖嘅決策單元」,但 agentic coding 打破咗呢個假設:自主執行、併發協作、任務粒度不匹配同決策黑盒。呢啲特徵令傳統 Git 工作流難以應對。
核心痛點包括:巨型單一 commit(diff 動輒數千行)、無意義碎片 commit(流水賬式歷史)、髒工作區(格式噪聲、誤刪文件)、語義合併錯誤(無文本衝突但運行時錯誤)。
巨型提交令審查、回滾同 git bisect 全部失效,因為 commit 內部係大雜燴,根因難以定位。
最佳實踐:規範與流程
建立 Agent-Aware Commit 規範,使用 Git Trailer 記錄Agent-Task、Agent-Model、Agent-Decision同Agent-Limitation,保留推理上下文。
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
小步提交策略:喺長任務嘅關鍵節點進行Checkpoint Commit,以 [WIP] 開頭,最終用 interactive rebase 整理。
- 完成數據模型/接口定義
- 完成核心邏輯實現
- 完成測試編寫
- 完成文檔更新
用 Interactive Rebase 整理歷史:將 checkpoint commits 合併(squash)為有意義嘅語義 commit,修改 message(reword),最終每個 commit 可獨立理解。
請幫我整理當前分支相對於 main 嘅提交歷史,準備開 PR。
步驟:
1. 運行 git log --oneline main..HEAD 查看當前所有提交
2. 分析哪些提交屬於同一個邏輯變更
3. 俾我一份整理方案(squash、保留、message 改乜)
4. 等我確認後執行 git rebase -i main
5. 展示最終結果
要求每個保留 commit 需符合 Conventional Commits 格式,並包含 Agent-Task、Agent-Decision trailer。
強制使用Feature Branch,禁止直接 push main;用 git worktree 隔離併發 agent,每個 agent 有獨立工作目錄。
設計結構化 PR 模板,要求 agent 填寫 Task Description、Key Design Decisions、Test Coverage 等;維護 AGENT.md 作為 agent 行為規範,涵蓋分支命名、commit 規範、PR 流程。
進階:Monorepo 與 Stacked PR
Monorepo 更適合 agent,提供完整嘅跨服務上下文,agent 可一次追蹤 UI 到數據庫嘅完整鏈路;依賴圖可見性幫助精確運行受影響嘅測試。
Monorepo 挑戰:衝突風險高(公共文件如 package.json)、PR diff 容易變大、CI 範圍界定。解決方案:git worktree 或 GitButler 虛擬分支隔離 agent;Stacked PR 將大任務拆成層疊單元。
- gh-stack:GitHub 原生功能,提供 Stack Navigator、聚焦 diff、按層 CI。
- Jujutsu:提交鏈天然係 stacked PR 工作單元,jj git push --all 後 gh stack submit 即可。
- GitButler:Stacked Branches 係核心功能,修改底層後自動級聯 rebase,GUI 可拖拽移動 commit。
新工具:jj 與 GitButler
Jujutsu(jj)以「變更」為核心,工作區即提交(working copy as a commit),永遠唔會丟失未保存工作。關鍵概念:Change ID 穩定不變,Commit ID 隨內容變化,類似 PR 編號 vs commit SHA。
$ 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
其他功能:jj absorb 自動將改動歸併到最合適嘅祖先 commit;jj op undo 可撤銷任意操作。
GitButler 引入「虛擬分支(Virtual Branches)」,允許多個 agent 同時修改同一工作目錄,按 hunk 分配變更。先做事再分類,避免為每個 agent 維護 worktree。
{
"branches": [
{ "id": "fe", "name": "feat/refresh-token" },
{ "id": "do", "name": "fix/login-redirect" }
],
"uncommitted": [
{ "id": "g0", "file": "src/auth/service.ts", "hunks": ["j0", "j1"] }
]
}
功能包括:but commit 將特定文件/hunk 提交到指定分支;but absorb 自動歸併;Stacked Branches 按依賴堆疊 PR,修改底層後自動 rebase 上層。
兩個工具都兼容 Git 生態,可與 GitHub、GitLab 及現有 CI/CD 管道協作,團隊成員可選擇使用,唔會產生協作障礙。


前言|新範式下 Agent 如何參與開發
在傳統開發中,git 的工作單元是「一個開發者的一次有意圖的決策」,但是 Agentic coding 打破了這個假設:
自主執行:agent 可以在無人監督的情況下連續修改數十個文件,跨越數分鐘到數小時
併發協作:多個 agent 實例可以同時在同一個 repo 中工作
任務粒度不匹配:一個自然語言描述的任務可能對應上百次文件操作,agent 對如何切分 commit 沒有天然感知
決策黑盒:agent 的中間推理過程不會留在 git 歷史中,只有最終代碼變更可見
以上這些特徵催生了一系列傳統 Git 工作流難以應對的新挑戰。那我們應該如何應對這些調整,我們將從核心痛點出發,為大家推薦更好的實踐技巧。

核心痛點
2.1 Git 只記錄 diff,不記錄意圖與推理過程

Git commit 可以精確告訴你「改了什麼」,卻很難說清 agent 為什麼這樣改、它依據了哪個 prompt、是否誤解了需求。傳統開發中,commit message 往往能補充一部分上下文;但 agent 的執行過程完全不同:它可能跨多個模塊探索、試錯、改寫、回滾,最終留下一個看似合理但意圖不清的 diff。
這帶來的典型問題是:PR 看起來完整,實際解決的卻是一些相關的問題而非原始需求;或者 agent 在修 bug 時順手重構、改依賴、改配置,導致 reviewer 很難判斷哪些變更是必要的,哪些只是副作用。
Agent 傾向於產生兩種極端的提交模式,進一步加劇了這一問題:
巨型單一 commit:將整個任務的所有修改壓成一個 commit,diff 動輒數千行,code review 形同虛設
無意義碎片 commit:為每一步操作單獨提交,歷史變成流水賬(fix typo、update file、try again),失去語義
「為什麼這樣做」「權衡了哪些方案」「有哪些已知限制」,這些對未來維護至關重要的信息,agent 不會主動寫進提交歷史。
2.2 髒工作區難以管控,變更噪聲大

Agent 的探索過程比人類更快、更分散,很容易造成工作區混亂。未提交的臨時文件、格式化變更、測試 fixture 和真實業務修改混在一起,髒工作區(dirty worktree)一旦累積,審查和回滾都會變得困難。
常見問題包括:
Agent 覆蓋了開發者尚未提交的本地 WIP
git diff 裏混入格式化、依賴鎖文件、生成代碼等噪聲,掩蓋真實變更
Agent 誤刪文件,或將臨時調試代碼提交進去
多個 agent 在同一 working tree 裏互相踩到對方的改動
無意中將 API key、數據庫連接串等敏感信息寫入代碼並提交
2.3 Git merge 只是文本校驗,但不保證語義正確

LLM agent 會做跨文件、跨抽象層的修改。Git 的 merge 機制是文本層面的:只要沒有行級衝突,就認為合併成功。但「無衝突合併」並不等於「語義正確」。
典型場景是:一個 agent 修改了某個接口的語義,另一個 agent 同時在舊語義下新增了調用點。兩個 branch 各自通過測試,合併時也沒有衝突,但運行時行為已經被破壞。多 agent 併發時,這種問題還會因為彼此不瞭解對方的修改意圖而加劇:
Agent 不理解「代碼所有權」,不會像人類一樣在動公共模塊前先溝通
自動衝突解決(auto-merge)可能悄悄引入語義錯誤,沒有測試覆蓋時很難發現
不能把「分支能 merge」等同於「可以發佈」,這一點在 agent 併發開發場景中尤為重要。
2.4 巨型提交讓審查、回滾與定位全部失效

Agent 一次性產出「巨型 diff」是最常見的問題之一:功能實現、測試、重構、格式化、文檔、依賴升級全混在一起,幾十個文件同時改動。這會導致一系列連鎖問題:
審查者無法快速判斷每個變更是否必要,review 質量隨 diff 體量的增大急劇下降
出問題時 git revert 會撤掉太多無關改動,修復成本高
git bisect 找到問題 commit 後,commit 的內部仍然是個大雜燴,根因難以定位
Agent 後續修錯時又在原有基礎上疊加更多噪音,形成惡性循環
git bisect 的價值在於用二分搜索快速找到引入問題的提交節點,但如果每個 commit 本身都包含大量無關變更,即便定位到了問題 commit,排查工作仍然沒有徹底完成。

最佳實踐
3.1 建立 Agent-Aware 的 Commit 規範

核心原則:每個 commit 應當能獨立描述「做了什麼、為什麼、上下文是什麼」。
推薦的 commit message 格式:
<type>(<scope>): <summary>
<正文:描述本次變更的背景與動機>
Agent-Task: <原始任務描述或任務 ID>
Agent-Model: <使用的模型,如 gpt-4o、gemini-2.5-pro>
Agent-Decision: <關鍵設計決策及理由>
Agent-Limitation: <已知侷限或後續 TODO>示例:
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 的先例,例如:
Signed-off-by: Alice <alice@example.com>
Co-authored-by: Bob <bob@example.com>
Fixes: #1234你可以用標準 git 命令查詢 trailer:
# 列出所有包含 Agent-Task trailer 的提交
git log --format='%(trailers:key=Agent-Task,valueonly)'
# 按 trailer 過濾提交歷史
git log --grep="^Agent-Task:" --all工程實施建議:
在 agent 的系統提示(system prompt)或 AGENT.md 中明確要求上述格式
使用 commit-msg hook 校驗 agent commit 是否包含必要的 trailer 字段
用類型前綴區分來源:feat / fix / refactor 等遵循 Conventional Commits,agent 生成的提交可額外加 [AI] 標籤便於過濾
3.2 小步提交:Checkpoint Commit 策略

對於耗時較長的 agent 任務,應要求 agent 在關鍵節點進行「檢查點提交」,而不是等任務全部完成再提交。
指令示例:
在完成以下關鍵節點時,執行一次 git commit:
1. 完成數據模型/接口定義
2. 完成核心邏輯實現
3. 完成測試編寫
4. 完成文檔更新
每個 checkpoint commit 的 message 以 [WIP] 開頭,最終完成後執行 git commit --amend 或通過 rebase 整理歷史。好處:
任務中斷時可以從最近的 checkpoint 恢復,而非從頭開始
Checkpoint commit 天然成為 code review 的切分點,reviewer 可以分段審查
便於 git bisect 定位引入問題的具體階段
3.3 使用 Interactive Rebase 整理 Agent 歷史

Agent 工作完成後,在合併前對 branch 歷史進行整理是一個良好習慣。
# 查看當前 branch 的提交歷史
git log --oneline main..HEAD
# 交互式 rebase 整理最近 N 個提交
git rebase -i main
# 常用操作:
# pick - 保留該提交
# squash/s - 合併到上一個提交
# reword/r - 修改 commit message
# drop/d - 刪除該提交
# fixup/f - 合併到上一個提交,丟棄本提交 message建議的整理策略:
將 [WIP] checkpoint commits 合併(squash)為有意義的語義 commit
確保最終歷史中每個 commit 都能獨立理解和回滾
不要對已經推送到遠程的分支做 force push(除非團隊有明確約定)
讓 Agent 輔助完成歷史整理
整理提交歷史這件事本身也可以交給 agent 來做,以下是一個簡潔的 prompt,可以在任務完成後直接發給 agent:
請幫我整理當前分支相對於 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:以原子粒度組織變更

Atomic commit 的核心定義是:一個 commit 只表達一個可解釋、可回滾、可驗證的語義變化,且在該 commit 節點上代碼可以編譯、測試可以通過。這一原則在人工開發中已被廣泛推崇,在 agentic coding 中更顯關鍵。
為什麼 agent 場景更需要 atomic commit:
Agent 執行長任務時,往往將多個不相關的修改混入同一次提交,atomic commit 是對抗這種熵增的直接手段
保持每個 commit 可獨立回滾,是降低 agent 引入問題時修復成本的核心保障
Reviewer 可以按 commit 逐步理解變更,而不必面對一個包含所有修改的巨型 diff
git bisect 的定位精度直接取決於每個 commit 的粒度,atomic commit 讓二分搜索真正有效
實踐指南:
這裏的 atomic 不是「一行一提交」,而是按邏輯關注點切分。以 refresh token 功能為例:
# 好的切分:每個 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而不是:
# 反例:所有改動壓成一個 commit
feat(auth): implement refresh token在系統提示中引導 agent 遵守 atomic commit:
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。
分支命名規範:
agent/<task-id>-<brief-description>
# 示例
agent/PROJ-234-refresh-token-rotation
agent/PROJ-301-migrate-postgres-schema配置 branch protection rules(以 GitHub 為例):
- 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 和指定人員
操作規範:
Agent 每次執行新任務前,從最新的 main 切出新分支
任務完成後由 agent 開 PR,但 merge 動作由人工觸發
避免在同一分支上執行多個不相關的 agent 任務
3.6 使用 git worktree 隔離併發 Agent

當多個 agent 並行工作時,git worktree 是比多個 clone 更輕量的隔離手段。每個 agent 獲得獨立的工作目錄,髒工作區的問題被天然隔離,同時所有 worktree 共享同一個 .git 目錄,分支管理統一。
# 為每個 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 有獨立的工作目錄,不會相互干擾工作區狀態
共享同一個 .git 目錄,分支管理統一,無需多次 clone
與 CI/CD 結合時,可以為每個 worktree 獨立運行測試
在多 agent 編排腳本中,為每個子任務指定工作目錄參數指向對應 worktree 路徑,確保 agent 的文件操作被限制在隔離目錄內。
3.7 結構化 PR 模板,補充 Agent 上下文
PR 是人機交接的關鍵界面。應為 agent 生成的 PR 設計專用模板,要求其填寫人類 reviewer 需要的上下文。
.github/pull_request_template/agent.md 示例:
## 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 重點關注的部分 -->工程實施建議:
在 AGENT.md 或 agent 系統提示中要求 agent 開 PR 時使用此模板並認真填寫
使用 GitHub Actions 校驗 PR description 是否包含必要章節(可用簡單的正則檢查)
3.8 維護 AGENT.md:Agent 的「團隊規範手冊」

AGENT.md是 agent 的行為規範入口,應當包含所有 VCS 相關約定。將規範寫入 AGENT.md,agent 在每次任務開始時都會讀取並遵循,是讓團隊規範真正生效的最低成本方式。
推薦包含的 Git 相關內容:
## 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 PR3.9 建立 Agent 任務的可追溯性鏈路

當出現問題時,需要能夠追溯「是哪個任務、用什麼 prompt、在什麼時候」產生了這段代碼。
追溯鏈路設計:
任務系統(Jira/Linear)
↓ task-id
Git Branch / PR
↓ commit message 中的 Agent-Task trailer
Agent Session Log(可選:存儲在 .agent-logs/ 目錄,加入 .gitignore)
↓ 包含完整的 prompt 和 agent reasoning
代碼變更實踐建議:
在任務管理系統中為 agent 任務打標籤(如 ai-generated),便於統計和追蹤
對於高風險變更(核心業務邏輯、安全相關代碼),在 PR 中附上關鍵的 agent 推理過程截圖或摘要
定期審計 git log --grep="^Agent-Task:" 的產出,評估 agent 任務的質量趨勢
現有工具
上述鏈路目前需要靠規範和手動維護來保證,已有一些專門針對這一痛點的產品出現:
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

為什麼 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 在本地運行:
### CI Commands for Agents
# 只運行受當前變更影響的 package 的測試(需要 Nx 或 Turborepo)
nx affected --target=test
turbo run test --filter='[HEAD^1]'
# 全量檢查(在 PR 合併前由 CI 執行,不建議 agent 本地全量運行)
# npm run test:allAtomic commit 的邊界:在 monorepo 中,atomic commit 的「一件事」需要更明確的定義。修改共享 library 的同時必須同步更新消費方,這算一個 commit 還是多個?推薦的做法是:一個 commit 表達一個完整的語義變化,即使它涉及多個 package,只要這些修改在邏輯上是不可分割的(例如接口變更加上對應的調用方更新),就可以放在同一個 commit 中。
3.11 Stacked PR:將大任務拆解為可審查的層疊單元

問題背景
Agent 往往能在一次任務中完成數量可觀的工作:實現新接口、補充測試、更新文檔、升級依賴,這些變更從語義上屬於不同關注點,卻全部堆進同一個 PR。巨型 PR 的審查質量很低,而簡單地「多拆幾個 PR」又面臨依賴管理的麻煩:PR B 依賴 PR A,PR A 還沒合併,reviewer 需要同時理解兩個 PR 的上下文。
Stacked PR(堆疊 PR)是解決這一矛盾的工作流:每個 PR 針對前一個 PR 的分支而非 main,形成有序的依賴鏈。每層 PR 只展示當前層的 diff,reviewer 可以獨立審查每一層,合併時按順序從底部開始依次合入。
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 testsGitHub Stacked PRs(gh-stack)
GitHub 正在以 gh-stack 的形式將 Stacked PR 作為原生特性引入(目前處於 private preview)。它的核心體驗包括:
PR 頭部的 Stack Navigator:reviewer 可以在 PR 頁面直接看到整條依賴鏈,並在各層之間跳轉
聚焦 diff:每個 PR 只展示本層相對於下一層的變更,不包含下層的內容
按層運行 CI:每個 PR 的 CI 針對其實際目標分支運行,而非全量
一鍵合併整個 stack:從最底層開始按序合併,所有 PR 的 branch protection 規則均被獨立校驗
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 自動更新:
# 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 命令:
# 創建 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 submitGitButler 的 GUI 提供可視化的 stack 視圖,可以通過拖拽在層之間移動 commit,是管理依賴性較強的多層 PR 的最低阻力路徑。

更適合 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 倉庫中啓用,無需遷移。
心智模型

jj 和 Git 最根本的差異在於工作區即提交(working copy as a commit)。
在 Git 中,你需要手動 add 再 commit,工作區是一個獨立的「暫存緩衝區」,未提交的內容隨時可能丟失。在 jj 中,工作區本身始終是一個提交(標記為 @),任何文件改動都實時反映到這個提交上,永遠不會丟失未保存的工作。
由此衍生出幾個關鍵概念:
Change ID vs Commit ID:jj 為每個變更同時維護兩種標識符,這是理解 jj 的關鍵。
Commit ID:內容哈希,與 Git 的 commit hash 相同。只要內容有任何改動,哈希就會變化——git commit --amend 之後你會得到一個全新的 commit hash,原來的 hash 就消失了。
Change ID:穩定的字母標識符(如 qpvuntsm)。無論你修改這個變更多少次,change ID 始終不變。
用一個熟悉的類比來理解:change ID 就像 GitHub PR 的編號,commit ID 就像 PR 裏每次 push 後的具體 commit SHA。當你對 PR #234 追加了新的提交,PR 編號還是 #234,但 commit SHA 已經變了。jj 用同樣的邏輯管理本地變更:你可以反覆修改一個變更的內容,change ID 始終是你引用它的穩定句柄。
在 jj log 的輸出中,兩種 ID 同時可見:
$ jj log
@ qpvuntsm 8f3a2b1c user@example.com 2025-04-2716:42:11
│ feat(auth): implement JWT refresh token issuance
○ ywnkulko 3d91cc4a user@example.com 2025-04-2714: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 侷限性
髒工作區問題:工作區始終是已提交狀態,agent 的探索過程被自動記錄,不存在「未提交的臨時文件」丟失的風險
巨型提交難以拆分:jj split 和 jj absorb 讓拆分和重新歸類變更變得極其低成本
歷史改寫的連鎖代價:自動 rebase 後代,agent 修改任意歷史提交不再需要手動維護提交鏈
功能示例
jj log:直觀的提交圖
$ jj log
@ qpvuntsm 9c1e4f2a user@example.com 2025-04-2716:42:11
│ (no description set) ← 工作區當前提交,隨時可 describe
○ mrzxpkqs 7b30dc81 user@example.com 2025-04-2715:30:00
│ feat(auth): expose POST /auth/refresh endpoint
○ ywnkulko 3d91cc4a user@example.com 2025-04-2714:10:00
│ feat(auth): implement JWT refresh token issuance
◆ zzzzzzzz main@origin
# ◆ 表示該提交已推送到遠端,不可本地改寫jj split:將混雜的工作區拆分為獨立提交
agent 常見情形:在修 bug 的同時順手改了格式和配置,全混在一個工作區裏。jj split 打開交互式 diff 編輯器,讓你選擇哪些 hunk 歸入第一個提交,剩餘的自動成為第二個:
$ jj split
# 交互式選擇 hunk,將 bugfix 和格式化變更拆入兩個獨立提交
# jj 自動將後代提交 rebase 到新的提交鏈上jj absorb:將改動自動歸併到最合適的歷史提交
agent 對多個功能同時做了少量修改,散落在工作區中。jj absorb 會分析每個 hunk 的 git blame 信息,自動將其歸入最合適的祖先提交,無需手動指定:
$ jj absorb
# 自動將 @ 中的改動分發到各個合適的祖先提交
# 等價於手動做多次 jj squash -i,但完全自動jj op undo:撤銷任意操作
$ jj op log
# 查看操作歷史
@ abc123 (2025-04-2716:45) rebase abc onto main
○ def456 (2025-04-2716:40) squash xyz into parent
○ ghi789 (2025-04-2716: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 最核心的創新是虛擬分支(Virtual Branches):多個分支可以同時處於活躍狀態,共享同一個工作目錄,而不需要 worktree。
傳統 Git 的工作方式是「先切分支再做事」:你必須決定要在哪個分支上工作,然後 checkout,然後修改。GitButler 的工作方式是「先做事再分類」:你直接修改文件,然後將每個 hunk(代碼塊)分配給對應的虛擬分支。
這對 agentic coding 的意義是:多個 agent 可以同時向同一個工作目錄寫入,GitButler 按 hunk 粒度將變更歸類到不同分支,避免了為每個 agent 單獨維護 worktree 的運維負擔。
與 Git 的主要差異

解決的 Git 侷限性
髒工作區難以管控:虛擬分支讓不同關注點的變更在同一工作目錄中保持分離,git diff 中的噪聲問題從根源上被消除
多 agent 併發衝突:每個 agent 會話綁定一個虛擬分支,互斥的 hunk 自動歸類,無需 worktree 隔離
大提交審查困難:hunk 級別的分配機制天然產生小而聚焦的提交,stacked branches 支持按依賴關係拆分 PR
功能示例
查看當前工作區狀態(JSON 輸出,適合 agent 消費)
$ 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(如 fe、g0、j1),agent 可以直接通過這些 ID 操作,無需解析完整路徑。
將特定文件/hunk 提交到指定分支
# 將 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 h0but absorb:自動歸併到最合適的提交
$ but absorb
# 分析每個 hunk 的上下文,自動吸收到最合適的現有提交中
# 類似 jj absorb,但在虛擬分支體系內操作Stacked Branches:按依賴關係堆疊 PR
# 創建一個堆疊在 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 工具選擇建議

值得注意的是,Jujutsu 和 GitButler 並不互斥,也不取代 Git 生態:它們都以 Git 倉庫作為後端,與 GitHub、GitLab 及現有 CI/CD 管道完全兼容。在團隊中,可以讓更熟悉這些工具的成員選擇使用,其他成員繼續使用 Git,不會產生協作障礙。

總結
LLM coding agent 帶來的不是 git 的終結,而是對 git 使用紀律的更高要求。傳統工作流中,版本控制的規範可以靠工程師的經驗和團隊文化來維持;在 agentic coding 中,這些規範必須被顯式化、工具化、自動化,才能真正生效。
核心原則可以歸納為三點:
隔離:Branch protection + worktree,為每個 agent 任務提供獨立、受保護的工作空間
透明:Atomic commit + commit trailer + PR 模板,讓 agent 的決策過程在版本歷史中可見
自動化:CI guardrails + branch protection required checks,用工具而非人工來守住質量底線
隨着 agentic coding 工具的快速演進,具體的最佳實踐也會持續更新,但「讓版本歷史成為可信的知識庫」這一核心目標不會改變,無論代碼是人寫的還是 agent 寫的。
如果你覺得本文不錯,歡迎大家點贊、在看、轉發三連呀!如果你想第一時間收到我們的最佳實踐推送,可以給賬號點個星標 🌟 ~
