Một buổi deploy lớn luôn có nhiều thứ xảy ra cùng lúc. Main session đang tail container log. Bạn đang edit .env.production để chuẩn bị restart. Có một script đang được scp lên server. Container state đang được poll.

Rồi bạn phát hiện một Dockerfile có typo. Một compose file thiếu env var. Nhỏ thôi, fix một lúc xong. Nhưng để fix, bạn phải checkout sang branch hotfix.

Và checkout sẽ reset working tree. Log tail mất, .env.production đang edit dở reset về HEAD, script scp đang xếp hàng bị orphan. Phải mất 15-30 phút để recover toàn bộ về trạng thái trước.

Bài này giải thích tại sao đây là thời điểm đúng để dùng worktree agent, và cho thấy chính xác cách flow đó hoạt động.

Bức tranh trước khi có hotfix

Hãy hình dung buổi deploy một service production. Main session của bạn đang:

Main session (branch: main)
├── terminal tab 1: tail -f /var/log/container/service-a.log
├── terminal tab 2: edit .env.production  <-- đang sửa dở
├── terminal tab 3: scp -i key tmp-fix.sh user@prod-server:/tmp/
└── terminal tab 4: watch -n 3 "docker ps --filter name=service-a"

Không có gì trong số này được commit. Đây là scratch state, ephemeral, sống trong working tree và trong terminal process. Không thể “save and restore” kiểu git stash đơn thuần vì git stash không stash được log tail hay scp process.

Bạn phát hiện trong Dockerfile:

# BEFORE (typo)
COPY srcc/ /app/src/

# SHOULD BE
COPY src/ /app/src/

Nhỏ. Một ký tự. Nhưng fix nó đúng cách yêu cầu một commit trên branch riêng, CI chạy, PR review, merge.

Option A và option B: tại sao cả hai đều sai

Option A: fix trực tiếp trong main session. Bạn git checkout -b hotfix/dockerfile-typo, sửa, commit, push, PR. Vấn đề: git checkout reset working tree. .env.production đang edit dở trở về state của HEAD. Script scp mất context. Log tail không biết bạn vừa đổi branch.

Option B: spawn no-isolation agent (không dùng worktree, agent edit trực tiếp trên branch hiện tại). Agent sửa Dockerfile trên branch main. Không có branch riêng, không có PR, không có CI gate. Không phù hợp khi code này cần review trước khi deploy.

Cả hai option đều phá scratch state hoặc bỏ qua quy trình review.

Option C: worktree agent

Worktree agent giải quyết cả hai vấn đề cùng lúc. Về cơ chế worktree, xem bài 17. Về các spawning pattern, xem bài 16.

Tóm tắt nhanh: khi spawn agent với isolation: "worktree", binary tạo một git worktree riêng (thư mục riêng, branch riêng) dựa trên HEAD hiện tại của main session. Agent làm việc trong thư mục đó, không đụng đến working tree của main session.

Main session không hề biết agent đang sửa gì, và không bị ảnh hưởng gì.

Main session                     Worktree agent
branch: main                     branch: worktree/dockerfile-fix
working-tree: .env.production     working-tree: riêng, độc lập
log-tail: running                 không liên quan
scp: running                      không liên quan
│                                │
│                                │  edit Dockerfile
│                                │  git add, commit
│                                │  git push
│                                │  gh pr create
│                                ▼
│                             PR #42 opened

▼  (khi sẵn sàng)
gh pr merge 42 --squash
git pull --ff-only origin main

Main session vẫn ở branch main, scratch state nguyên vẹn.

Cách spawn trong thực tế

Từ main session, bạn spawn agent theo dạng này:

Spawn agent với isolation: worktree
Task: fix Dockerfile typo trong file Dockerfile ở root project
Cụ thể: dòng "COPY srcc/ /app/src/" phải sửa thành "COPY src/ /app/src/"
Target branch để PR vào: main
Sau khi fix: commit, push, mở PR về main. Không merge, không delete branch.

Agent nhận task, binary tạo worktree mới, agent làm việc trong đó. Bạn quay lại main session và tiếp tục monitor production.

Hai hotfix song song

Deploy lớn thường có nhiều vấn đề nhỏ xuất hiện cùng lúc. Nếu ngoài Dockerfile typo còn có một compose file thiếu env var, bạn có thể spawn hai worktree agent song song:

Agent A (worktree/dockerfile-fix):
  Fix: COPY srcc/ -> COPY src/ trong Dockerfile

Agent B (worktree/compose-env-fix):
  Fix: thêm DATABASE_URL vào docker-compose.yml service section

Hai agent chạy song song, hai worktree độc lập, hai PR riêng. Main session không bị block bởi bất kỳ agent nào.

Main session (monitor prod)
├── Agent A  -->  PR #42: fix Dockerfile typo
└── Agent B  -->  PR #43: add DATABASE_URL to compose

Khi cả hai agent báo xong, bạn merge theo thứ tự:

