TL;DR: git cherry-pick <sha> คัดลอกคอมมิตหนึ่งตัวจากบรานช์ใดก็ได้มาไว้บนบรานช์ปัจจุบัน — แพตช์เดิม SHA ใหม่ ไม่มีประวัติใดขยับ สำหรับหลายคอมมิต ให้พิมพ์รายชื่อ SHA หรือใช้ช่วง (git cherry-pick A..B); ข้อควรจำคือช่วงนี้ไม่รวม A ให้เขียน A^..B เพื่อรวมมัน ถ้าหยุดที่คอนฟลิกต์ ให้แก้แล้ว git add แล้ว git cherry-pick --continue cherry-pick ใช้เพื่อย้ายแพตช์เฉพาะเจาะจง — ถ้าคุณต้องการทุกอย่างจากอีกบรานช์ ให้ใช้ merge หรือ rebase แทน
git cherry-pick ทำอะไรกันแน่?
cherry-pick หยิบคอมมิตที่มีอยู่แล้วและเอา diff ของมันมาเป็นคอมมิตใหม่บนบรานช์ปัจจุบันของคุณ คอมมิตต้นฉบับอยู่ที่เดิม สำเนาได้ SHA ใหม่สด ๆ git ไม่ได้ “ย้าย” อะไรเลย — คนที่ภายหลังงงว่าทำไมคอมมิตยังโผล่บนบรานช์เก่ากำลังเห็นข้อเท็จจริงนี้พอดี
โมเดลคัดลอก-ไม่ใช่ย้ายนี้ตัดสินว่า cherry-pick เป็นเครื่องมือที่ใช่เมื่อไร:
- ต้องการหนึ่งการแก้จาก feature branch มาที่
mainตอนนี้ โดยไม่ merge ที่เหลือ - hotfix ที่ถูก commit ผิดบรานช์ต้องมาลงบรานช์ที่ถูก
- แพตช์ต้องเล่นซ้ำลง release branch ที่ไม่เคย merge จาก
main
ทักษะคู่กันคือรู้วิธีถอยคอมมิตที่ปรากฏว่าผิด — กลไกของเรื่องนี้อยู่ใน git undo last commit: เก็บการเปลี่ยนแปลงไว้
cherry-pick คอมมิตจากบรานช์อื่นอย่างไร?
หา SHA สลับไปบรานช์เป้าหมาย แล้วหยิบ:
# 1. หาตำแหน่งคอมมิตบนบรานช์ต้นทาง
git log feature/payment-fix --oneline -5
# 2. สลับไปบรานช์ที่จะรับมัน
git switch main
# 3. คัดลอกมา
git cherry-pick 1a2b3c4 สองความสะดวกที่ควรรู้:
git cherry-pick <branch>หยิบคอมมิตปลายสุดของบรานช์นั้น — สะดวก แต่กดผ่านโดยบังเอิญง่าย เมื่อความเข้าใจเรื่อง “ปลายสุด” ล้าสมัย- หลังหยิบ
git log -1 --statยืนยันว่าอะไรลงมาแล้ว หนึ่งวินาทีของการอ่านช่วยเซฟการ revert ได้
คอมมิตยังอยู่บน feature/payment-fix ลบบรานช์นั้นเมื่อไรก็ได้ — สำเนาที่ถูกหยิบมาบน main มี SHA ของตัวเองและไม่พึ่งพาตัวเก่า
cherry-pick หลายคอมมิตอย่างไร?
สามรูปแบบ เรียงตามความถี่ที่คุณต้องใช้:
# 1. ระบุชื่อเอง — ถูกหยิบตามลำดับที่พิมพ์
git cherry-pick 1a2b3c4 5d6e7f8
# 2. ช่วง — ทุกอย่างหลัง A ถึงรวม B
git cherry-pick A..B
# 3. ช่วงที่รวม A
git cherry-pick A^..B ความต่างระหว่าง A..B กับ A^..B คือเรื่องน่าตกใจสุดคลาสสิก: A..B ตัด A ทิ้ง ถ้าคุณนึกช่วงจาก git log แล้วหยิบ oldest..newest คุณจะข้ามคอมมิตเก่าที่สุดไปแบบเงียบ ๆ เมื่อเป้าหมายคือ “คอมมิตเก่า ๆ หลายตัวตามลำดับ” ให้เขียน oldest^..newest แล้ว off-by-one จะหายไป
ที่จะรวมหลายคอมมิตที่หยิบมาเป็นหนึ่งเดียว ใช้ stage โดยไม่ commit ผ่าน -n / --no-commit แล้ว commit ครั้งเดียว:
git cherry-pick -n 1a2b3c4 5d6e7f8
git commit -m "Backport: payment retry fixes" ทำไม git cherry-pick ถึงไม่ทำงาน?
สี่สาเหตุจริง เรียงตามความถี่:
1. คอนฟลิกต์หยุดการหยิบ git ใช้แพตช์ เจอบรรทัดที่เปลี่ยนทั้งสองบรานช์ แล้วหยุดกลางทาง:
# แก้ไฟล์เสร็จแล้ว:
git add <resolved-files>
git cherry-pick --continue # หรือ --abort เพื่อกลับไปก่อนเริ่มหยิบ --continue ไม่ใช่สิ่งที่เลือกได้หรือถือว่าหมายถึงกัน — จนกว่าคุณจะรันมัน คุณอยู่ในลำดับ cherry-pick ที่พักค้างและ git status จะย้ำอย่างนั้นต่อไป
2. การหยิบว่างเปล่า (“The previous cherry-pick is now empty”) การเปลี่ยนแปลงนี้มีอยู่บนบรานช์นี้แล้ว มักจากการหยิบรอบก่อนหรือ merge ที่ถูก squash ข้ามด้วย git cherry-pick --skip หรือบังคับคอมมิตว่างด้วย --allow-empty ถ้าคุณจริง ๆ ต้องการหมุดนั้น
3. คอมมิตนั้นเป็น merge commit การ merge มีพ่อสองตัว “ใช้ diff นี้” จึงกำกวม — git ปฏิเสธแทนการเดา บอกว่าเทียบกับพ่อตัวไหน:
git cherry-pick -m 1 <merge-sha> # พ่อ 1 = บรานช์ที่ merge*เข้ามา* 4. working tree ผิดหรือ HEAD หลุด การหยิบจะลงตรงที่ HEAD ชี้ เช็ก git branch --show-current ก่อนหยิบ ถ้าไม่พิมพ์อะไรออกมา คุณอยู่ใน detached HEAD และคอมมิตจะกลายเป็นของกำพร้าเมื่อคุณสลับที่
Cherry-pick vs merge vs rebase: ใช้ตัวไหนเมื่อไร?
| คำสั่ง | สิ่งที่ลงบนเป้าหมาย | ประวัติ | ใช้เมื่อ |
|---|---|---|---|
git cherry-pick <sha> | เฉพาะคอมมิตที่ระบุ | คัดลอก SHA ใหม่ | แพตช์เจาะจงต้องย้ายตอนนี้ |
git merge <branch> | ทุกอย่างบนบรานช์ | merge commit หรือ fast-forward | ต้องการทั้งบรานช์ เห็นความแยกชัด |
git rebase <base> | ทุกคอมมิตบนบรานช์ เล่นซ้ำ | เป็นเส้นตรง SHA ถูกเขียนใหม่ | ต้องการบรานช์เป็นแถวเส้นตรงสะอาด |
git revert <sha> | คอมมิตกลับด้าน | เพิ่ม undo commit | คอมมิตที่ลงแล้วต้องถูกยกเลิกบนประวัติร่วม |
กฎหนึ่งบรรทัด: cherry-pick ย้ายสิ่งที่เลือก; merge กับ rebase ย้ายทุกอย่าง ยื่นมือไปหา cherry-pick เพื่อ “ซิงก์” กับบรานช์คือสัญญาณว่าจริง ๆ คุณต้องการ merge — และถ้าบรานช์นั้นคือ main ของ fork กับ upstream ขั้นตอนเต็มอยู่ที่ซิงก์ fork กับ upstream ทีละขั้น
นิสัยที่ควรข้าม: cherry-pick คอมมิตเดิมเข้าหลายบรานช์ในระยะยาว ทุกการแก้ในอนาคตบนบรานช์ต้นทางต้องหยิบใหม่อีก และบรานช์จะลอยแยกกันในที่สุด การ backport ลง release branch เป็นรูปแบบปกติ แต่จักรวาลขนานถาวรไม่ใช่
เวิร์กโฟลว์ cherry-pick ฉบับย่อ
git log <source-branch> --oneline -5 # หา SHA
git switch <target-branch> # ลงจอดที่ถูกที่
git cherry-pick A^..B # ช่วง รายชื่อ หรือ SHA เดียว
# เจอคอนฟลิกต์: แก้ → git add → git cherry-pick --continue
git log -1 --stat # ยืนยันว่าอะไรลงมา หา สลับ หยิบ ตรวจ คำสั่งนี้มีชื่อเสียงเรื่องอันตรายที่มันไม่สมควรได้รับ — diff อย่างใดอย่างหนึ่งจะถูกใช้ได้ หรือมันหยุดและบอกคุณว่าทำไม ความผิดพลาดที่ทำลายข้อมูลจริงมีอย่างเดียวคือหยิบผิดบรานช์ และ git log -1 ก่อนพุชทำให้พลาดจุดนั้นยาก
— mrsaynothing
— mrsaynothing
บันทึกหน้างานเรื่อง AI, Linux และ self-hosted
คุยต่อโพสต์นี้บน dev.to dev.to ↗
รับวิธีแก้ฉบับถัดไปทางอีเมล
อีเมลหนึ่งฉบับต่อหนึ่งโพสต์ แก้เสร็จแล้วไปต่อ
นี่คืออะไร?Cron vs systemd timers: ควรใช้แบบไหน
ถ้าอ่านแล้วชอบ — ผมสร้างงานแบบนี้เป็นอาชีพ จ้างผม