Bài 5, rebase phát lại toàn bộ chuỗi commit riêng của 1 nhánh lên nền mới. Nhưng đôi khi bạn chỉ cần đúng 1 commit cụ thể từ nhánh khác — không phải cả nhánh. Đó là lúc git cherry-pick phát huy tác dụng.

1. Bài toán: Chỉ Muốn 1 Commit, Không Phải Cả Nhánh

Tình huống kinh điển: một lập trình viên vô tình commit bản sửa lỗi bảo mật khẩn cấp lên nhánh feature đang phát triển dở (chưa sẵn sàng release). Bạn cần bản vá đó trên main ngay lập tức, nhưng merge cả feature vào main sẽ kéo theo toàn bộ code dở dang chưa hoàn thiện. git cherry-pick <hash> cho phép "nhặt" đúng commit sửa lỗi đó sang main, bỏ qua mọi commit khác trên feature.

2. Cơ Chế: Tạo Commit Mới Cùng Diff, Khác Hash

Giống hệt nguyên lý rebase đã thấy ở Bài 5: cherry-pick không di chuyển commit gốc. Nó tính diff mà commit đó giới thiệu (so với commit cha của nó), rồi áp diff đó lên đỉnh nhánh hiện tại — tạo ra 1 commit hoàn toàn mới với cha khác, nên hash cũng khác. Commit gốc trên nhánh nguồn vẫn còn nguyên, không bị ảnh hưởng gì.

ℹ️ Lưu ý: Message thường ghi rõ nguồn gốc
Theo mặc định, Git thêm dòng (cherry picked from commit <hash>) vào cuối message của commit mới — giúp bất kỳ ai đọc log sau này biết thay đổi này vốn đến từ đâu, dù commit gốc và bản sao chép có hash hoàn toàn khác nhau.

3. Xử Lý Xung Đột Khi Cherry-pick

Cherry-pick vẫn có thể xung đột — nếu nhánh hiện tại đã thay đổi cùng phần nội dung theo cách khác kể từ điểm phân kỳ, Git không biết chọn phiên bản nào. Về bản chất, cơ chế giải xung đột giống hệt three-way merge đã học ở Bài 4 — chỉ khác base lúc này là commit cha của commit được pick, còn theirs chính là commit đó:

terminal
$ git cherry-pick a1b2c3d
# Nếu xung đột:
Auto-merging app.js
CONFLICT (content): Merge conflict in app.js

# Sửa file thủ công, rồi:
$ git add app.js
$ git cherry-pick --continue
🕳️ Cạm bẫy thường gặp: Cherry-pick lặp lại gây trùng lặp lịch sử
Nếu bạn cherry-pick 1 commit từ feature sang main, rồi sau này vẫn merge feature vào main, thay đổi đó tồn tại 2 lần trong lịch sử dưới 2 hash khác nhau (dù nội dung cây thường giống hệt nên Git thường tự merge êm, không báo conflict). Kết quả: git log hiện 2 commit riêng biệt mang cùng nội dung — gây khó hiểu khi tra cứu lịch sử về sau. Cân nhắc kỹ trước khi cherry-pick từ 1 nhánh vẫn còn dự định merge đầy đủ sau này.

4. So Sánh Cherry-pick, Rebase, và Merge

Tiêu chí Cherry-pick Rebase Merge
Số commit bị ảnh hưởng Đúng 1 commit chỉ định Toàn bộ commit riêng của nhánh Không tạo lại commit nào
Commit mới tạo ra 1 commit mới (hash mới) N commit mới (N = số commit replay) 1 merge commit (2 cha)
Trường hợp dùng điển hình Backport 1 hotfix cụ thể sang nhánh khác Dọn lịch sử thẳng hàng trước khi chia sẻ Hợp nhất đầy đủ lịch sử 2 nhánh
🔬 Đào sâu: Cherry-pick chỉ là 1 trường hợp đặc biệt của Merge
Về mặt thuật toán, cherry-pick dùng đúng three-way merge đã học ở Bài 4 — chỉ khác cách chọn 3 điểm so sánh: base = commit cha của commit được pick, ours = HEAD hiện tại, theirs = chính commit được pick. Vì vậy mọi quy tắc phát hiện xung đột ở Bài 4 áp dụng y hệt ở đây — Git không có 2 thuật toán merge khác nhau, chỉ có 2 cách khác nhau để chọn đầu vào cho cùng 1 thuật toán.
💡 Mẹo: Khi nào nên dùng cherry-pick?
Cherry-pick lý tưởng cho: backport 1 bản vá bảo mật khẩn cấp sang nhiều nhánh release cùng lúc; cứu 1 commit hữu ích từ 1 Pull Request đã bị đóng/từ chối mà không muốn merge toàn bộ; hoặc chuyển 1 commit bị commit nhầm nhánh sang đúng nhánh nó thuộc về.

Sân chơi tương tác: Cherry-pick Simulator

Kịch bản mẫu đã dựng sẵn 2 nhánh phân kỳ với 1 commit "Fix security bug" trên nhánh hotfix. Thử git cherry-pick C2 khi đang ở main để xem cách nhặt commit đó — và xử lý xung đột thực sự xảy ra vì main cũng đã thay đổi nội dung khác kể từ điểm phân kỳ.

🍒 Sân chơi tương tác: Cherry-pick Simulator

Terminal giả lập

  • git branch/checkout <tên>
  • git commit -m "..."
  • git cherry-pick <id>
  • git log

Nhật ký

⚠️ XUNG ĐỘT KHI CHERRY-PICK — sửa nội dung bên dưới rồi bấm "Hoàn tất"

git-cherry-pick-live.js

Trắc nghiệm ôn tập

Câu 1: Sau khi git cherry-pick C2 thành công, commit C2 gốc trên nhánh hotfix có bị thay đổi hay xoá không?

Trắc nghiệm ôn tập

Câu 2: Vì sao commit tạo ra bởi cherry-pick có hash khác hoàn toàn với commit gốc, dù nội dung thay đổi giống hệt nhau?

Trắc nghiệm ôn tập

Câu 3: Khi nào cherry-pick 1 commit KHÔNG gây xung đột (áp dụng êm)?

📖 Tài liệu tham khảo / References

Bài viết liên quan trong series

Bài 7: Undo & Phục Hồi Bài 5: Rebase & Viết Lại Lịch Sử Quay lại Lộ trình Series Git Bài 4: Merge & Conflict (three-way merge nền tảng)