วิธีการเลือกหลายเชอร์รี่


875

ฉันมีสองสาขา กระทำaเป็นหัวของหนึ่งในขณะที่อื่น ๆ ที่มีb, c, d, eและด้านบนของf aฉันต้องการที่จะย้ายc, d, eและสาขาแรกโดยไม่ต้องกระทำf bใช้เชอร์รี่รับมันเป็นเรื่องง่ายที่: เช็คเอาท์สาขาแรกเชอร์รี่เลือกหนึ่งโดยหนึ่งcไปfและ rebase สาขาที่สองบนแรก แต่มีวิธีใดที่จะเลือกเชอร์รี่ทั้งหมดc- fในคำสั่งเดียว?

นี่คือคำอธิบายภาพของสถานการณ์ (ขอบคุณJJD ):

ป้อนคำอธิบายรูปภาพที่นี่


3
rebase ที่คุณพูดถึงไม่เกี่ยวข้องกับคำถามจริงๆหรือ (ฉันเข้าใจว่าคุณอาจต้องการbใช้ในfภายหลัง แต่ไม่เกี่ยวข้องกับการเก็บเชอร์รี่)
Superole

คำตอบ:


1281

Git 1.7.2 แนะนำความสามารถในการเลือกช่วงเชอร์รี่ จากบันทึกประจำรุ่น :

git cherry-pickเรียนรู้ที่จะเลือกช่วงของการกระทำ (เช่นcherry-pick A..Bและcherry-pick --stdin) ทำเช่นนั้นgit revert; rebase [-i]แม้ว่าสิ่งเหล่านี้จะไม่สนับสนุนการควบคุมการเรียงลำดับที่ดีกว่า

หากต้องการเชอร์รี่เลือกกระทำทั้งหมดจากกระทำAเพื่อกระทำB(ที่Aเก่ากว่าB) เรียกใช้:

git cherry-pick A^..B

หากคุณต้องการละเว้น A เองให้รัน:

git cherry-pick A..B

(เครดิตไปที่ damian, JB Rainsberger และ sschaef ในความคิดเห็น)


249
ในรูปแบบ "cherry-pick A..B" A ควรจะแก่กว่า B หากคำสั่งผิดลำดับคำสั่งจะล้มเหลวอย่างเงียบ ๆ
Damian

294
นอกจากนี้สิ่งนี้จะไม่ใช่เชอร์รี่เลือก A แต่จะทำทุกอย่างหลังจาก A ถึงและรวมถึง B.
JB Rainsberger

455
หากต้องการรวมประเภท A justgit cherry-pick A^..B
kiritsuku

17
หากคุณมี git 1.7.1 หรือเก่ากว่าและไม่สามารถอัปเดตได้คุณสามารถเชอร์รี่รับได้อย่างรวดเร็วตามลำดับด้วยการวิ่งgit cherry-pick f~3แล้วgit cherry-pick f~2เป็นต้นไปจนถึงgit cherry-pick f(กดลูกศรขึ้นเพื่อรับคำสั่งก่อนหน้าเพื่อให้ฉันสามารถเปลี่ยนจำนวนและเรียกใช้ได้อย่างรวดเร็ว ควรคล้ายกันในคอนโซลส่วนใหญ่)
David Mason

19
อาจเป็นการดีที่จะรู้ว่าไวยากรณ์นี้ใช้ได้กับชื่อสาขาด้วย git cherry-pick master..somebranchจะเลือกคอมมิชชันทั้งหมดในแบรนช์ตั้งแต่มาสเตอร์ (สมมติว่ามีการรีบูทบนมาสเตอร์แล้ว) และนำไปใช้กับสาขาปัจจุบันของคุณ
Tor Klingberg

103

วิธีที่ง่ายที่สุดที่จะทำนี้กับตัวเลือกในการonto rebaseสมมติว่าสาขาที่เสร็จสิ้นในปัจจุบันที่aเรียกว่า mybranch และนี้เป็นสาขาที่คุณต้องการที่จะย้ายc- fบน

# checkout mybranch
git checkout mybranch

# reset it to f (currently includes a)
git reset --hard f

# rebase every commit after b and transplant it onto a
git rebase --onto a b

1
ขอบคุณ! คุณสามารถเพิ่มgit checkout secondbranch && git rebase mybranchคำตอบแบบเต็มได้ไหม
tig

1
คำตอบนี้ช่วยฉันได้มากในการทำความเข้าใจสิ่งที่เกิดขึ้นในสถานการณ์นี้ และ: คุณสามารถใช้rebaseโหมดโต้ตอบได้เช่นกัน ขอบคุณ @Charles!
Oliver

1
ความสวยงามของวิธีนี้คือคุณสามารถใช้--interactiveเพื่อลบการกระทำบางอย่างจากลำดับหรือเรียงลำดับใหม่ก่อน "เชอร์รี่เลือก" +1
Michael Merickel

