git cherry-pick กล่าวว่า“ … 38c74d เป็นการผสาน แต่ไม่มีการเลือกตัวเลือก -m”


518

ฉันทำการเปลี่ยนแปลงบางอย่างในสาขาหลักของฉันและต้องการนำทวนเหล่านั้น เมื่อฉันเลือกเชอร์รี่ต่อไปนี้ฉันจะติด fd9f578 เมื่อ git พูดว่า:

$ git cherry-pick fd9f578
fatal: Commit fd9f57850f6b94b7906e5bbe51a0d75bf638c74d is a merge but no -m option was given.

คอมไพล์กำลังพยายามบอกอะไรกับฉันและเลือกสิ่งที่ถูกต้องกับการใช้เชอร์รี่ที่นี่? สาขาหลักจะรวมถึงการเปลี่ยนแปลงไฟล์ที่ได้รับการแก้ไขในสาขาอัปสตรีมดังนั้นฉันแน่ใจว่าจะมีข้อขัดแย้งในการผสานบางอย่าง แต่สิ่งเหล่านั้นไม่ได้เลวร้ายเกินกว่าที่จะทำให้ตรงได้ ฉันรู้ว่าต้องเปลี่ยนแปลงอะไรบ้าง

สิ่งเหล่านี้คือความมุ่งมั่นที่ฉันต้องการนำมาใช้

e7d4cff added some comments...
23e6d2a moved static strings...
44cc65a incorporated test ...
40b83d5 whoops delete whitspace...
24f8a50 implemented global.c...
43651c3 cleaned up ...
068b2fe cleaned up version.c ...
fd9f578 Merge branch 'master' of ssh://extgit/git/sessions_common
4172caa cleaned up comments in sessions.c ...

คำตอบ:


606

วิธีที่เชอร์รี่เลือกโดยการใช้ดิฟเป็นเซ็ตการแก้ไข (ความแตกต่างระหว่างต้นไม้ทำงานที่จุดนั้นและต้นไม้ทำงานของพ่อแม่) และนำไปใช้กับสาขาปัจจุบันของคุณ

ดังนั้นถ้าคอมมิทมีพ่อแม่สองคนขึ้นไปมันก็แสดงให้เห็นถึงความแตกต่างอย่างน้อยสองอัน - อันไหนที่ควรใช้?

คุณกำลังพยายามเลือกเชอร์รี่fd9f578ซึ่งเป็นการผสานกับผู้ปกครองสองคน ดังนั้นคุณต้องบอกคำสั่ง cherry-pick ว่าคำตอบใดที่ควรคำนวณโดยใช้-mตัวเลือก ตัวอย่างเช่นเมื่อgit cherry-pick -m 1 fd9f578ต้องการใช้พาเรนต์ 1 เป็นฐาน

ฉันไม่สามารถพูดได้อย่างแน่นอนสำหรับสถานการณ์เฉพาะของคุณ แต่โดยทั่วไปจะแนะนำให้ใช้git mergeแทน git cherry-pickเมื่อคุณเชอร์รี่เลือกผสานกระทำก็ทรุดฮวบลงทุกการเปลี่ยนแปลงที่เกิดขึ้นในผู้ปกครองที่คุณไม่ได้ระบุที่จะ-mเข้าสู่ที่หนึ่งกระทำ คุณสูญเสียประวัติทั้งหมดของพวกเขาและเยือกเย็นความแตกต่างทั้งหมดของพวกเขา การโทรของคุณ


3
@ วูฟูคุณควรเรียนรู้เกี่ยวกับgit rebaseมันด้วย - มันเหมือนกับการผสาน แต่แทนที่จะรวมสองสาขาเข้าด้วยกันมันจะทำการปลูกถ่ายกิ่งหนึ่งเพื่อนั่งอยู่บนอีกฝั่งหนึ่ง
Borealid

91
คุณจะรู้หมายเลขผู้ปกครองได้อย่างไร
Anentropic

66
@Anentropic 1 คือ "ผู้ปกครองคนแรก" 2 คนคือ "ผู้ปกครองที่สอง" และอื่น ๆ คำสั่งซื้อเป็นสิ่งที่พวกเขาอยู่ในรายการกระทำ (ตามที่ดูgit showและไม่ชอบ)
Borealid

2
@lkraav คุณสามารถทำได้เพียงgit reset --hard HEAD@{1}เพื่อคืนความผูกพันที่หายไป git resetไม่ได้ถูก จำกัด ให้ย้าย "ไปข้างหลัง" ในประวัติศาสตร์ git checkout -b mybranch HEAD@{1}ก็จะทำงานเช่นกัน
Borealid

