บางครั้งเราต้องการแค่ commit เดียวจาก develop
โปรเจกต์ที่ผมดูแลแบ่ง branch ไว้แบบในคำสั่ง git ที่ใช้ทุกวัน คืองานทุกชิ้นรวมกันที่ develop แล้วค่อยไหลไป uat และ main ซึ่งเป็น production
ทีนี้ลูกค้าแจ้งบั๊กบน production ว่าล็อกอินแล้วไม่กลับไปหน้าที่เปิดค้างไว้ เราแก้บน develop เสร็จแล้ว แต่บน develop ยังมีงาน export PDF ที่ยังไม่ผ่านการทดสอบอยู่ทั้งก่อนและหลัง commit แก้บั๊ก ถ้า merge develop เข้า main ตอนนี้ งาน PDF ก็จะขึ้น production ไปด้วย
git log --oneline --graph develop main
25993f7develop7b2cf7af902a269bed57emainb3c5f58เราอยากได้แค่ 7b2cf7a ไปไว้บน main ตัวเดียว ซึ่งก็คือสิ่งที่ git cherry-pick ทำ
cherry-pick คัดลอก commit ที่เลือกมาต่อบน branch ของเรา
สลับไป branch ที่จะรับ แล้วบอก hash ของ commit ที่ต้องการ
git switch main
git cherry-pick -x 7b2cf7a
[main 6af1a26] แก้ redirect หลัง login
Date: Tue Oct 13 10:00:00 2026 +0700
1 file changed, 1 insertion(+)git หยิบการแก้ไขของ 7b2cf7a มาวางบน main แล้วสร้าง commit ใหม่ 6af1a26 ข้อความ commit กับชื่อคนเขียนเหมือนเดิม วันที่ใน Date: ก็ยังเป็นวันที่ commit ต้นฉบับ แต่ parent เปลี่ยนจาก ปุ่ม export เป็น Release 2.4 hash จึงเปลี่ยนตาม เป็นกลไกเดียวกับที่ rebase คัดลอก commit ไปต่อท้ายอีก branch (อ่านเพิ่มได้ในrebase กับ merge ต่างกันตรงไหน)