gh pr merge 42 --squash
git pull --ff-only origin main

gh pr merge 43 --squash
git pull --ff-only origin main

Main session vẫn ở branch main xuyên suốt. Mỗi git pull --ff-only chỉ bring commit mới vào, không switch branch, không reset working tree.

Integration: merge từ main session mà không switch branch

Đây là điểm quan trọng nhất của pattern này. Khi merge, bạn không bao giờ git checkout sang worktree branch trong main session.

Đúng:

# Từ main, merge qua cloud PR
gh pr merge 42 --squash
git pull --ff-only origin main   # bring the squashed commit into main

Sai:

# KHÔNG làm thế này
git checkout worktree/dockerfile-fix
git log   # explore agent's work
git checkout main
git merge worktree/dockerfile-fix

Lý do: ngay khi bạn git checkout worktree/dockerfile-fix trong main session, working tree reset theo branch đó. .env.production đang edit của bạn bị overwrite bởi version ở HEAD của branch kia. Đây chính xác là vấn đề bạn đang cố tránh.

Review agent’s work trước khi merge

Bạn vẫn review được mà không cần switch branch. Hai cách:

1. Xem PR diff trên GitHub:

gh pr view 42 --web   # mở browser, xem diff trực tiếp

2. Fetch và diff locally mà không checkout:

git fetch origin worktree/dockerfile-fix
git diff main...origin/worktree/dockerfile-fix

git diff main...origin/worktree/dockerfile-fix so sánh diff mà không thay đổi HEAD hay working tree của main session. Xem xong, nếu ổn:

gh pr merge 42 --squash
git pull --ff-only origin main

Bài học từ một buổi deploy

Incident pattern phổ biến trông như thế này: một deploy wave lớn, main session đang monitor production với nhiều scratch state đang chạy. Phát hiện hai vấn đề cùng lúc: một Dockerfile nhỏ cần sửa và một compose file thiếu biến.

Thay vì dùng worktree agent, main session checkout hai lần. Mỗi lần checkout reset working tree, .env.production đang edit bị mất, script scp bị orphan. Hai lần như vậy, cộng lại mất gần 30 phút chỉ để recover về trạng thái trước, trước khi thực sự bắt đầu debug vấn đề thật.

Worktree agent là pattern đúng. Main session delegate cả hai fix cho hai agent song song, tiếp tục monitor, merge khi xong. Tổng thời gian overhead: khoảng 5 phút, chủ yếu là thời gian CI chạy.

Anti-pattern cần ghi nhớ

PatternVấn đề
git checkout trong main sessionReset working tree, mất scratch state
No-isolation agent sửa trên main branchKhông có PR, không có CI gate, không có review
Merge trực tiếp từ main session bằng git merge worktree/...Không có audit trail, bypass CI/CD
Spawn agent dontAsk / bypassPermissionsCực kỳ nguy hiểm, không bao giờ làm

Khi nào dùng worktree agent vs. khi nào không cần

Worktree agent có overhead: tạo worktree, CI chạy, PR review. Với hotfix một dòng trong buổi deploy khẩn, overhead đó xứng đáng vì bảo vệ scratch state của main session và đảm bảo review gate trước khi code vào main.

Nhưng không phải lúc nào cũng cần. Nếu main session đang rảnh (không có scratch state nào đáng lo), chỉ có một file nhỏ cần sửa, không cần PR, thì fix trực tiếp trong main session là ổn (option A đúng trong điều kiện đó).

Quyết định là: main session đang giữ scratch state không thể recover dễ không? Nếu có, dùng worktree agent. Nếu không, checkout thẳng là fine.

Có scratch state quan trọng?
├── Có  -->  worktree agent
└── Không
    ├── Cần PR/CI gate?
    │   ├── Có  -->  worktree agent
    │   └── Không  -->  fix trực tiếp trong main session

Tóm tắt và bài tiếp theo

  • Khi main session đang giữ scratch state (log tail, file đang edit, process đang chạy), bất kỳ git checkout nào cũng là rủi ro. Worktree agent tránh hoàn toàn vấn đề này.
  • Spawn worktree agent với task rõ ràng, agent tự tạo branch riêng, commit, push, mở PR. Main session không bị block và không bị ảnh hưởng.
  • Hai hotfix song song: hai worktree agent, hai PR, merge theo thứ tự từ main session bằng gh pr mergegit pull --ff-only.
  • Không bao giờ git checkout sang worktree branch trong main session. Xem diff qua gh pr view --web hoặc git diff main...origin/branch.

Bài 22 sẽ đi sang một use case khác của worktree nhưng ở cấp config: branch-per-machine, cách đồng bộ ~/.claude/ giữa các máy mà không conflict state của từng máy.

Liên quan: skill nf-agents handle case workflow này qua solo mode (single agent + worktree, không cần team registry). Pre-flight check cũng catch case bạn quên WorktreeCreate hook trước khi spawn.


Bài thuộc series Claude Code từ zero. Series plan tại bài giới thiệu.