TL;DR: git cherry-pick <sha> copy một commit từ bất kỳ branch nào lên branch hiện tại của bạn — cùng patch, SHA mới, không đụng history. Cần nhiều commit, liệt kê SHA hoặc dùng range (git cherry-pick A..B); lưu ý range đó loại A, nên viết A^..B để gồm cả nó. Nếu dừng lại vì conflict, xử lý xong, git add, rồi git cherry-pick --continue. Cherry-pick dành cho việc chuyển một fix cụ thể — khi bạn muốn mọi thứ từ branch kia, hãy merge hoặc rebase.
git cherry-pick thực sự làm gì?
Cherry-pick lấy một commit có sẵn và áp diff của nó thành một commit mới trên branch hiện tại của bạn. Commit gốc ở nguyên chỗ; bản copy nhận SHA mới. Git không “chuyển” gì cả — ai sau này thắc mắc sao commit vẫn hiện trên branch cũ đang nhìn đúng hiện tượng này.
Mô hình copy-thay-vì-chuyển đó quyết định khi nào cherry-pick là đúng công cụ:
- Bạn cần một fix từ feature branch lên
mainngay, mà không merge phần còn lại. - Một hotfix bị commit nhầm branch cần hạ xuống branch đúng.
- Một patch phải được replay lên release branch — thứ không bao giờ merge từ
main.
Kỹ năng bổ sung là biết cách rút lại một commit hóa ra sai — cơ chế của việc đó nằm trong git undo last commit: giữ lại thay đổi.
Làm sao cherry-pick một commit từ branch khác?
Tìm SHA, chuyển sang branch đích, pick:
# 1. Tìm commit trên branch nguồn
git log feature/payment-fix --oneline -5
# 2. Chuyển sang branch sẽ nhận nó
git switch main
# 3. Copy nó sang
git cherry-pick 1a2b3c4 Hai tiện ích đáng biết:
git cherry-pick <branch>pick commit tip của branch đó — tiện, nhưng dễ làm nhầm khi hình dung của bạn về “tip” đã cũ.- Sau khi pick,
git log -1 --statxác nhận cái gì vừa hạ xuống. Một giây đọc, cứu một lần revert.
Các commit vẫn nằm trên feature/payment-fix; xóa branch đó khi nào cũng được — bản copy trên main có SHA riêng và không phụ thuộc cái cũ.
Làm sao cherry-pick nhiều commit?
Ba dạng, xếp theo tần suất bạn cần chúng:
# 1. Liệt kê tường minh — pick theo đúng thứ tự bạn liệt kê
git cherry-pick 1a2b3c4 5d6e7f8
# 2. Range — mọi thứ sau A cho tới và gồm cả B
git cherry-pick A..B
# 3. Range gồm cả A
git cherry-pick A^..B Phân biệt A..B với A^..B là cú bất ngờ kinh điển: A..B loại A. Nếu bạn hình dung range từ git log rồi pick oldest..newest, bạn lặng lẽ bỏ sót commit cũ nhất. Khi mục tiêu là “vài commit cũ nhất, đúng thứ tự”, viết oldest^..newest và lỗi lệch một đơn vị biến mất.
Để gộp nhiều lần pick vào một commit thay vì ba, stage mà chưa commit bằng -n / --no-commit, rồi commit một lần:
git cherry-pick -n 1a2b3c4 5d6e7f8
git commit -m "Backport: payment retry fixes" Vì sao git cherry-pick không chạy?
Bốn nguyên nhân có thật, theo thứ tự tần suất:
1. Conflict chặn lần pick. Git áp patch, đụng một dòng đã đổi trên cả hai branch, và tạm dừng giữa chừng:
# xử lý các file, rồi:
git add <resolved-files>
git cherry-pick --continue # hoặc --abort để quay về trạng thái trước khi pick --continue không tùy chọn và không tự động — cho tới khi bạn chạy nó, bạn vẫn đang trong một chuỗi cherry-pick bị tạm dừng và git status sẽ cứ nhắc điều đó.
2. Lần pick rỗng (“The previous cherry-pick is now empty”). Thay đổi đã tồn tại trên branch này, thường từ một lần pick trước hoặc một merge bị squash. Bỏ qua bằng git cherry-pick --skip, hoặc ép một commit rỗng bằng --allow-empty nếu bạn thật sự cần dấu mốc đó.
3. Commit đó là merge commit. Một merge có hai cha, nên “áp diff này” là mơ hồ — git từ chối thay vì đoán. Hãy nói rõ bạn lấy diff so với cha nào:
git cherry-pick -m 1 <merge-sha> # parent 1 = branch mà bạn merge *vào* 4. Working tree sai hoặc detached HEAD. Lần pick hạ xuống bất cứ đâu HEAD đang trỏ. Chạy git branch --show-current trước khi pick; nếu nó không in gì, bạn đang ở detached HEAD và commit sẽ bị bỏ rơi khi bạn chuyển đi.
Cherry-pick vs merge vs rebase: cái nào dùng lúc nào?
| Lệnh | Cái gì hạ xuống đích | History | Dùng khi |
|---|---|---|---|
git cherry-pick <sha> | Chỉ các commit được nêu tên | Copy, SHA mới | Một fix cụ thể phải chuyển ngay |
git merge <branch> | Mọi thứ trên branch | Merge commit hoặc fast-forward | Bạn muốn cả branch, thấy rõ chỗ rẽ nhánh |
git rebase <base> | Mọi commit của branch, được replay | Tuyến tính, SHA viết lại | Bạn muốn branch thành một dải tuyến tính sạch |
git revert <sha> | Nghịch đảo một commit | Thêm một commit undo | Một commit đã hạ phải bị rút lại trên history dùng chung |
Quy tắc một dòng: cherry-pick chuyển một phần chọn lọc; merge và rebase chuyển tất cả. Với tay ra cherry-pick để “sync” với một branch là dấu hiệu bạn thật ra muốn một merge — và nếu branch đó là main của fork so với upstream, toàn bộ quy trình nằm trong sync fork với upstream, từng bước.
Một thói quen nên bỏ: cherry-pick cùng một commit vào nhiều branch về lâu dài. Mỗi fix tương lai trên branch nguồn lại cần một lần pick nữa, và rồi các branch trôi dần. Backport lên release branch là pattern bình thường; một vũ trụ song song vĩnh viễn thì không.
Quy trình cherry-pick, bản rút gọn
git log <source-branch> --oneline -5 # tìm (các) SHA
git switch <target-branch> # hạ xuống đúng chỗ
git cherry-pick A^..B # range, list, hoặc một SHA
# gặp conflict: xử lý → git add → git cherry-pick --continue
git log -1 --stat # xác nhận cái gì vừa hạ Tìm, chuyển, pick, xác minh. Lệnh này có tiếng nguy hiểm mà nó không đáng — diff hoặc áp được, hoặc nó dừng lại và nói cho bạn biết vì sao. Sai lầm thật sự phá hoại duy nhất là pick nhầm branch, và git log -1 trước khi push khiến điều đó khó mà lọt qua mắt.
— mrsaynothing
— mrsaynothing
Ghi chú thực địa về AI, Linux và self-hosting.
Thảo luận bài này trên dev.to dev.to ↗
Nhận how-to tiếp theo qua email
Một email mỗi bài viết. Sửa xong rồi đi tiếp.
cái này là gì?Cron vs systemd timer: Bạn nên dùng cái nào?
Thích kiểu viết này? Tôi build như vậy để kiếm sống. thuê tôi