Tạo Claude Code Skill tự động Cherry-Pick Deploy lên Production theo Ticket

Nếu bạn đang làm việc trong một team có quy trình deploy theo từng ticket — nghĩa là không phải merge cả branch mà phải chọn lọc commit nào được lên production — thì hẳn bạn đã quen với cảnh này: mở git log, grep commit, cherry-pick từng cái, gặp conflict ngồi giải quyết, push, rồi báo cáo lại. Làm đi làm lại mỗi sprint.

Bài này sẽ hướng dẫn bạn tạo một Claude Code Skill để tự động hóa toàn bộ quy trình đó — từ lọc commit theo mã ticket, cherry-pick tuần tự, xử lý conflict, đến báo cáo kết quả rõ ràng. Và quan trọng: Skill sẽ biết khi nào nên dừng lại để hỏi bạn, thay vì cứ tiến tới một cách liều lĩnh.

Bài toán thực tế

Hãy hình dung quy trình deploy phổ biến trong nhiều team:

  1. Developer làm việc trên feature branch, merge vào test để QA kiểm tra
  2. Sau khi QA approve, chỉ những ticket được duyệt mới được lên production — không phải toàn bộ test
  3. Người deploy phải tự tìm commit của từng ticket và cherry-pick thủ công lên production

Vấn đề là bước 3 rất dễ sai nếu làm tay: cherry-pick nhầm thứ tự, bỏ sót commit, hay resolve conflict ẩu trong lúc vội. Một Skill rõ ràng sẽ đảm bảo quy trình này luôn được thực hiện đúng cách — mỗi lần.

Thiết kế Skill trước khi viết

Trước khi gõ dòng đầu tiên, mình luôn nghĩ qua: Skill này cần biết gì? Làm gì? Dừng ở đâu? Với bài toán cherry-pick deploy, câu trả lời khá rõ:

  • Biết gì: mã ticket, branch nguồn, branch đích, format commit message của project
  • Làm gì: sync repo → lọc commit → cherry-pick từng cái theo thứ tự cũ → mới → push
  • Dừng ở đâu: khi gặp conflict phức tạp không tự resolve được, và khi có thể xác định được commit phụ thuộc còn thiếu

Một nguyên tắc quan trọng khi thiết kế Skill cho Git operations: không bao giờ tự push nếu còn điều chưa chắc chắn. Môi trường production không có chỗ cho “thử xem sao”.

File Skill hoàn chỉnh

Tạo file tại .claude/skills/cherry-pick-deploy.md trong project của bạn (hoặc ~/.claude/skills/ nếu muốn dùng cho mọi project):

# Skill: Cherry-Pick Deploy to Production

## Mô tả
Tự động hóa quy trình deploy production bằng cách cherry-pick
các commit theo mã ticket từ branch test/staging sang production.

## Khi nào dùng
- "Deploy ticket [TICKET-ID] lên production"
- "Cherry-pick ticket [TICKET-ID] từ test sang prod"
- "Đẩy [TICKET-ID] lên prod"

## Thông tin cần xác nhận trước khi thực hiện
1. Mã ticket: ví dụ PROJ-123, APP-456
2. Branch nguồn (source): test, staging, develop
3. Branch đích (target): production, main, prod

## Quy trình

### Bước 1 — Sync repo
git status                              # phải sạch, không có file uncommitted
git fetch origin
git checkout <source> && git pull origin <source>
git checkout <target> && git pull origin <target>

### Bước 2 — Lọc commit theo ticket (thứ tự cũ → mới là bắt buộc)
git log origin/<source> --oneline --grep="<TICKET_ID>" --reverse

→ Hiển thị danh sách cho người dùng xác nhận trước khi tiếp tục
→ Nếu danh sách rỗng: dừng, báo người dùng

### Bước 3 — Cherry-pick tuần tự
git cherry-pick <hash_1>    # log: ✅ hash — message
git cherry-pick <hash_2>    # log: ✅ hash — message
# ...tiếp tục cho đến hết

### Bước 4 — Xử lý conflict

Khi gặp conflict, kiểm tra ngay:
  git status
  git diff --diff-filter=U

CÓ THỂ tự resolve:
  - Conflict chỉ là whitespace, blank line, import order
  - Hai phía thay đổi khác vùng code hoàn toàn
  - Một bên thêm code mới, bên kia không có gì
  → git add <file> && git cherry-pick --continue

KHÔNG tự resolve — dừng và báo người dùng khi:
  - Cùng một dòng bị sửa theo hai hướng khác nhau
  - Conflict ở logic business, config, migration DB, schema
  - Conflict xuất hiện ở hơn 5 file cùng lúc

