วิธีการรวมการคอมมิทเฉพาะใน Git


1034

ฉันแยกสาขาจากที่เก็บใน GitHub และส่งมอบสิ่งที่เฉพาะเจาะจงให้ฉัน HEADตอนนี้ผมพบว่าพื้นที่เก็บข้อมูลเดิมมีคุณลักษณะที่ดีซึ่งเป็นที่

ฉันต้องการที่จะรวมมันโดยไม่ต้องกระทำก่อนหน้านี้ ฉันควรทำอย่างไรดี? ฉันรู้วิธีผสานการกระทำทั้งหมด:

git branch -b a-good-feature
git pull repository master
git checkout master
git merge a-good-feature
git commit -a
git push

หากคุณกำลังพยายามทำสิ่งนี้เกี่ยวกับ GitHub บทความนี้จะนำคุณเข้าสู่ขั้นตอนนี้ markosullivan.ca/how-to-handle-a-pull-request-from-github
johndpope

คำตอบ:


1174

' git cherry-pick' ควรเป็นคำตอบของคุณที่นี่

ใช้การเปลี่ยนแปลงที่แนะนำโดยการกระทำที่มีอยู่

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

A-----B------C
 \
  \
   D

กลายเป็น:

A-----B------C
 \
  \
   D-----C'

ปัญหาของการคอมมิทนี้คือคอมไพล์พิจารณาแล้วว่าจะรวมประวัติทั้งหมดก่อนหน้าพวกเขา

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

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


1
@ openid000: "กิ่งเล็ก ๆ ที่ละเอียดยิ่งขึ้น": ซึ่งเป็นสิ่งที่ bdonlan แนะนำในคำตอบของเขา
VonC

8
หมายเหตุ: "git rebase" จะเปลี่ยน SHA-1 ด้วย ดูเพิ่มเติมที่ "การรีบูท git vs. git merge ( stackoverflow.com/questions/804115/git-rebase-vs-git-merge ) และ" git เวิร์กโฟลว์ "( stackoverflow.com/questions/457927/ … ) สำหรับกรณีที่" รีบูท git "ถูกต้องตามกฎหมาย
VonC

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

@VonC "กิ่งเล็กเนื้อละเอียด" ใช่ ฉันมีสองสาขาและฉันได้อัปเกรดเป็นโมดูลการสร้างภาพข้อมูลเฉพาะในสาขาเดียว โมดูลนี้เป็นอิสระจากรหัสอื่น ๆ ทั้งหมดดังนั้นเชอร์รี่เลือกได้รับความสะดวกในการใช้การเปลี่ยนแปลงเหล่านี้ไปยังสาขาอื่นเช่นกัน
Cheeku

1
แต่โปรดทราบว่าเมื่อคุณรวมทั้งคอมมิชชัน C และ C จะเหนือกว่าในประวัติศาสตร์การคอมมิท
ราหุลชาห์

738

คุณสามารถใช้ git cherry-pick เพื่อใช้การคอมมิทเดี่ยวด้วยตัวเองกับสาขาปัจจุบันของคุณ

ตัวอย่าง: git cherry-pick d42c389f


68
+1 สำหรับโพสต์เดิมของคุณในการเก็บเชอร์รี่ ( stackoverflow.com/questions/880957/… ) ฉันเอาเสรีภาพในการคัดลอกสารสกัดจากมันในคำตอบของฉันเองข้างต้น
VonC

4
อาจgit cherry-pick d42cหรือgit cherry-pick d42c3 จะทำงาน Git นั้นฉลาด ;)
guneysus

2
ร้ายแรง: การแก้ไขที่ไม่ดี
Ievgen Naida

2
ฉันเพิ่งทำคำสั่งนี้และดูเหมือนว่าจะได้ทำงาน แต่เมื่อฉันทำสถานะคอมไพล์มันบอกว่า "ไม่มีอะไรที่จะกระทำทำความสะอาดต้นไม้ทำงาน" เมื่อฉันรีเฟรชหน้า Commits ในเว็บเพจ bitbucket ของฉันมันจะไม่ปรากฏขึ้น แต่มันจะปรากฏขึ้นเมื่อฉันรันบันทึก git และฉันเห็นรหัสที่แก้ไขแล้ว บางคนสามารถอธิบายได้หรือไม่หากฉันต้องทำตามขั้นตอนเพิ่มเติม
Ray

1
น่าเสียดายที่นี่ไม่ได้ตอบคำถาม: มันไม่ได้สร้างการผสาน d42c389fมีบรรพบุรุษชี้ไปไม่ได้ บางที OP ไม่สนใจเกี่ยวกับการสร้างผสานแต่ความแตกต่างก็มีความสำคัญ
LarsH

29

ลองทำตัวอย่างและทำความเข้าใจ:

ฉันมีสาขาพูดหลักชี้ไปที่ X <commit-id> และฉันมีสาขาใหม่ที่ชี้ไปที่ Y <sha1>

โดยที่Y <commit-id> = <master> ส่งมอบสาขา - กระทำไม่กี่ครั้ง

ตอนนี้พูดสำหรับสาขา Y ฉันต้องปิดช่องว่างความผูกพันระหว่างสาขาหลักและสาขาใหม่ ด้านล่างเป็นขั้นตอนที่เราสามารถทำตาม:

ขั้นตอนที่ 1:

git checkout -b local origin/new

โดย local คือชื่อสาขา สามารถตั้งชื่อใด ๆ ได้

ขั้นตอนที่ 2:

  git merge origin/master --no-ff --stat -v --log=300

รวมการกระทำจากสาขาหลักไปยังสาขาใหม่และสร้างการรวมข้อความคอมมิชชันที่มีคำอธิบายหนึ่งบรรทัดจาก <n> การคอมมิชชันที่เกิดขึ้นจริงที่ถูกรวมเข้าด้วยกัน

สำหรับข้อมูลเพิ่มเติมและพารามิเตอร์เกี่ยวกับการรวม Git โปรดดูที่:

git merge --help

นอกจากนี้หากคุณต้องการรวมการกระทำที่เฉพาะเจาะจงคุณสามารถใช้:

git cherry-pick <commit-id>

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

ฉันจะทำสิ่งนั้นได้อย่างไรจากจุดที่แน่นอนของสาขาที่ฉันต้องการรวม
Kulbhushan Singh

3

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

ในกรณีนี้การเลือกเชอร์รี่ไม่ใช่ตัวเลือกที่ดี อย่างไรก็ตามเราสร้าง local-branch จาก commit-id จากนั้นทำการรวม local-branch เพื่อทำการ master และทำการตรวจสอบ mvn clean (เราใช้ maven) หากสำเร็จให้ปล่อยสิ่งประดิษฐ์เวอร์ชันการผลิตให้กับ nexus โดยใช้ปลั๊กอินการปล่อย maven ที่มี localCheckout = ตัวเลือกจริงและ pushChanges = false ในที่สุดเมื่อทุกอย่างประสบความสำเร็จจากนั้นผลักดันการเปลี่ยนแปลงและแท็กไปยังแหล่งกำเนิด

ตัวอย่างโค้ด:

สมมติว่าคุณอยู่ในระดับปริญญาโทถ้าทำด้วยตนเอง อย่างไรก็ตามในเจนกินส์เมื่อคุณชำระเงิน repo คุณจะอยู่ในสาขาเริ่มต้น (ต้นแบบถ้ากำหนดค่า)

git pull  // Just to pull any changes.
git branch local-<commitd-id> <commit-id>  // Create a branch from the given commit-id
git merge local-<commit-id>  // Merge that local branch to master.
mvn clean verify   // Verify if the code is build able
mvn <any args> release:clean release:prepare release:perform // Release artifacts
git push origin/master  // Push the local changes performed above to origin.
git push origin <tag>  // Push the tag to origin

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

อย่าลังเลที่จะให้คำแนะนำในกรณีที่มีตัวเลือกที่ดีกว่า


3

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

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

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

คุณสามารถทำได้จริงgit merge --no-commitและปรับดัชนีด้วยตนเองเพื่อลบการเปลี่ยนแปลงที่คุณไม่ต้องการแทน

สมมติว่าคุณอยู่ในสาขาAและคุณต้องการที่จะรวมการกระทำที่ปลายสาขาB:

git checkout A
git merge --no-commit B

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

(อาจมีวิธีง่ายๆในการตั้งค่าสถานะของไดเรกทอรีทำงานและดัชนีกลับไปทางก่อนที่จะผสานเพื่อให้คุณมีกระดานชนวนที่สะอาดเพื่อที่จะเลือกความมุ่งมั่นที่คุณต้องการตั้งแต่แรก ฉันไม่ทราบวิธีการบรรลุกระดานชนวนสะอาดgit checkout HEADและgit reset HEADทั้งสองจะลบสถานะผสานเอาชนะวัตถุประสงค์ของวิธีนี้)

ดังนั้นเลิกทำการเปลี่ยนแปลงที่ไม่ต้องการด้วยตนเอง ตัวอย่างเช่นคุณสามารถ

git revert --no-commit 012ea56

สำหรับการกระทำที่ไม่พึงประสงค์แต่ละ012ea56ครั้ง

เมื่อคุณปรับสิ่งต่าง ๆ เสร็จแล้วให้สร้างการกระทำของคุณ:

git commit -m "Merge in commit 823749a from B which tweaked the timeout code"

ตอนนี้คุณมีเพียงการเปลี่ยนแปลงที่คุณต้องการและต้นไม้ตระกูลแสดงให้เห็นว่าคุณรวมทางเทคนิคจาก B

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