commit บน develop ยังอยู่ที่เดิม main ได้ตัวที่คัดลอกมา
6af1a26main25993f7develop7b2cf7af902a269bed57eb3c5f58ตอนนี้ main มีงานแก้บั๊กแล้ว ส่วน ปุ่ม export กับ สร้าง PDF ยังอยู่บน develop เท่านั้น push main ขึ้นไปก็ deploy แก้บั๊กได้เลย
ถ้าทีมบังคับให้ทุกอย่างเข้า main ผ่าน PR ให้แตก branch จาก main ก่อน แล้ว cherry-pick ลง branch นั้นแทน
git switch -c fix/login-redirect-main origin/main
git cherry-pick -x 7b2cf7a
git push -u origin fix/login-redirect-main
ใส่ -x ให้ commit จำได้ว่าคัดลอกมาจากไหน
-x ต่อบรรทัดนี้ท้ายข้อความ commit ให้
แก้ redirect หลัง login
(cherry picked from commit 7b2cf7ab170e3a64f4612722633c4fe93191a8d1)
อีกหลายเดือนต่อมา ถ้ามีคนสงสัยว่าทำไม main มี commit นี้โผล่มาก่อน develop จะ merge เข้ามา บรรทัดนี้บอกที่มาได้ทันที เอกสารของ git แนะนำให้ใช้ -x ตอนคัดลอกระหว่าง branch ที่คนอื่นเห็นด้วย อย่าง develop กับ main ส่วนตอนคัดลอกใน branch ส่วนตัวไม่ต้องใส่ก็ได้ เพราะคนอื่นไม่เคยเห็น commit ต้นฉบับอยู่แล้ว
หยิบหลาย commit พร้อมกันก็ได้
ใส่ hash เรียงกันไปได้หลายตัว หรือใส่เป็นช่วง
# ระบุทีละตัว
git cherry-pick -x 7b2cf7a 25993f7
# ทุก commit ตั้งแต่ f902a26 ถึง 25993f7
git cherry-pick -x f902a26^..25993f7
ช่วง A..B ใน git หมายถึง commit ที่อยู่ใน B แต่ไม่อยู่ใน A จึงไม่รวม A เอง ถ้าอยากได้ A ด้วยต้องเติม ^ เป็น A^..B ซึ่งแปลว่าเริ่มจาก parent ของ A
ถ้าเจอ conflict ก็แก้แบบเดียวกับ merge
ถ้า main กับ develop แก้บรรทัดเดียวกันไว้คนละแบบ cherry-pick จะหยุดให้เราแก้ conflict ก่อน วิธีแก้เหมือนตอน merge แก้ไฟล์ให้เรียบร้อย git add แล้วสั่งต่อ
git cherry-pick --continue
# ถ้าหยิบหลาย commit แล้วอยากข้ามตัวนี้ไป
git cherry-pick --skip
# ยกเลิกทั้งหมด กลับไปเหมือนยังไม่เริ่ม
git cherry-pick --abort
พอ merge develop เข้า main ทีหลัง git รู้ว่าแก้ไปแล้ว
ผ่านไปสองวัน งาน PDF ทดสอบเสร็จ เรา merge develop เข้า main ตามปกติ
1d9ffb1main25993f7develop7b2cf7af902a266af1a269bed57eb3c5f58merge ผ่านโดยไม่มี conflict เพราะทั้งสองฝั่งแก้ login.php แบบเดียวกันทุกตัวอักษร ไฟล์จึงมีบรรทัดแก้บั๊กอยู่บรรทัดเดียว ไม่ซ้ำ แต่ในประวัติจะเห็น แก้ redirect หลัง login สองตัว ตัวหนึ่งคือต้นฉบับบน develop อีกตัวคือตัวที่คัดลอกมา
ถ้าหลัง cherry-pick มีคนแก้บรรทัดเดิมบน develop ซ้ำอีก สองฝั่งจะไม่เหมือนกันแล้ว ตอน merge ก็อาจ conflict ได้
ก่อน merge อยากรู้ว่า commit ไหนบน develop ที่ main มีการแก้ไขเดียวกันแล้ว ใช้ git cherry ได้
git cherry -v main develop
+ f902a262e84f86465288bccd554fef825495b752 เพิ่มปุ่ม export
- 7b2cf7ab170e3a64f4612722633c4fe93191a8d1 แก้ redirect หลัง login
+ 25993f7e7e9b2abe84945610d4bd6525e89a8905 สร้าง PDF ด้วย mPDF- คือ commit ที่ main มีการแก้ไขแบบเดียวกันอยู่แล้ว ส่วน + คือที่ยังไม่มี
ถ้าต้อง cherry-pick บ่อย แตก branch แก้บั๊กจาก main แทน
cherry-pick เหมาะกับตอนที่งานแก้บั๊กไปอยู่บน develop แล้ว แต่ถ้ารู้ตั้งแต่ต้นว่าเป็นบั๊กบน production ที่ต้องขึ้นด่วน ทางที่ประวัติสะอาดกว่าคือแตก branch แก้บั๊กออกจาก main แล้ว merge branch นั้นเข้าทั้ง main และ develop
git switch -c fix/login-redirect origin/main
# แก้ แล้ว commit
git push -u origin fix/login-redirect
# เปิด PR เข้า main แล้วเปิดอีก PR เข้า develop
แบบนี้ commit แก้บั๊กมีตัวเดียว hash เดียวทั้งสอง branch ไม่ต้องคัดลอก และไม่มี commit ซ้ำในประวัติ
สรุปเลือกใช้แบบนี้
| สถานการณ์ | ใช้ |
|---|---|
| แก้บั๊กบน develop ไปแล้ว แต่ต้องขึ้น production ก่อนงานอื่น | git cherry-pick -x <hash> ลง main หรือ branch ที่แตกจาก main |
| รู้ตั้งแต่ต้นว่าเป็นบั๊กด่วนบน production | แตก branch จาก main แล้ว merge เข้าทั้ง main และ develop |
| commit ผิด branch และยังไม่ได้ push | cherry-pick ไป branch ที่ถูก แล้วลบออกจาก branch เดิมด้วย git reset --hard HEAD~1 |
| อยากได้งานทั้ง branch | git merge หรือ git rebase ไม่ใช่ cherry-pick |
ใน PHPStorm คลิกขวาที่ commit ในแท็บ Git log แล้วเลือก Cherry-Pick ก็ได้ผลเหมือน git cherry-pick ส่วนใน terminal ถ้าอยากเลือก branch และเห็นคำสั่ง git ที่รันจริงจากหน้าต่างเดียว ลองดู git-prompt ได้ครับ






