ส่วนหนึ่งการเก็บผลเชอร์รี่กับ Git


501

ผมทำงานใน 2 สาขาที่แตกต่างกัน: การเปิดตัวและการพัฒนา

ฉันสังเกตเห็นว่าฉันยังคงต้องรวมการเปลี่ยนแปลงบางอย่างที่มุ่งมั่นในการเปิดสาขากลับเข้าไปในสาขา การพัฒนา

ปัญหาคือฉันไม่ต้องการความมุ่งมั่นทั้งหมดเพียงบาง hunks ในบางไฟล์ดังนั้นง่าย

git cherry-pick bc66559

ไม่ได้ทำเคล็ดลับ

เมื่อฉันทำ

git show bc66559

ฉันเห็นความแตกต่าง แต่ไม่รู้วิธีที่ดีในการนำส่วนนั้นไปใช้กับแผนผังการทำงานปัจจุบันของฉัน

คำตอบ:


792

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

หากต้องการใช้ร่วมกับ cherry-pick:

git cherry-pick -n <commit> # get your patch, but don't commit (-n = --no-commit)
git reset                   # unstage the changes from the cherry-picked commit
git add -p                  # make all your choices (add the changes you do want)
git commit                  # make the commit!

(ขอบคุณ Tim Henigan ที่เตือนฉันว่า git-cherry-pick มีตัวเลือก - ไม่ผูกมัดและขอบคุณ Felix Rabe สำหรับการชี้ให้เห็นว่าคุณต้องรีเซ็ต! หากคุณต้องการทิ้งบางสิ่งออกไป คุณสามารถใช้git reset <path>...เพื่อ unstage เฉพาะไฟล์เหล่านั้น)

แน่นอนคุณสามารถระบุเส้นทางเฉพาะadd -pหากจำเป็น หากคุณกำลังเริ่มต้นด้วยแพทช์คุณสามารถแทนที่ด้วยcherry-pickapply


หากคุณต้องการจริงๆgit cherry-pick -p <commit>(ไม่มีตัวเลือกนั้น) คุณสามารถใช้

git checkout -p <commit>

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


ที่จริงแล้วถ้าฉันทำตามคำแนะนำด้วย git 1.7.5.4 'git add -p' บอกว่า 'ไม่มีการเปลี่ยนแปลง' เพราะมันอยู่ในดัชนีอยู่แล้ว ฉันต้องทำการ 'รีเซ็ต git HEAD' ก่อน 'git add' - วิธีใดที่จะหลีกเลี่ยงการรีเซ็ตด้วยตัวเลือกบางอย่าง?
เฟลิกซ์ Rabe

@FelixRabe: ฉันแปลกใจจริงว่าในบางจุดcherry-pick -nที่เห็นได้ชัดไม่ปล่อยให้การเปลี่ยนแปลงฉาก - การประชุมแน่นอนว่า--no-commitตัวเลือกหยุดขวาก่อนที่จะกระทำเช่นที่มีการเปลี่ยนแปลงทุกฉาก ฉันจะเพิ่มการรีเซ็ตลงในคำตอบ
Cascabel

1
@Blixt นั่นคือถ้ากระทำที่อยู่ในสาขาอื่น ๆ แต่ไม่สาขาปัจจุบันของคุณเป็น ABCDEF, git checkout -p <F>ไม่ได้เพียงแค่คุณได้รับการเปลี่ยนแปลงจาก F มันทำให้คุณได้รับ ABCDEF ทั้งหมดบดเข้าด้วยกันและช่วยให้คุณสามารถจัดเรียงสิ่งที่เป็นส่วนหนึ่งของที่คุณต้องการ . การยึดติดกับการเปลี่ยนแปลงบางอย่างจาก F เป็นความเจ็บปวด ในทางกลับกันgit cherry-pick -n <F>คุณจะได้รับเฉพาะการเปลี่ยนแปลงจาก F - และหากการเปลี่ยนแปลงบางอย่างขัดแย้งกันมันจะบอกคุณอย่างเป็นประโยชน์เพื่อให้คุณสามารถหาวิธีผสานได้อย่างถูกต้อง
Cascabel

ฉันมีปัญหากับสิ่งนี้เมื่อการเปลี่ยนแปลงเป็นการเพิ่มไฟล์ git resetจะลบไฟล์ที่จัดฉากและadd -pก็จะพูดว่า 'ไม่มีอะไรที่จะเพิ่ม'
Ian Grainger

72

ฉันรู้ว่าฉันกำลังตอบคำถามเก่า แต่ดูเหมือนว่ามีวิธีใหม่ในการทำเช่นนี้กับการตรวจสอบแบบโต้ตอบ:

