cherry-pick ใน git คืออะไร และวิธีหยิบ commit เดียวไปใช้กับอีก branch

git cherry-pick คัดลอก commit ที่เลือกไปต่อบน branch ที่เรายืนอยู่ เหมาะกับตอนต้องเอา commit แก้บั๊กตัวเดียวจาก develop ขึ้น production ก่อน โดยไม่พางานอื่นที่ยังไม่เสร็จติดไปด้วย

เผยแพร่
เวลาอ่าน
4 นาที
แท็ก
#Git#Tools

บางครั้งเราต้องการแค่ 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
ก่อน cherry-pick
25993f7สร้าง PDF ด้วย mPDFdevelop
7b2cf7aแก้ redirect หลัง login
f902a26เพิ่มปุ่ม export
9bed57eRelease 2.4main
b3c5f58หน้า login

เราอยากได้แค่ 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 ต่างกันตรงไหน)

cherry-pick คัดลอก commit แก้บั๊กตัวเดียวจาก develop ไปต่อบน main เป็น commit ใหม่

commit บน develop ยังอยู่ที่เดิม main ได้ตัวที่คัดลอกมา

หลัง git cherry-pick 7b2cf7a
6af1a26แก้ redirect หลัง loginmain
25993f7สร้าง PDF ด้วย mPDFdevelop
7b2cf7aแก้ redirect หลัง login
f902a26เพิ่มปุ่ม export
9bed57eRelease 2.4
b3c5f58หน้า login

ตอนนี้ 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 ตามปกติ

หลัง merge develop เข้า main
1d9ffb1Merge branch 'develop'main
25993f7สร้าง PDF ด้วย mPDFdevelop
7b2cf7aแก้ redirect หลัง login
f902a26เพิ่มปุ่ม export
6af1a26แก้ redirect หลัง login
9bed57eRelease 2.4
b3c5f58หน้า login

merge ผ่านโดยไม่มี 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 ได้ครับ

อ่านต่อ

ถูกอ้างถึงใน

ล่าสุด

ดูทั้งหมด →