คู่มือ

git cherry-pick: วิธีย้ายคอมมิตเดียวไปยังบรานช์อื่น

อัปเดต: · Skillaria.Top

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".

จากนั้นมีสามทาง:

  1. แก้แล้วดำเนินการต่อ เปิดไฟล์ ลบเครื่องหมาย <<<<<<<, =======, >>>>>>> เหลือเฉพาะเวอร์ชันที่ถูกต้อง แล้วรัน git add src/discount.js และ git cherry-pick --continue
  2. ข้ามคอมมิต เมื่อย้ายเป็นลิสต์ git cherry-pick --skip จะข้ามคอมมิตที่มีปัญหาและไปยังคอมมิตถัดไป
  3. ยกเลิกทั้งหมด 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-pickgit 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 с нуля до уверенного разработчика”

ไปที่คอร์ส