4
คำเตือน: git mergeอาจมีผลกระทบที่ไม่ตั้งใจ คำสั่งนั้นจะเพิ่มการคอมมิท (เก่า) อื่น ๆ ทั้งหมดที่มีอยู่ในสาขาพาเรนต์ คนมักจะเลือกที่จะเลือกเชอร์รี่เพราะพวกเขาไม่ต้องการให้คนอื่นทำ ให้แน่ใจว่าคุณตรวจสอบอีกครั้งว่าคุณกำลังดำเนินการเปลี่ยนแปลงที่คุณต้องการเท่านั้น!
Kay V

52

-m หมายถึงหมายเลขผู้ปกครอง

จาก git doc:

โดยปกติแล้วคุณไม่สามารถเลือกการรวมแบบเชอร์รี่ได้เนื่องจากคุณไม่ทราบว่าการผสานด้านใดที่ควรพิจารณาว่าเป็นการฉีด ตัวเลือกนี้ระบุหมายเลขพาเรนต์ (เริ่มจาก 1) ของการฉีดและอนุญาตให้ cherry-pick ทำการเล่นซ้ำการเปลี่ยนแปลงที่สัมพันธ์กับพาเรนต์ที่ระบุ

ตัวอย่างเช่นหากทรีทเนอร์ของคุณเป็นดังนี้:

- A - D - E - F -   master
   \     /
    B - C           branch one

จากนั้นgit cherry-pick Eจะสร้างปัญหาที่คุณเผชิญ

git cherry-pick E -m 1หมายถึงการใช้D-Eในขณะที่วิธีการใช้git cherry-pick E -m 2B-C-E


32

@ คำตอบของ Borealid นั้นถูกต้อง แต่สมมติว่าคุณไม่สนใจที่จะรักษาประวัติศาสตร์การรวมสาขาที่แน่นอนและต้องการที่จะเลือกรุ่นเชิงเส้นของเชอร์รี่ นี่เป็นวิธีที่ง่ายและปลอดภัยในการทำเช่นนั้น:

เริ่มต้นรัฐ: คุณอยู่ในสาขาและคุณต้องการที่จะเชอร์รี่เลือกกระทำXY..Z

  1. git checkout -b tempZ Z
  2. git rebase Y
  3. git checkout -b newX X
  4. git cherry-pick Y..tempZ
  5. (ไม่จำเป็น) git branch -D tempZ

สิ่งนี้จะสามารถที่จะสร้างสาขาtempZขึ้นอยู่กับZแต่มีประวัติความเป็นมาจากYเชิงเส้นเป็นต้นไปและจากนั้นเชอร์รี่เลือกที่ลงบนสำเนาที่เรียกว่าX newX(มันปลอดภัยที่จะทำเช่นนี้ในสาขาใหม่มากกว่าที่จะกลายพันธุ์X.) แน่นอนว่าอาจจะมีความขัดแย้งในขั้นตอนที่ 4 ซึ่งคุณจะต้องแก้ปัญหาในทางปกติ ( cherry-pickทำงานอย่างมากเช่นrebaseในส่วนที่) ในที่สุดก็จะลบtempZสาขาชั่วคราว

หากขั้นตอนที่ 2 ให้ข้อความ "ปัจจุบันสาขา tempZ เป็นรุ่นล่าสุด" แสดงว่าY..Zเป็นเชิงเส้นอยู่แล้วดังนั้นให้ละเว้นข้อความนั้นและดำเนินการตามขั้นตอนที่ 3 เป็นต้นไป

จากนั้นตรวจสอบnewXและดูว่าทำในสิ่งที่คุณต้องการหรือไม่

(หมายเหตุ: นี่ไม่เหมือนแบบเรียบง่ายgit rebase Xเมื่ออยู่ในสาขาZเพราะมันไม่ได้ขึ้นอยู่กับความสัมพันธ์ระหว่างXและY; อาจมีข้อผูกพันระหว่างบรรพบุรุษร่วมกับYคุณไม่ต้องการ)


1
git rebase Yพูดว่าCurrent branch tempZ is up to date
Basilevs

ฉันคิดว่านั่นหมายความว่าY..Zเป็นเส้นตรงแล้ว ดังนั้นคุณสามารถละเว้นข้อความนั้นและดำเนินการตามขั้นตอนที่ 3 และ 4
Daira Hopwood

1
แนวคิดที่น่าสนใจฉันต้องวาดลงบนกระดาษเพื่อชื่นชมสิ่งที่เกิดขึ้น = D
Chris

2
สุกใส คอมไพล์เชอร์รี่เลือกสำหรับทั้งช่วงบ่นอย่างใดอย่างหนึ่งว่าตัวเลือก -m หายไปหรือว่ามันก็มีให้ ทางออกของคุณเป็นสีทอง (คำแนะนำเดียว: ลบสาขา tempZ หลังจาก)
Otheus

1
มันอัศจรรย์มาก! ฉันดิ้นรนกับการเก็บเชอร์รี่และมันก็สมเหตุสมผลดี ฉันมีปัญหาเล็กน้อยกับตัวอักษรที่เลือก (บางสาขาและคอมมิทเป็นตัวพิมพ์ใหญ่และบางสาขาเป็นตัวพิมพ์เล็ก)
pcarvalho