Khi không thể tự resolve, báo ra:

  🚨 CONFLICT — Cần can thiệp thủ công
  Commit: <hash> — <message>
  Files:
    - src/PaymentService.java (dòng 45-67)
    - config/application.yml (dòng 12)

  Nguyên nhân có thể: commit này phụ thuộc vào commit chưa
  được cherry-pick. Kiểm tra:
    git log origin/<source> --oneline -- <file_bị_conflict> | head -10

  Gợi ý xử lý:
    1. Cherry-pick thêm commit phụ thuộc trước
    2. Resolve thủ công → git cherry-pick --continue
    3. Hủy toàn bộ → git cherry-pick --abort

### Bước 5 — Push (chỉ khi tất cả commit thành công)
git push origin <target>

### Bước 6 — Báo cáo kết quả
  ✅ Deploy hoàn tất — Ticket <TICKET_ID>
  Branch: <source> → <target>
  Commits:
    ✅ <hash_1> — <message_1>
    ✅ <hash_2> — <message_2>
  Tổng: 2 commits | Conflict tự resolve: 0 | Cần can thiệp: 0

## Lưu ý
- Thứ tự cherry-pick phải từ cũ đến mới — sai thứ tự gây conflict
- KHÔNG dùng -X theirs hoặc -X ours trong production
- KHÔNG push nếu còn conflict chưa được người dùng xác nhận

File skill đầy đủ có thể tải về cuối bài để dùng ngay.

Kích hoạt Skill trong claude.md

Để Claude tự động nhận diện khi nào cần dùng Skill này, thêm đoạn sau vào file claude.md ở root project:

## Skills

Khi được yêu cầu deploy, cherry-pick, hay đẩy ticket lên production,
hãy tham khảo skill tại `.claude/skills/cherry-pick-deploy.md`
và thực hiện đúng theo quy trình trong đó.

Sau đó, bạn chỉ cần nói với Claude:

Deploy ticket APP-789 từ branch test lên production

Và Claude sẽ tự đọc Skill, làm theo đúng quy trình mà không cần bạn nhắc từng bước.

Chạy thử: xem Claude làm gì

Hãy xem qua một ví dụ thực tế để hiểu rõ hơn flow hoạt động.

Trường hợp 1: Mọi thứ suôn sẻ

Bạn: Deploy ticket APP-789 từ test lên production

Claude:
→ git fetch origin
→ git checkout test && git pull origin test
→ git checkout production && git pull origin production

Tìm thấy 3 commits cho APP-789 (theo thứ tự):
  a1b2c3d [APP-789] feat: add payment retry logic
  e4f5g6h [APP-789] fix: handle timeout edge case
  i7j8k9l [APP-789] test: add unit tests for retry

Xác nhận cherry-pick 3 commits này không?

Bạn: OK

Claude:
→ git cherry-pick a1b2c3d   ✅
→ git cherry-pick e4f5g6h   ✅
→ git cherry-pick i7j8k9l   ✅
→ git push origin production

✅ Deploy hoàn tất — Ticket APP-789
Commits: 3 | Conflict: 0

Trường hợp 2: Conflict đơn giản, tự resolve được

→ git cherry-pick e4f5g6h
  CONFLICT: Auto-merging src/utils/formatter.js
  (conflict chỉ là import order khác nhau)

Claude phân tích conflict:
  File: src/utils/formatter.js
  Loại: import statement reorder — không ảnh hưởng logic
  → Tự resolve bằng cách giữ thứ tự import từ cherry-pick
  → git add src/utils/formatter.js
  → git cherry-pick --continue

✅ e4f5g6h — Conflict tự resolve (import order)

Trường hợp 3: Conflict phức tạp, phát hiện commit phụ thuộc

→ git cherry-pick e4f5g6h
  CONFLICT: Merge conflict in src/services/PaymentService.java

Claude phân tích:
  File: src/services/PaymentService.java, dòng 45-67
  Conflict: logic xử lý retry — hai bên thay đổi khác nhau
  → Không tự resolve được

Claude kiểm tra git log của file bị conflict:
  git log origin/test --oneline -- src/services/PaymentService.java
  # b9c0d1e [APP-788] refactor: restructure PaymentService base class
  # e4f5g6h [APP-789] fix: handle timeout edge case   ← commit đang pick

🚨 CONFLICT — Cần can thiệp thủ công

Commit: e4f5g6h — [APP-789] fix: handle timeout edge case
File conflict: src/services/PaymentService.java (dòng 45-67)

Nguyên nhân: commit này phụ thuộc vào b9c0d1e từ ticket APP-788
  "[APP-788] refactor: restructure PaymentService base class"
  Commit đó thay đổi cùng file nhưng chưa được cherry-pick lên production.

