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:
- Developer làm việc trên feature branch, merge vào
testđể QA kiểm tra - 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 - 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 —
--reversetrong 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
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.