นี่เป็นคำสั่งที่ฉลาดมากหากินไปรอบ ๆ แต่มันก็เป็นสิ่งมหัศจรรย์
Valerio

ไว้อาลัยที่คุณต้องให้คำมั่นสัญญาว่าคุณไม่ต้องการที่จะลดระดับเป็นหนึ่งในข้อโต้แย้ง ( bในตัวอย่างนี้) แต่ใช่สิ่งนี้ได้ผลสำหรับฉัน
asontu

85

หรือหนึ่งซับที่ร้องขอ:

git rebase --onto a b f

5
ถ้าเพียงเพราะความกะทัดรัดนี่เป็นคำตอบที่ดีที่สุด
Nate Chandler

9
อัปเดต แต่จะทำให้คุณอยู่ในสถานะ HEAD ที่แยกออกมาถ้า f เป็นกระทำ (ตรงข้ามกับสาขา) - คุณควรแก้ไขเพื่อเพิ่มสิ่งนั้นควรชำระเงินสาขาตามคำตอบด้านล่าง
Mr_and_Mrs_D

68

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

กรุณาเปิดภาพในแท็บใหม่ ...

ขั้นตอนการทำงาน

ในการสรุปคำสั่งในรูปแบบข้อความ:

  1. เปิดgitkเป็นกระบวนการอิสระโดยใช้คำสั่ง: gitk --all &.
  2. git rebase --onto a b fวิ่ง
  3. ข่าวF5ในgitk ไม่มีอะไรเปลี่ยนแปลง แต่ไม่มีการHEADทำเครื่องหมาย
  4. วิ่ง git branch selection
  5. ข่าวF5ในgitk สาขาใหม่ที่มีความมุ่งมั่นจะปรากฏขึ้น

สิ่งนี้ควรอธิบายสิ่งต่าง ๆ :

  • กระทำaคือปลายทางรากใหม่ของกลุ่ม
  • กระทำbคือกระทำก่อนที่จะกระทำครั้งแรกของกลุ่ม (พิเศษ)
  • กระทำfคือกระทำสุดท้ายของกลุ่ม (รวม)

หลังจากนั้นคุณสามารถใช้git checkout feature && git reset --hard bเพื่อลบการกระทำcจนfจากfeatureสาขา

นอกเหนือจากคำตอบนี้ฉันได้เขียนบล็อกโพสต์ซึ่งอธิบายคำสั่งในสถานการณ์อื่นซึ่งควรช่วยในการใช้งานโดยทั่วไป


2
หาก mybranch (a..f commits) ไม่ต้องการอีกต่อไปสิ่งนี้สามารถทำให้ง่ายขึ้นไปที่: git rebase --onto a b mybranchและ btw - โปรแกรมใดที่รูปภาพ git git ที่ดี?
Mr_and_Mrs_D

2
@Mr_and_Mrs_D ขอบคุณสำหรับความคิดเห็นของคุณ ฉันคิดว่าฉันใช้cacoo.comเพื่อวาดภาพ
JJD

48

ในการใช้ความคิดเห็นของ JB Rainsberger และ sschaef เพื่อตอบคำถามโดยเฉพาะ ... หากต้องการใช้ช่วงเชอร์รี่ที่รับในตัวอย่างนี้:

git checkout a
git cherry-pick b..f

หรือ

git checkout a
git cherry-pick c^..f

3
ฉันใช้git 2.7.0.windows.1และสังเกตเห็นว่าเมื่อฉันพยายามที่จะเชอร์รี่เลือกช่วงของการกระทำทุกอย่างก็โอเค แต่คอมไพล์ไม่ได้บอกคุณทุกที่ที่คุณต้องทำgit cherry-pick --continue | --abort | --quitก่อนที่จะพยายามที่จะกระทำ / เชอร์รี่เลือกอีกครั้ง ดังนั้นถ้าคุณเลือกที่จะรับช่วงเชอร์รี่คุณจะต้องวิ่งgit cherry-pick --continueทุกครั้งที่คุณพร้อม (แก้ไขข้อขัดแย้งหรืออื่น ๆ ) ด้วยความมุ่งมั่นจากช่วงที่กำหนด
kuskmen

ฉันทำแบบเดียวกัน แต่ร้ายแรง: หา 'a..b' ไม่ได้
Amit Karnik

ฉันไม่รู้ว่าฉันผิดตรงไหน แต่เมื่อฉัน 'git cherry-pick c ^ .. f' ที่ด้านข้างของฉันนี่รวมถึงการกระทำ f แต่ไม่ใช่การกระทำ c แต่เมื่อฉันอ่านทุกที่มันควรจะนิยาม c และ f อย่างครอบคลุม หรือฉันผิด
ซามูเอล

@Samuel ใช่ถูกต้องแล้ว ^หลังจากคจริงหมายถึง "กระทำก่อนที่จะค" ซึ่งเป็นขในกรณีนี้ นี่คือเหตุผลที่มีความหมายไปc^..f b..fลองทำgit log c^..fแล้วคุณจะเห็นความมุ่งมั่นเช่นเดียวกับที่คุณทำgit log b..f
Andy