19

ลดความซับซ้อน เชอร์รี่รับความมุ่งมั่น อย่าเชอร์รี่เลือกการผสาน

ต่อไปนี้เป็นคำตอบที่ได้รับการยอมรับใหม่ซึ่งจะอธิบายข้อดี / ความเสี่ยงของแนวทางที่เป็นไปได้อย่างชัดเจน:

คุณกำลังพยายามเลือกเชอร์รี่ fd9f578 ซึ่งเป็นการรวมกับผู้ปกครองสองคน

แทนที่จะรวมเชอร์รี่กับการเลือกสิ่งที่ง่ายที่สุดคือการเลือกเชอร์รี่ที่คุณต้องการจากแต่ละสาขาในการผสาน

เมื่อคุณรวมแล้วอาจเป็นไปได้ทั้งหมดที่คุณต้องการจะอยู่ในรายการของคุณ เชอร์รี่เลือกพวกเขาโดยตรงและคุณไม่จำเป็นต้องยุ่งกับการกระทำที่ผสาน

คำอธิบาย

วิธีที่เชอร์รี่เลือกโดยการใช้ดิฟที่มีเซ็ตการแก้ไข (ความแตกต่างระหว่างแผนผังการทำงานที่จุดนั้นและแผนผังการทำงานของพาเรนต์) และการใช้เซ็ตการแก้ไขกับสาขาปัจจุบันของคุณ

หากการกระทำมีผู้ปกครองสองคนขึ้นไปเช่นกรณีที่มีการรวมการกระทำนั้นจะแสดงถึงความแตกต่างอย่างน้อยสองรายการ ข้อผิดพลาดเกิดขึ้นเนื่องจากความไม่แน่นอนที่แตกต่างกันซึ่งควรใช้

ทางเลือก

หากคุณพิจารณาว่าคุณจำเป็นต้องรวมการรวม vs การเลือกเชอร์รี่ที่เกี่ยวข้องคุณมีสองตัวเลือก:

  1. (ซับซ้อนและคลุมเครือยิ่งกว่านั้นจะละทิ้งประวัติ) คุณสามารถระบุผู้ปกครองที่ควรใช้

    • ใช้-mตัวเลือกในการทำเช่นนั้น ตัวอย่างเช่นgit cherry-pick -m 1 fd9f578จะใช้พาเรนต์แรกที่ระบุในการผสานเป็นฐาน

    • นอกจากนี้ให้พิจารณาด้วยว่าเมื่อคุณเลือกรวมการกระทำมันจะยุบการเปลี่ยนแปลงทั้งหมดที่เกิดขึ้นในพาเรนต์ที่คุณไม่ได้ระบุ-mไว้ในการคอมมิชชันนั้น คุณสูญเสียประวัติทั้งหมดของพวกเขาและเยือกเย็นความแตกต่างทั้งหมดของพวกเขา การโทรของคุณ

  2. (ที่เรียบง่ายและมีความคุ้นเคยมากขึ้นเก็บรักษาประวัติ) คุณสามารถใช้แทนgit mergegit cherry-pick

    • ตามปกติด้วยgit mergeจะพยายามใช้การกระทำทั้งหมดที่มีอยู่ในสาขาที่คุณกำลังรวมและรายการพวกเขาเป็นรายบุคคลในบันทึก git ของคุณ

2

ความเรียบง่ายของวิธีการ @Daira Hopwood ที่ดีสำหรับการเลือกหนึ่งคอมมิท ไม่ต้องการสาขาชั่วคราว

ในกรณีของผู้แต่ง:

  • Z ต้องการส่งมอบ (fd9f578)
  • Y กระทำก่อนหน้านี้
  • X สาขาการทำงานปัจจุบัน

จากนั้นทำ:

git checkout Z   # move HEAD to wanted commit
git reset Y      # have Z as changes in working tree
git stash        # save Z in stash
git checkout X   # return to working branch
git stash pop    # apply Z to current branch
git commit -a    # do commit

2
หลักสูตรนี้สูญเสียข้อมูลเมตาที่เกี่ยวข้องกับการส่งต้นฉบับ ฉันเดาว่ามันเป็นเรื่องของความเห็นไม่ว่าจะง่ายกว่านี้ ฉันจะใช้มันบางครั้งเมื่อฉันต้องการที่จะสูญเสียเมตาดาต้าและทำให้การเปลี่ยนแปลงรหัสโดยรวมเท่านั้น โปรดทราบว่ามันใช้งานได้แม้ว่า Y จะไม่ได้เป็นพาเรนต์ทันทีของ Z (ในกรณีนี้การเปลี่ยนแปลงจะถูกแบน)
Daira Hopwood
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.