git cherry-pick: วิธีย้ายคอมมิตเดียวไปยังบรานช์อื่น
git cherry-pick นำการเปลี่ยนแปลงของคอมมิตที่ระบุไปใช้ในบรานช์ปัจจุบัน และสร้างคอมมิตใหม่ที่มี diff เดียวกันและข้อความเดียวกัน แต่มีแฮชต่างกัน ให้ย้ายไปยังบรานช์เป้าหมายแล้วรัน git cherry-pick <แฮช> หากเกิดความขัดแย้งให้แก้ไฟล์ รัน git add และ git cherry-pick --continue
git cherry-pick ย้ายการเปลี่ยนแปลงของคอมมิตเดียวที่ระบุไปยังบรานช์ปัจจุบัน โดยไม่ต้อง merge ทั้งบรานช์ Git คำนวณ diff ของคอมมิตที่เลือกเทียบกับพาเรนต์ นำไปใช้กับ HEAD ของคุณ และสร้างคอมมิตใหม่ ข้อความและผู้เขียนเหมือนเดิม แต่แฮชต่างกัน เพราะพาเรนต์ต่างกัน
สถานการณ์ทั่วไป: ในบรานช์ฟีเจอร์คุณแก้บั๊กไว้แล้ว และการแก้นี้ต้องการด่วนในบรานช์รีลีส ซึ่งฟีเจอร์ยังไม่พร้อม จะ merge ทั้งบรานช์ไม่ได้ แต่ย้ายคอมมิตเดียวได้
วิธีย้ายคอมมิตเดียวไปยังบรานช์อื่น
ขั้นแรกหาแฮชของคอมมิตที่ต้องการ จากนั้นสลับไปยังบรานช์ปลายทางแล้วรัน cherry-pick
# 1. หาคอมมิตในบรานช์ feature
git log --oneline feature
a1b2c3d แก้การหารด้วยศูนย์ในการคำนวณส่วนลด
9f8e7d6 เพิ่มหน้าจอชำระเงินใหม่
# 2. ย้ายไปยังบรานช์เป้าหมาย
git switch release-1.4
# 3. ย้ายคอมมิต
git cherry-pick a1b2c3d
[release-1.4 4e5f6a7] แก้การหารด้วยศูนย์ในการคำนวณส่วนลด
Date: Mon Oct 5 14:12:03 2026 +0300
1 file changed, 3 insertions(+), 1 deletion(-)
โปรดสังเกต: คอมมิตใหม่ได้แฮช 4e5f6a7 ไม่ใช่ a1b2c3d เป็นอ็อบเจกต์สองชิ้นที่มีการเปลี่ยนแปลงเหมือนกัน บรานช์ feature ดั้งเดิมไม่เปลี่ยนแปลง
แทนที่จะใช้แฮช สามารถส่งการอ้างอิงคอมมิตใดก็ได้: git cherry-pick feature จะหยิบคอมมิตล่าสุดของบรานช์ feature และ git cherry-pick feature~2 จะหยิบคอมมิตที่สามนับจากท้าย
วิธีย้ายหลายคอมมิต
ระบุเป็นรายการ
สามารถส่งแฮชเป็นลิสต์ Git จะนำไปใช้ตามลำดับที่ระบุ และสร้างคอมมิตใหม่ตามจำนวนนั้น
git cherry-pick a1b2c3d 7c8d9e0 3f4a5b6
ลำดับสำคัญ: หากคอมมิตที่สองขึ้นอยู่กับคอมมิตแรก แต่คุณระบุสลับกัน จะเกิดความขัดแย้งหรือโค้ดที่พัง ควรระบุจากเก่าไปใหม่จะปลอดภัยกว่า
เป็นช่วง
สำหรับคอมมิตที่ต่อเนื่องกันใช้ไวยากรณ์ของช่วง มีกับดักที่ทุกคนพลาด: A..B หมายถึง "คอมมิตที่เข้าถึงได้จาก B แต่เข้าถึงไม่ได้จาก A" นั่นคือตัว A เองไม่ได้อยู่ในช่วง ไม่รวม
# ย้ายคอมมิตหลัง A จนถึง B รวมด้วย
git cherry-pick A..B
# ย้าย A และทุกอย่างจนถึง B รวมด้วย
git cherry-pick A^..B
หากต้องการย้ายทุกอย่างที่มีในบรานช์ feature แต่ไม่มีใน main สะดวกด้วย git cherry-pick main..feature แต่ถ้ามีคอมมิตจำนวนมาก ให้พิจารณาว่าอาจต้องใช้ rebase หรือ merge แทน cherry-pick
แฟล็กที่มีประโยชน์ของ git cherry-pick
| แฟล็ก | ทำอะไร | เมื่อไรควรใช้ |
|---|---|---|
-x | เพิ่มบรรทัด "(cherry picked from commit …)" ในข้อความ | เมื่อย้ายการแก้ไขระหว่างบรานช์สาธารณะ เพื่อให้เห็นที่มา |
-n, --no-commit | นำการเปลี่ยนแปลงไปยังดัชนีและไดเรกทอรีทำงานโดยไม่คอมมิต | ต้องการรวมหลายคอมมิตเป็นหนึ่ง หรือแก้ไขก่อนคอมมิต |
-e, --edit | เปิดเอดิเตอร์เพื่อแก้ไขข้อความ | ต้องการปรับข้อความให้เหมาะกับบรานช์ปลายทาง |
-s, --signoff | เพิ่มบรรทัด Signed-off-by | โปรเจกต์ที่ต้องการ DCO |
-m 1 | ระบุพาเรนต์ "หลัก" ของคอมมิต merge | ย้ายคอมมิต merge |
--ff | เลื่อนบรานช์ หาก HEAD คือพาเรนต์ของคอมมิตที่เลือก | นาน ๆ ครั้ง ช่วยไม่ให้เกิดสำเนาซ้ำ |
--allow-empty | อนุญาตให้ย้ายคอมมิตที่ว่างตั้งแต่แรก | คอมมิตว่างที่ใช้เป็นเครื่องหมาย |
ทำไมต้องใช้ -x
อีกหกเดือนมีคนเห็นการแก้ไขในบรานช์รีลีสและอยากรู้ว่ามาจากไหน บรรทัดที่เพิ่มโดย -x ให้คำตอบตรง ๆ:
git cherry-pick -x a1b2c3d
git log -1
แก้การหารด้วยศูนย์ในการคำนวณส่วนลด
(cherry picked from commit a1b2c3d4e5f60718293a4b5c6d7e8f9012345678)
ใช้ -x เมื่อคอมมิตต้นทางถูกเผยแพร่แล้ว สำหรับการย้ายจากบรานช์ท้องถิ่นของตัวเองที่จะลบภายหลัง ลิงก์จะชี้ไปที่ที่ไม่มีอยู่ จึงไม่จำเป็นต้องใช้แฟล็กนี้
รวมหลายคอมมิตเป็นหนึ่งด้วย -n
git cherry-pick -n a1b2c3d 7c8d9e0
git status # การเปลี่ยนแปลงของทั้งสองคอมมิตอยู่ในดัชนี
git commit -m "แก้ไขการคำนวณส่วนลด"
ความขัดแย้งระหว่าง cherry-pick และวิธีแก้
ความขัดแย้งเกิดเมื่อการเปลี่ยนแปลงของคอมมิตไม่สอดคล้องกับโค้ดปัจจุบัน คือบรรทัดเดียวกันในบรานช์ปลายทางมีหน้าตาต่างออกไปแล้ว Git จะหยุดและแจ้งให้ทราบ
git cherry-pick a1b2c3d
Auto-merging src/discount.js
CONFLICT (content): Merge conflict in src/discount.js
error: could not apply a1b2c3d... แก้การหารด้วยศูนย์ในการคำนวณส่วนลด
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git cherry-pick --continue".
จากนั้นมีสามทาง:
- แก้แล้วดำเนินการต่อ เปิดไฟล์ ลบเครื่องหมาย
<<<<<<<,=======,>>>>>>>เหลือเฉพาะเวอร์ชันที่ถูกต้อง แล้วรันgit add src/discount.jsและgit cherry-pick --continue - ข้ามคอมมิต เมื่อย้ายเป็นลิสต์
git cherry-pick --skipจะข้ามคอมมิตที่มีปัญหาและไปยังคอมมิตถัดไป - ยกเลิกทั้งหมด
git cherry-pick --abortจะคืนบรานช์ให้เป็นสถานะก่อนเริ่มการดำเนินการ
มี git cherry-pick --quit ด้วย ซึ่งหยุดการดำเนินการแต่คงคอมมิตที่นำไปใช้แล้วและสถานะไฟล์ปัจจุบันไว้ มีประโยชน์เมื่อย้ายสำเร็จไปครึ่งหนึ่งของลิสต์และต้องการทำต่อด้วยมือ
หากความขัดแย้งเกิดซ้ำ ๆ เช่น คุณย้ายการแก้ไขไปยังหลายบรานช์รีลีสเป็นประจำ ให้เปิดใช้ git config rerere.enabled true Git จะจำวิธีที่คุณแก้ความขัดแย้ง และนำวิธีนั้นไปใช้อัตโนมัติในครั้งถัดไป
วิธีย้ายคอมมิต merge
คอมมิต merge มีพาเรนต์สองตัว และ Git ไม่รู้ว่าจะคำนวณ diff เทียบกับตัวไหน หากไม่ให้คำแนะนำจะเกิดข้อผิดพลาด:
git cherry-pick 5d6e7f8
error: commit 5d6e7f8 is a merge but no -m option was given.
แฟล็ก -m 1 บอกว่า ให้คำนวณการเปลี่ยนแปลงเทียบกับพาเรนต์ตัวแรก ซึ่งมักคือบรานช์ที่ถูก merge เข้าไป ดังนั้นคุณจะย้ายทุกอย่างที่บรานช์นั้นนำมาในคอมมิตเดียว
git cherry-pick -m 1 5d6e7f8
โปรดทราบว่าหลังจากนี้ Git จะไม่ถือว่าบรานช์นั้นถูก merge แล้ว เมื่อ merge ในอนาคต Git อาจพยายามนำการเปลี่ยนแปลงเดิมไปใช้ซ้ำ
git cherry-pick และ git apply ต่างกันอย่างไร
git apply มักถูกนึกถึงคู่กับ cherry-pick เพราะทั้งสองคำสั่ง "นำการเปลี่ยนแปลงไปใช้" แต่ทำงานกับข้อมูลนำเข้าต่างกัน
| git cherry-pick | git apply | |
|---|---|---|
| แหล่งข้อมูล | คอมมิตที่มีอยู่ในรีโพซิทอรี | ไฟล์แพตช์ (diff) |
| สร้างคอมมิต | ใช่ (ถ้าไม่ใช้ -n) | ไม่ เพียงเปลี่ยนไฟล์ (กับ --index จะเปลี่ยนดัชนีด้วย) |
| เก็บผู้เขียนและข้อความ | ใช่ | ไม่ เพราะแพตช์ไม่มีข้อมูลเหล่านี้ |
| ความขัดแย้ง | merge สามทางพร้อมเครื่องหมาย | ค่าเริ่มต้นคือปฏิเสธ ด้วย --3way จะมีเครื่องหมาย |
| ต้องการรีโพซิทอรีร่วมกัน | ใช่ คอมมิตต้องเข้าถึงได้ในเครื่อง | ไม่ ส่งแพตช์ได้ทุกวิธี |
ตัวอย่างการใช้ git apply เมื่อไม่มีคอมมิตในรีโพซิทอรีของคุณ เช่น เพื่อนร่วมงานส่ง diff เป็นไฟล์มา:
# เพื่อนร่วมงานทำ
git diff main..fix-discount > fix.patch
# คุณตรวจสอบและนำไปใช้
git apply --check fix.patch # ตรวจว่าแพตช์จะนำไปใช้ได้หรือไม่
git apply fix.patch # นำไปใช้กับไดเรกทอรีทำงาน
git apply --3way fix.patch # หากไม่ตรงกัน ใช้เครื่องหมายความขัดแย้ง
หากต้องการส่งคอมมิตทั้งก้อน พร้อมผู้เขียนและข้อความ ใช้คู่คำสั่ง git format-patch และ git am อันแรกบันทึกคอมมิตเป็นไฟล์ อันหลังสร้างคอมมิตจากไฟล์เหล่านั้น โดยพื้นฐานแล้วคือ cherry-pick "ทางอีเมล"
ยังสามารถ cherry-pick จากรีโพซิทอรีอื่นได้ เพิ่มรีโพซิทอรีนั้นเป็น remote รัน git fetch แล้วคอมมิตจะใช้ได้ด้วยแฮช
เมื่อไรที่ cherry-pick เป็นความคิดที่ไม่ดี
Cherry-pick สร้างสำเนาซ้ำ การเปลี่ยนแปลงเดียวกันอยู่ในประวัติภายใต้สองแฮช ในปริมาณน้อยก็ปกติ แต่มีบางสถานการณ์ที่ทำให้เกิดปัญหา
- ย้ายหลายสิบคอมมิต. หากย้ายเกือบทั้งบรานช์ ควรใช้ rebase หรือ merge cherry-pick จะให้ประวัติซ้ำยาวและความขัดแย้งมากขึ้น
- ย้ายไปกลับ. คอมมิตถูกย้ายจาก feature ไป main แล้วภายหลัง feature ถูก merge เข้า main Git มักจัดการได้ (การเปลี่ยนแปลงตรงกัน) แต่ถ้าหลังย้ายมีการแก้บรรทัดเหล่านั้น จะเกิดความขัดแย้งโดยไม่จำเป็น
- คอมมิตที่พึ่งพากัน. คอมมิตใช้ฟังก์ชันที่เพิ่มในสองคอมมิตก่อนหน้า cherry-pick จะย้ายเฉพาะคอมมิตนั้น และโค้ดในบรานช์ปลายทางจะคอมไพล์ไม่ผ่าน ควรตรวจการคอมไพล์และเทสต์ทุกครั้งหลังย้าย
แนวปฏิบัติที่ดีสำหรับ hotfix คือทำการแก้ไขในบรานช์ที่เก่าที่สุดที่ยังรองรับ แล้ว merge "ขึ้นไป" ไปยังบรานช์ใหม่ เช่นนี้ cherry-pick จะเป็นข้อยกเว้นเท่านั้น
วิธียกเลิก cherry-pick
หากการดำเนินการยังค้างอยู่ (มีความขัดแย้ง) ให้รัน git cherry-pick --abort หากคอมมิตถูกสร้างแล้วและยังไม่ได้ส่งขึ้นเซิร์ฟเวอร์ ให้ลบออก:
git reset --hard HEAD~1
หากคอมมิตถูก push ไปยังบรานช์ที่ใช้ร่วมกันแล้ว ห้ามเขียนประวัติทับ ให้สร้างคอมมิตย้อนกลับแทน:
git revert 4e5f6a7
และหากคุณทำ reset แล้วเปลี่ยนใจ คอมมิตที่หายไปหาได้ผ่าน git reflog
วิธีตรวจว่าคอมมิตถูกย้ายไปแล้วหรือยัง
เนื่องจากแฮชต่างกัน git branch --contains ธรรมดาจะไม่ช่วย Git สามารถเปรียบเทียบคอมมิตตามเนื้อหาการเปลี่ยนแปลงได้ (patch-id):
git cherry -v release-1.4 feature
- a1b2c3d แก้การหารด้วยศูนย์ในการคำนวณส่วนลด
+ 9f8e7d6 เพิ่มหน้าจอชำระเงินใหม่
เครื่องหมายลบหมายความว่า การเปลี่ยนแปลงที่เทียบเท่ามีอยู่ใน release-1.4 แล้ว เครื่องหมายบวกหมายความว่ายังไม่มี ทางเลือกคือ git log --cherry-pick --oneline release-1.4...feature ซึ่งซ่อนคอมมิตคู่แฝด หากใช้ -x ก็ค้นจากข้อความได้เลย: git log --grep="cherry picked from commit a1b2c3d"
สรุป
git cherry-pick เป็นเครื่องมือเฉพาะจุด: นำ hotfix เข้ารีลีส ดึงคอมมิตที่มีประโยชน์จากบรานช์ที่ถูกทิ้ง หรือกู้คอมมิตที่ทำผิดบรานช์ จำไว้สามเรื่อง: คอมมิตใหม่ได้แฮชใหม่ ช่วง A..B ไม่รวม A และสำหรับบรานช์สาธารณะควรเพิ่ม -x หากต้องการย้ายไม่ใช่คอมมิตแต่เป็น diff จากไฟล์ ให้ใช้ git apply Rebase, stash, cherry-pick และแท็กถูกอธิบายและฝึกจริงในหลักสูตร Git
คำถามที่พบบ่อย
cherry-pick เปลี่ยนบรานช์ต้นทางหรือไม่?
ไม่ คอมมิตต้นฉบับอยู่ที่เดิม และในบรานช์ปัจจุบันจะมีสำเนาที่มีแฮชใหม่ปรากฏขึ้น
cherry-pick คอมมิตจากบรานช์รีโมตได้หรือไม่?
ได้ รัน git fetch ก่อน หลังจากนั้นคอมมิตจะเข้าถึงได้ด้วยแฮชหรือเป็น origin/ชื่อบรานช์ และส่งให้ git cherry-pick ได้
ทำไมหลัง cherry-pick คอมมิตจึงมีแฮชต่างกัน?
แฮชขึ้นกับพาเรนต์ เวลาคอมมิต และเนื้อหาของโครงสร้างไฟล์ สำเนามีพาเรนต์ต่างกันและเวลาของผู้คอมมิตต่างกัน แฮชจึงต่างด้วย
ผู้เขียนคอมมิตถูกเก็บไว้หรือไม่เมื่อ cherry-pick?
เก็บ ผู้เขียนและวันที่ของการเขียนมาจากคอมมิตต้นฉบับ ส่วนผู้คอมมิตจะเป็นคุณพร้อมวันที่ปัจจุบัน
ถ้า cherry-pick แจ้งว่าคอมมิตว่างจะทำอย่างไร?
หมายความว่าการเปลี่ยนแปลงนั้นมีอยู่ในบรานช์แล้ว ข้ามด้วย git cherry-pick --skip หรือบันทึกเป็นคอมมิตว่างด้วย git commit --allow-empty
หัวข้อนี้สอนอย่างละเอียดพร้อมฝึกปฏิบัติในคอร์ส “Git с нуля до уверенного разработчика”
ไปที่คอร์ส