41

หากคุณมีการแก้ไขแบบเลือกรวมเพื่อพูด A, C, F, J จาก A, B, C, D, E, F, G, H, I, J ให้คำมั่นสัญญาเพียงใช้คำสั่งด้านล่าง:

git cherry-pick ACFJ


1
ดีและเรียบง่าย
spinup

21
git rev-list --reverse b..f | xargs -n 1 git cherry-pick

2
ทำงานได้อย่างสมบูรณ์หากไม่มีข้อขัดแย้งมิฉะนั้น "rebase สู่" อาจทำได้ง่ายขึ้นเพราะคุณไม่ต้องคิดว่าจะหยุดที่ไหนและนำส่วนที่เหลือของแพทช์กลับมาใช้ใหม่
Ruslan Kabalin

6
โปรดเพิ่มความคิดเห็นเพื่ออธิบายสิ่งที่กำลังทำอยู่
Mr_and_Mrs_D

7
เนื่องจากไม่มีใครอธิบาย ... git rev-list จะพิมพ์การแก้ไขทั้งหมดจาก Branch b ถึง f (ตรงกันข้าม) ดังนั้นเมื่อแต่ละบรรทัด (การส่งแฮช) ถูกเรียงตามลำดับ iegit cherry-pick {hash of c}; git cherry-pick {hash of d}; ...
coderatchet

8

ในการเลือกเชอร์รี่จากรหัสยืนยันจนถึงปลายสาขาคุณสามารถใช้:

git cherry-pick commit_id^..branch_name


นี่เป็นส่วนหนึ่งของคำตอบstackoverflow.com/a/31640427/96823 แล้ว
tig

1
คำตอบนี้แตกต่างและเป็นประโยชน์กับฉัน มันระบุชื่อสาขาไม่ใช่การมอบหมาย SHA ครั้งสุดท้าย
Subtletree

7

ตัวแปรที่ควรค่าแก่การกล่าวถึงคือถ้าคุณต้องการให้คอมnมิตสุดท้ายจากสาขา~ไวยากรณ์อาจมีประโยชน์:

git cherry-pick some-branch~4..some-branch

ในกรณีนี้คำสั่งด้านบนจะเลือก 4 คอมมิทล่าสุดจากสาขาที่เรียกว่าsome-branch(แม้ว่าคุณสามารถใช้แฮชการคอมมิทแทนชื่อสาขา)


1
คำตอบที่มีประโยชน์มากขอบคุณ! :)
Jacek Dziurdzikowski

3

จริงๆแล้ววิธีที่ง่ายที่สุดในการทำคือ:

  1. บันทึกผสานฐานระหว่างสองสาขา: MERGE_BASE=$(git merge-base branch-a branch-b)
  2. กรอไปข้างหน้าหรือรีบูตสาขาที่เก่ากว่าไปยังสาขาที่ใหม่กว่า
  3. rebase สาขาที่เกิดขึ้นกับตัวเองเริ่มต้นที่ฐานผสานจากขั้นตอนที่ 1 และลบการกระทำที่ไม่ต้องการด้วยตนเอง:

    git rebase ${SAVED_MERGE_BASE} -i
    

    อีกทางเลือกหนึ่งหากมีข้อผูกพันใหม่เพียงไม่กี่ข้อให้ข้ามขั้นตอนที่ 1 และใช้งานง่าย

    git rebase HEAD^^^^^^^ -i
    

    ในขั้นตอนแรกให้ใช้พอที่^จะเลื่อนผ่านฐานผสาน

คุณจะเห็นบางอย่างเช่นนี้ในการตอบโต้เชิงโต้ตอบ:

pick 3139276 commit a
pick c1b421d commit b
pick 7204ee5 commit c
pick 6ae9419 commit d
pick 0152077 commit e
pick 2656623 commit f

จากนั้นลบบรรทัด b (และอื่น ๆ ที่คุณต้องการ)



0

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

https://gist.github.com/nickboldt/99ac1dc4eb4c9ff003a1effef2eb2d81

ในการเลือกรับจากสาขาของคุณเป็นหลัก (ใช้สาขาปัจจุบันเป็นแหล่งที่มา):

./gcpl.sh -m

หากต้องการเชอร์รี่เลือก 5 คอมมิตล่าสุดจาก 6.19.x สาขาของคุณเป็นมาสเตอร์:

./gcpl.sh -c 5 -s 6.19.x -t master

ทำไมสคริปต์นี้จะต้องใช้เมื่อคุณสามารถทำกับ Git ได้โดยตรง ...
code_dredd

พิมพ์น้อยลงและสคริปต์ของฉันจะเลือกการกระทำให้คุณโดยอัตโนมัติดังนั้นคุณไม่จำเป็นต้องเลือกเชอร์รี่แต่ละรายการด้วย SHA อย่างไรก็ตาม YMMV
nickboldt
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.