Gợi ý:
  1. Cherry-pick thêm APP-788 trước (nếu đã được approve):
     git cherry-pick b9c0d1e
  2. Resolve thủ công rồi: git cherry-pick --continue
  3. Hủy: git cherry-pick --abort

Hiện tại đã dừng, chưa push gì cả.

Trường hợp 3 là lý do quan trọng nhất để có Skill này. Thay vì bạn phải ngồi đọc conflict và tự đoán nguyên nhân, Claude đã phân tích git log của file bị conflict và chỉ ra đúng commit nào đang gây ra vấn đề — kèm gợi ý xử lý cụ thể.

Tại sao thứ tự cherry-pick quan trọng đến vậy?

Đây là điểm mà nhiều người hay bỏ qua khi làm thủ công. Git cherry-pick áp dụng commit như một “diff patch” — nghĩa là nó cần context xung quanh để áp đúng chỗ. Nếu bạn cherry-pick commit C trước khi cherry-pick commit B (mà C được viết sau B và phụ thuộc vào code B đã thêm vào), Git sẽ không tìm được context phù hợp và sinh ra conflict hoàn toàn không cần thiết.

Đó là lý do Skill luôn dùng --reverse trong câu lệnh git log để đảm bảo thứ tự từ cũ đến mới:

git log origin/test --oneline --grep="APP-789" --reverse

Một vài điều chỉnh cho project của bạn

Skill trên là bản generic, dùng được cho hầu hết team. Nhưng bạn nên điều chỉnh một vài chỗ cho phù hợp với convention của project:

Format commit message khác nhau

Không phải team nào cũng viết commit kiểu [APP-789] feat: .... Nếu team bạn dùng format khác, thay đổi phần mô tả trong Skill:

# Format Jira-style: APP-789 ở đầu
git log origin/test --oneline --grep="^APP-789" --reverse

# Format GitHub issue: #789
git log origin/test --oneline --grep="#789" --reverse

# Format tự do: ticket xuất hiện bất kỳ đâu trong message
git log origin/test --oneline --grep="APP-789" --reverse

Thêm bước tạo tag sau deploy

Nếu team bạn có convention tag production sau mỗi deploy, thêm vào cuối Bước 5:

git push origin <target>
git tag -a "deploy-<TICKET_ID>-$(date +%Y%m%d)" -m "Deploy <TICKET_ID>"
git push origin --tags

Thêm bước notify Slack hoặc Jira

Nếu đã cài Slack MCP hoặc Jira MCP, bạn có thể thêm vào Bước 6 của Skill:

## Sau khi push thành công
- Dùng Slack MCP để gửi thông báo vào channel #deploy:
  "✅ [<TICKET_ID>] đã lên production — <số> commits"
- Dùng Jira MCP để chuyển ticket sang status "Done"

Cái này mình đã đề cập ở bài về MCP — Skills và MCP kết hợp với nhau sẽ tạo ra workflow automation thực sự mạnh.

Tổng kết

Cherry-pick deploy là một trong những quy trình lặp lại nhàm chán nhất trong vòng đời một sprint — nhưng cũng là một trong những quy trình dễ sai nhất nếu làm tay lúc cuối ngày đang vội. Viết Skill một lần, Claude sẽ làm đúng mỗi lần sau đó.

Những điểm cốt lõi của Skill này:

  • Luôn xác nhận danh sách commit trước khi thực hiện — tránh nhầm ticket
  • Thứ tự từ cũ đến mới là bắt buộc — --reverse trong git log
  • Phân biệt rõ conflict nào tự resolve được, conflict nào phải dừng lại
  • Tìm commit phụ thuộc bằng cách phân tích git log của file bị conflict
  • Không bao giờ push khi còn chưa chắc — báo người dùng và chờ xác nhận

File skill đầy đủ đính kèm bên dưới — tải về, bỏ vào .claude/skills/, và dùng ngay trong lần deploy tiếp theo.

Chúc anh em code vui! 🚀


Tags: #claude #claudecode #skills #git #cherrypick #deploy #automation #devops

1 Comment

  1. Nếu bạn đang làm việc trong một team có quy trình deploy theo từng ticket — nghĩa là không phải merge cả branch mà phải chọn lọc commit nào được lên production — thì hẳn bạn đã quen với cảnh này: mở git log, grep commit, cherry-pick từng cái, gặp conflict ngồi giải quyết, push, rồi báo cáo lại. Làm đi làm lại mỗi sprint.

    Bài này sẽ hướng dẫn bạn tạo một Claude Code Skill để tự động hóa toàn bộ quy trình đó — từ lọc commit theo mã ticket, cherry-pick tuần tự, xử lý conflict, đến báo cáo kết quả rõ ràng. Và quan trọng: Skill sẽ biết khi nào nên dừng lại để hỏi bạn, thay vì cứ tiến tới một cách liều lĩnh.

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *