สาขาหลักและ 'ต้นกำเนิด / ต้นแบบ' ได้แยกออกจากกันวิธีการ 'แยก' สาขา '


964

ไม่ว่าอาจารย์และสาขาต้นกำเนิด / หลักของฉันจะแยกกัน
จริง ๆ แล้วฉันไม่ต้องการให้พวกเขาแตกต่าง

ฉันจะดูความแตกต่างเหล่านี้และ 'รวม' พวกเขาได้อย่างไร


2
คุณหมายถึงอะไรโดยการเบี่ยงเบน คุณ rebase เจ้านายของคุณหลังจากกดมัน?
hasen

13
ฉันได้รับข้อความแจ้งว่า "สาขาและ 'ต้นกำเนิด / ปรมาจารย์ของคุณ' ได้แยกจากกัน # และมีการกระทำที่แตกต่างกัน 1 และ 1 อันตามลำดับ"
แฟรงค์

ฉันได้อัปเดตคำตอบของฉันเพื่อสะท้อนว่าข้อความเตือน
VonC

คำตอบที่ได้รับการยอมรับสำหรับคำถามอื่นอาจมีประโยชน์ในการแก้ไขบางกรณีที่อาจมีการเล่น (เช่นคุณกำลังพยายามย้ายนายไปรอบ ๆ แต่มันถูกผลักไปแล้ว): stackoverflow.com/questions/2862590/ ......
lindes

8
คำอธิบายที่บล็อกนี้ช่วยฉันได้มากกว่าคำตอบด้านล่างนี้: sebgoo.blogspot.com/2012/02/…

คำตอบ:


1014

คุณสามารถตรวจสอบความแตกต่างด้วย:

git log HEAD..origin/master

ก่อนที่จะดึงมัน (ดึงข้อมูล + ผสาน) (ดูเพิ่มเติมที่"คุณจะทำให้ git ดึงจากสาขาที่ต้องการได้อย่างไร" )


เมื่อคุณมีข้อความเช่น:

"สาขาและ 'ต้นกำเนิด / ปรมาจารย์ของคุณ' ถูกแยกแล้ว # และมีการกระทำที่แตกต่างกัน 1 และ 1 รายการตามลำดับ"

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

... o ---- o ---- A ---- B  origin/master (upstream work)
                   \
                    C  master (your work)

คุณใช้คอมมิชชัน C ในการส่งมอบ A เนื่องจากนั่นเป็นงานล่าสุดที่คุณดึงมาจากอัปสตรีมในเวลานั้น

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

จากนั้นคุณสามารถผสานหรือรีบูต ดูPro Git: Git Branching - การรีบูตสำหรับรายละเอียด

ผสาน

ใช้คำสั่ง git merge:

$ git merge origin/master

สิ่งนี้จะบอกให้ Git รวมการเปลี่ยนแปลงจากorigin/masterในงานของคุณและสร้างการผสาน
กราฟของประวัติศาสตร์ตอนนี้มีลักษณะดังนี้:

... o ---- o ---- A ---- B  origin/master (upstream work)
                   \      \
                    C ---- M  master (your work)

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

โปรดทราบว่าประวัติหลัง M อยู่ในขณะนี้ไม่ใช่เชิงเส้น

rebase

ใช้คำสั่ง git rebase:

$ git rebase origin/master

สิ่งนี้จะบอกให้ Git เล่นซ้ำกระทำ C (งานของคุณ) ราวกับว่าคุณอ้างอิงจากกระทำ B แทน A.
CVS และผู้ใช้ Subversion จะทำการ rebase การเปลี่ยนแปลงในเครื่องที่ด้านบนของงานอัปสตรีมเป็นประจำเมื่ออัปเดตก่อนส่งข้อมูล
Git เพิ่งเพิ่มการแยกที่ชัดเจนระหว่างขั้นตอนการส่งและส่งคืน

กราฟของประวัติศาสตร์ตอนนี้มีลักษณะดังนี้:

... o ---- o ---- A ---- B  origin/master (upstream work)
                          \
                           C'  master (your work)

Commit C 'เป็นคอมมิทใหม่ที่สร้างโดยคำสั่ง git rebase
มันแตกต่างจาก C ในสองวิธี:

  1. มันมีประวัติที่แตกต่าง: B แทน A
  2. เนื้อหาของบัญชีมีการเปลี่ยนแปลงทั้งใน B และ C มันเหมือนกับ M จากตัวอย่างที่ผสาน

โปรดทราบว่าประวัติเบื้องหลัง C 'ยังคงเป็นแบบเชิงเส้น
เราได้เลือก (ตอนนี้) cmake.org/cmake.gitเพื่อให้ประวัติศาสตร์เพียงเส้นตรง
วิธีนี้จะรักษาเวิร์กโฟลว์ที่ใช้ CVS ที่ใช้ก่อนหน้านี้และอาจช่วยให้เกิดการเปลี่ยนแปลงได้ง่ายขึ้น
ความพยายามที่จะผลักดัน C 'ลงในพื้นที่เก็บข้อมูลของเราจะใช้งานได้ (สมมติว่าคุณมีสิทธิ์และไม่มีใครผลักขณะที่คุณกำลังรีบูต)

คำสั่ง git pull จัดเตรียมวิธีชวเลขเพื่อดึงข้อมูลจากต้นทางและรีบูตงานโลคัลบน:

$ git pull --rebase

สิ่งนี้รวมการดึงข้อมูลและการทำซ้ำขั้นตอนเป็นคำสั่งเดียว


5
ฉันพบสิ่งนี้ในขณะที่ค้นหาปัญหาเดียวกันคุณสามารถอธิบายได้ไหมว่าเหตุใด 'การรีเซ็ต git - ฮาร์ดหัว' จึงไม่สามารถแก้ปัญหาได้
Neth

12
@Neth: เพราะมันไม่ได้เกี่ยวกับการแก้ไขฉาก (เช่นการแก้ไขที่มีอยู่ในดัชนี แต่ยังไม่ได้ทำ) แต่เกี่ยวกับการกระทำในท้องถิ่น (ซึ่งแตกต่างจากการกระทำที่มีอยู่ในระยะไกล) git reset --hard HEADเท่านั้นที่จะลบการปรับเปลี่ยนใด ๆ ในท้องถิ่นจัดทำดัชนีที่ไม่ใช่ความมุ่งมั่นและจะไม่ทำอะไรที่จะกระทบความแตกต่างระหว่างท้องถิ่นและระยะไกลกระทำ เฉพาะการผสานหรือการรีบูตเท่านั้นที่จะนำการกระทำสองชุด (รายการในเครื่องและชุดรีโมต) เข้าด้วยกัน
VonC

4
ว้าวขอบคุณสำหรับการตอบกลับที่ยอดเยี่ยมนี้ เราบังเอิญทำ "git pull" โดยไม่มี "--rebase" และ "git rebase origin / master" เป็นเพียงการแก้ไข!
mrooney

3
แล้ว - ฉันแค่ต้องการเพิกเฉย / ทิ้งการเปลี่ยนแปลงในพื้นที่ของฉันและอยู่กับสาขาในพื้นที่ของฉันที่มีรีโมตอยู่? กล่าวอีกนัยหนึ่งฉันต้องการmasterชี้ไปBที่ตัวอย่างของคุณ
CygnusX1

23
@ CygnusX1 ที่จะgit reset --hard origin/masterเป็นดังกล่าวในคำตอบด้านล่าง: stackoverflow.com/a/8476004/6309
VonC

725

ฉันมีสิ่งนี้และฉันประหลาดใจเป็นสิ่งที่ทำให้มันแม้หลังจากอ่านคำตอบข้างต้น ทางออกของฉันคือการทำ

git reset --hard origin/master

จากนั้นเพียงแค่รีเซ็ตสำเนาต้นแบบ (ภายในเครื่อง) ของฉัน (ซึ่งฉันคิดว่าถูกทำให้แน่น) เป็นจุดที่ถูกต้องซึ่งแสดงโดยจุดกำเนิด / ต้นแบบ (ระยะไกล)

คำเตือน : origin/masterคุณจะสูญเสียการเปลี่ยนแปลงทั้งหมดยังไม่ได้ผลักดันให้


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

7
สิ่งนี้จะต้องอยู่ในสาขาหลักก่อน ("git checkout master")
blueyed

สิ่งนี้เกิดขึ้นกับฉันเพียงครั้งเดียวเมื่อฉันได้รับแหล่งกำเนิดล่าสุดจากนั้นมีคนอื่นกำลังผลักดันไปยังแหล่งกำเนิดซึ่งทำให้ความมุ่งมั่นเดิมในแหล่งกำเนิดได้รับการคืนค่า ดังนั้นสาขาในพื้นที่ของฉันจึงมีการคืนสิทธิ์และเมื่อฉันพยายามดึงข้อมูลล่าสุดจากแหล่งกำเนิดมันก็บอกว่าฉันต้องรวม ในกรณีนี้มันเป็นเพียงความรู้สึกที่จะรีเซ็ต - ฮาร์ดแหล่งที่มา / (สาขา) เพราะปัญหาได้รับการแก้ไขแล้วในแหล่งกำเนิด
Landon Poch

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

6
@PedroLoureiro คอมมิชชันนั้นหายตัวไปจริงๆคุณยังสามารถค้นหาคอมมิทด้วยgit reflogหรือดูพวกมันgitk --allได้ แต่แน่นอนว่าการรีเซ็ตฮาร์ดเป็นอีกสิ่งหนึ่งที่มากกว่าการรีบูต
sebkraemer

52
git pull --rebase origin/master 

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

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


89
โปรดพูดถึงสิ่งที่คำสั่งทำคนอื่นอาจเรียกใช้มันและจบลงด้วยการ
เมา

1
หากไม่มีปัญหาคุณควรลงเอยกับนายของคุณที่มีต้นกำเนิด / การเปลี่ยนแปลงทั้งหมดพร้อมทั้งคำมั่นสัญญาในท้องถิ่นของคุณทั้งหมดจะถูกเล่นซ้ำ ดูดีสำหรับฉัน
Philipp Claßen

7
ยกเว้นเมื่อมีความแตกต่างที่แท้จริงและจะทำให้คุณอยู่ในการปฏิเสธการยกเลิก
ffledgling

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

32

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

สมมติว่าคุณอยู่ในสาขา my_remote_tracking_branch ซึ่งแยกจากต้นแบบ

$ git status

# ในสาขา my_remote_tracking_branch

ไม่มีอะไรที่จะกระทำ (ทำความสะอาดไดเรกทอรีทำงาน)

และตอนนี้คุณกำลังพยายามลดระดับจากต้นแบบเป็น:

git rebase master

หยุดทันทีและช่วยตัวเองให้เดือดร้อน! ให้ใช้การผสานเป็น:

git merge master

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

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

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

รีเซ็ต git - ต้นกำเนิด / my_remote_tracking_branch


5
กฎง่ายๆคือrebaseถ้าสาขาที่คุณกำลัง rebasing ยังไม่ได้เผยแพร่ (และคนอื่นใช้) mergeมิฉะนั้นการใช้งาน หากคุณรีบูทสาขา (และใช้แล้ว) ที่เผยแพร่แล้วคุณต้องประสานงานสมรู้ร่วมคิดเพื่อเขียนประวัติของนักพัฒนาทุกคนที่ใช้สาขาของคุณ
Mikko Rantalainen

1
แต่น่าเสียดายที่ฉันไม่ได้อ่านข้อความนี้ก่อนที่จะทำgit rebase master...
Vitaly Isaev

ถ้าฉันทำ git rebase master ขณะอยู่ที่ 'foobar' ในทางเทคนิคแล้ว foobar ทางเทคนิคจะถูกแยกจากแหล่งกำเนิด / foobar จนกระทั่งฉันทำ git push -f ใช่ไหม?
relipse


1
git reset --hard origin/my_remote_tracking_branchทำงานอะไรจริง ๆ
roothahn

24

ในกรณีของฉันนี่คือสิ่งที่ฉันทำเพื่อทำให้ข้อความที่แยกออก : ฉันทำgit pushแต่แล้วก็git commit --amendเพิ่มบางสิ่งบางอย่างในข้อความยืนยัน จากนั้นฉันก็ทำอีกอย่างหนึ่ง

ดังนั้นในกรณีของฉันที่หมายถึงต้นกำเนิด / หลักล้าสมัย เพราะฉันรู้ว่าไม่มีใครได้สัมผัสต้นกำเนิด / ต้นแบบการแก้ไขจึงเป็นเรื่องเล็กน้อย: git push -f (ซึ่ง-fหมายถึงแรง)


8
+1 สำหรับgit push -fเพื่อเขียนทับการเปลี่ยนแปลงที่ทำไว้ก่อนหน้านี้และผลักไปที่จุดเริ่มต้น ฉันยังมั่นใจว่าไม่มีใครแตะต้องที่เก็บ
zacharydl

4
คำสั่งที่มีความเสี่ยงมาก กรุณาเขียนข้อมูลสั้น ๆ เกี่ยวกับปัจจัยเสี่ยงของคำสั่ง
J4cK

1
@ เคล็ดลับ: ฉันได้อธิบายถึงความเสี่ยงแล้ว: "เพราะฉันรู้ว่าไม่มีใครได้สัมผัสต้นกำเนิด / มาสเตอร์" ฉันเชื่อว่าในกรณีนี้มันไม่ได้เป็นคำสั่งที่มีความเสี่ยง
Darren Cook

1
หากมีคนทำคอมมิชชันมาสเตอร์แล้วคนหนึ่งรันคำสั่ง git push -f มันก็เป็นคำสั่งที่มีความเสี่ยงสูง
J4cK

11

ในกรณีของฉันฉันได้ผลักดันการเปลี่ยนแปลงไปorigin/masterแล้วก็รู้ว่าฉันไม่ควรทำเช่นนั้น :-( นี่ซับซ้อนเนื่องจากข้อเท็จจริงที่ว่าการเปลี่ยนแปลงในท้องถิ่นอยู่ในทรีย่อยดังนั้นฉันจึงกลับไปที่การกระทำสุดท้ายที่ดีก่อนท้องถิ่น "เลว" การเปลี่ยนแปลง (โดยใช้ SourceTree) จากนั้นฉันได้รับข้อความ "divergence"

หลังจากแก้ไขระเบียบภายในของฉัน (รายละเอียดไม่สำคัญที่นี่) ฉันต้องการ "ย้อนเวลากลับไป" origin/masterสาขาระยะไกลเพื่อที่จะซิงค์กับท้องถิ่นmasterอีกครั้ง ทางออกในกรณีของฉันคือ:

git push origin master -f

สังเกต-fสวิตช์ (บังคับ) สิ่งนี้ลบ "การเปลี่ยนแปลงที่ไม่ดี" ที่ถูกผลักไปorigin/masterโดยไม่ได้ตั้งใจและขณะนี้สาขาในพื้นที่และระยะไกลกำลังซิงค์กัน

โปรดทราบว่านี่เป็นการดำเนินการทำลายล้างที่อาจเกิดขึ้นดังนั้นให้ดำเนินการเฉพาะในกรณีที่คุณแน่ใจ 100% ว่า "การย้อนกลับ" ต้นแบบระยะไกลในเวลานั้นตกลง


มีประโยชน์เสมอ แต่ก็ไม่ตอบคำถาม
Thibault D.

1
@ThibaultD แม้ว่ามันจะไม่เป็นเช่นนั้นนี่คือสิ่งที่ฉันกำลังมองหา
Neil Chowdhury

You are not allowed to force push code to a protected branch on this project.ฉันได้รับ ฉันพยายามที่จะผลักดันให้ส้อมของฉัน
BanAnanas

ฉันต้องลบการป้องกันใน gitlab repo stackoverflow.com/questions/32246503/…
BanAnanas

5

ฉันรู้ว่ามีคำตอบมากมายที่นี่ แต่ฉันคิดว่าgit reset --soft HEAD~1สมควรได้รับความสนใจเพราะช่วยให้คุณสามารถเปลี่ยนแปลงในท้องถิ่นล่าสุด(ไม่ผลัก) กระทำในขณะที่แก้ปัญหารัฐที่แตกต่าง ฉันคิดว่านี่เป็นวิธีแก้ปัญหาที่หลากหลายมากกว่าการดึงrebaseเพราะการมอบหมายในท้องถิ่นสามารถตรวจสอบได้และย้ายไปยังสาขาอื่น

ที่สำคัญคือการใช้แทนการที่รุนแรง--soft --hardหากมีมากกว่า 1 การกระทำรูปแบบของHEAD~xควรจะทำงาน ดังนั้นนี่คือขั้นตอนทั้งหมดที่แก้ไขสถานการณ์ของฉัน (ฉันมี 1 การกระทำในท้องถิ่นและ 8 การกระทำในระยะไกล):

1) git reset --soft HEAD~1เพื่อยกเลิกการกระทำในท้องถิ่น สำหรับขั้นตอนต่อไปฉันใช้อินเทอร์เฟซใน SourceTree แต่ฉันคิดว่าคำสั่งต่อไปนี้ควรใช้งานได้:

2) git stashเพื่อซ่อนการเปลี่ยนแปลงจาก 1) ตอนนี้การเปลี่ยนแปลงทั้งหมดมีความปลอดภัยและไม่มีความแตกต่างอีกต่อไป

3) git pullเพื่อรับการเปลี่ยนแปลงจากระยะไกล

4) git stash popหรือgit stash applyใช้การเปลี่ยนแปลงที่ถูกเก็บครั้งล่าสุดตามด้วยคอมมิชชันใหม่หากต้องการ ขั้นตอนนี้เป็นทางเลือกพร้อมกับ2)เมื่อต้องการลบทิ้งการเปลี่ยนแปลงในคอมมิทท้องถิ่น นอกจากนี้เมื่อต้องการกระทำการกับสาขาอื่นขั้นตอนนี้ควรทำหลังจากเปลี่ยนเป็นสาขาที่ต้องการ


ที่จริงแล้วทุกวันนี้สิ่งเหล่านี้pull --rebaseจะซ่อนตัวโดยอัตโนมัติอยู่ดี stackoverflow.com/a/30209750/6309
VonC

4

วิธีดูความแตกต่าง:

git difftool --dir-diff master origin/master

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


1
การใช้ git-dir ที่น่าสนใจ: +1
VonC

3

ในกรณีของฉันนี้เกิดจากการไม่ยอมรับการแก้ไขข้อขัดแย้งของฉัน

ปัญหาเกิดจากการรันgit pullคำสั่ง การเปลี่ยนแปลงในที่มานำไปสู่ความขัดแย้งกับ repo ท้องถิ่นของฉันซึ่งฉันแก้ไข อย่างไรก็ตามฉันไม่ได้กระทำ วิธีแก้ปัญหา ณ จุดนี้คือการคอมมิตการเปลี่ยนแปลง ( git commitไฟล์ที่แก้ไขแล้ว)

หากคุณได้แก้ไขไฟล์บางไฟล์ตั้งแต่การแก้ไขข้อขัดแย้งgit statusคำสั่งจะแสดงการปรับเปลี่ยนในท้องถิ่นเป็นการแก้ไขแบบโลคัลและการรวมการแก้ไขเป็นการแก้ไขแบบโลคัลแบบฉาก สิ่งนี้สามารถแก้ไขได้อย่างถูกต้องโดยยอมรับการเปลี่ยนแปลงจากการผสานก่อนgit commitแล้วจึงเพิ่มและกระทำการเปลี่ยนแปลงที่ไม่ได้ทำตามปกติ (เช่นโดยgit commit -a)


0

ฉันมีข้อความเดียวกันเมื่อฉันพยายามที่จะแก้ไขข้อความยืนยันครั้งล่าสุดจากข้อความยืนยันแล้วโดยใช้: git commit --amend -m "New message" เมื่อฉันผลักการเปลี่ยนแปลงที่ใช้git push --force-with-lease repo_name branch_name ไม่มีปัญหา


0

พบปัญหานี้เมื่อฉันสร้างสาขาตามสาขา A โดย

git checkout -b a

แล้วฉันจะตั้งค่ากระแสของสาขา a ให้กำเนิดสาขา B โดย

git branch -u origin/B

จากนั้นฉันได้รับข้อความแสดงข้อผิดพลาดด้านบน

วิธีหนึ่งในการแก้ไขปัญหานี้สำหรับฉันคือ

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