git checkout -p bc66559

ให้เครดิตฉันสามารถเลือกล่าสัตว์จากคอมมิวนิตี้คอมมิชชันอื่น ๆ


36

สมมติว่าการเปลี่ยนแปลงที่คุณต้องการอยู่ที่ส่วนหัวของสาขาที่คุณต้องการเปลี่ยนแปลงใช้ git checkout

สำหรับไฟล์เดียว:

git checkout branch_that_has_the_changes_you_want path/to/file.rb

สำหรับหลาย ๆ ไฟล์เพียงแค่เดซี่เชน:

git checkout branch_that_has_the_changes_you_want path/to/file.rb path/to/other_file.rb

5
คัดลอกไฟล์ทั้งหมด: ไม่เพียง แต่การเปลี่ยนแปลงเท่านั้น
Jeremy List

1
คำตอบนี้เช่นเดียวกับคำตอบอื่น ๆ ที่นี่จนถึงขณะนี้มีข้อเสียเปรียบอย่างมาก: มันไม่ได้รักษาผู้แต่งดั้งเดิมของการเปลี่ยนแปลงไว้แทนที่จะมุ่งมั่นภายใต้ชื่อของคุณ หากการเปลี่ยนแปลงนั้นดีคุณกำลังขโมยเครดิตของใครบางคนหากการเปลี่ยนแปลงนั้นไม่ดี ดูเหมือนว่าจะไม่มีทางที่จะมี git cherry-pick-p และน่าละอายที่มันยังไม่มีอยู่
pfalcon

15

อาคารไมค์ Monkiewiczตอบคุณยังสามารถระบุไฟล์เดียวหรือมากกว่าที่จะเช็คเอาท์จากที่จัด sha1 / สาขา

git checkout -p bc66559 -- path/to/file.java 

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


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

1

หากคุณต้องการระบุรายการไฟล์ในบรรทัดคำสั่งและทำทุกอย่างให้เสร็จในคำสั่ง atomic เดียวให้ลอง:

git apply --3way <(git show -- list-of-files)

--3way: หากแพทช์ไม่ได้ใช้อย่างหมดจด Git จะสร้างความขัดแย้งในการผสานเพื่อให้คุณสามารถทำงานgit mergetoolได้ การไม่ใช้งาน--3wayจะทำให้ Git ยอมแพ้กับซอฟต์แวร์ที่ไม่ได้ใช้อย่างหมดจด


0

หาก "การหยิบเชอร์รี่บางส่วน" หมายถึง "ภายในไฟล์เลือกการเปลี่ยนแปลงบางอย่าง แต่การละทิ้งคนอื่น" สามารถทำได้โดยการนำเข้าgit stash:

  1. เลือกเชอร์รี่เต็ม ๆ
  2. git reset HEAD^ เพื่อแปลงความมุ่งมั่นทั้งหมดของเชอร์รี่ให้กลายเป็นการเปลี่ยนแปลงการทำงานที่ไม่คงที่
  3. ตอนนี้git stash save --patch: เลือกเนื้อหาที่ไม่ต้องการเพื่อซ่อน
  4. Git ย้อนกลับการเปลี่ยนแปลงที่เก็บไว้จากสำเนาการทำงานของคุณ
  5. git commit
  6. git stash dropทิ้งสะสมของการเปลี่ยนแปลงที่ไม่พึงประสงค์:

เคล็ดลับ: หากคุณให้ที่ซ่อนของการเปลี่ยนแปลงที่ไม่ต้องการชื่อ: git stash save --patch junkถ้าคุณลืมที่จะทำ (6) ตอนนี้ในภายหลังคุณจะรู้จักที่ซ่อนสำหรับสิ่งที่มันเป็น


ถ้าคุณแค่หยิบเชอร์รี่แล้วรีเซ็ต ... คุณจะไม่เก็บอะไรเลย ดังที่ได้กล่าวไว้ข้างต้นคุณต้องเลือกเชอร์รี่กับ - ไม่ยอมรับหรือรีเซ็ต - ฮาร์ดเฮด ~ โปรดทราบว่าคุณกำลังดำเนินการในเชิงลบ (เลือกสิ่งที่คุณไม่ต้องการ) วิธีการแก้ปัญหาที่ได้รับการยอมรับข้างต้นอนุญาตให้ใช้วิธีบวกหรือลบ
Pierre-Olivier Vares

0

ใช้git format-patchเพื่อแบ่งส่วนของความมุ่งมั่นที่คุณสนใจและgit amนำไปใช้กับสาขาอื่น

git format-patch <sha> -- path/to/file
git checkout other-branch
git am *.patch
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.