Git pull ส่งผลให้ข้อความ“ Merge branch” ที่ไม่เกี่ยวข้องในบันทึกคอมมิต


110

ฉันกำลังทำงานร่วมกับนักพัฒนารายอื่นในโปรเจ็กต์และเรากำลังใช้ Github เป็น repo ระยะไกล ฉันใช้ Mac โดยใช้ git 1.7.7.3 เขาใช้ Windows โดยใช้ git 1.7.6

นี่คือสิ่งที่เกิดขึ้น

  1. พวกเราคนหนึ่ง (ขอเรียกเขาว่านักพัฒนา A แต่ไม่สำคัญว่าคนไหน) ผลักดันชุดการคอมมิตไปที่ GitHub
  2. อีกคนหนึ่ง (ผู้พัฒนา B) ทำการตกลงในพื้นที่
  3. B git pullไม่ได้
  4. B git pushไม่ได้
  5. เมื่อดูบันทึกประวัติการกระทำฉันเห็นMerge branch 'master' ของ github.com:foo/bar

บันทึกการคอมมิตจะเกลื่อนไปด้วยข้อความ "Merge branch" เมื่อเวลาผ่านไปและยังแสดงให้นักพัฒนา B ยอมรับการเปลี่ยนแปลงที่นักพัฒนา A ทำ วิธีเดียวที่เราพบเพื่อป้องกันปัญหานี้คือทำgit pull --rebaseในขั้นตอนที่ 3 แต่ฉันไม่รู้ว่าจะมีผลข้างเคียงอะไรบ้าง นี่เป็นครั้งแรกของฉันที่ทำงานกับ repo git สำหรับนักพัฒนาหลายคนนี่เป็นเพียงพฤติกรรมปกติหรือไม่ มีความคิดเกี่ยวกับวิธีแก้ปัญหานี้หรือไม่?


2
คุณสามารถดูบันทึกโดยไม่รวมกับgit log --no-merges
wjandrea

คำตอบ:


88

การกระทำที่คุณเห็นนั้นดีมาก pullได้อย่างมีประสิทธิภาพทำงานgit fetchแล้วดังนั้นการผสานมักจะเกิดขึ้นเมื่อคุณเรียกใช้git mergegit pull

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

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

เรื่องสั้นสั้น ๆ : ใช่การผสานคอมมิชทำได้ดีมากและคุณไม่ควรกังวลกับพวกเขา


2
ตอบได้ดีมาก. ฉันเองลองใช้สไตล์ rebase เนื่องจากมีการแนะนำในแนวทางการสนับสนุนโครงการโอเพนซอร์สและทำให้ฉันมีปัญหา สมาชิกใหม่ในทีมก็เหมือนกัน ฉันคิดว่าตัวเลือก rebase ไม่ได้มีไว้สำหรับทีมที่ทำงานร่วมกันทั้งวัน แต่ถูกต้องสำหรับโครงการที่มีผู้สนับสนุนหลักและผู้มีส่วนร่วมอื่น ๆ ที่เพิ่งส่งแพตช์ สิ่งเหล่านี้ควรจะดึง repo หลักได้ดีและปรับเปลี่ยนการเปลี่ยนแปลงก่อนที่จะส่งคำขอดึงออก
Meligy

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

28
คำตอบนี้ทำให้ดูเหมือนว่าการใช้ rebase ตามที่ OP อธิบายไว้นั้นอันตราย แต่ไม่ใช่ การทำซ้ำในขั้นตอนที่ 3 ไม่ได้เป็นการเขียนประวัติซ้ำทั้งหมด เฉพาะคอมมิตในเครื่องที่ยังไม่ถูกพุชเท่านั้นที่จะถูกเขียนใหม่โดยนำไปใช้ใหม่ที่ด้านบนของ HEAD ใหม่ (คอมมิตล่าสุดที่พุชไปยังสาขานั้น) สิ่งนี้จะป้องกันไม่ให้เกิดการผสานที่ไม่เกี่ยวข้องและไม่มีผลข้างเคียงอื่น ๆ
bob esponja

1
@bobesponja คอมมิตทั้งหมดที่ไม่ได้อยู่บนรีโมตแบรนช์ที่ดึงมาจะถูกเขียนใหม่ ซึ่งอาจรวมถึงคอมมิตที่เผยแพร่จากสาขาอื่น ๆ เช่นสาขาฟีเจอร์ซึ่งผู้อื่นอาจเคยเข้าถึงมาก่อน ด้วยเหตุนี้ใช่แล้วการทำซ้ำโดยไม่คิดว่าฐานข้อมูลของคุณจะค่อนข้างอันตราย
โผล่

1
@bobesponja ใช่หากคุณเผยแพร่สาขาฟีเจอร์ของคุณก่อนเวลา (เนื่องจากคนอื่นทำงานกับมันหรือเป็นเพียงการสำรองข้อมูล) คุณไม่ควรตั้งฐานใหม่เพราะคนอื่นสามารถดึงข้อมูลได้แล้ว จากนั้นการรีเบตตามที่คุณพูดกับตัวเองขัดต่อแนวทางการลดราคาที่ฉันระบุไว้ในคำตอบของฉัน อย่างไรก็ตามหากคุณไม่เผยแพร่คำมั่นสัญญาของคุณการทำซ้ำก็ใช้ได้หากคุณต้องการและไม่ต้องสนใจประวัติเชิงเส้น แต่ขึ้นอยู่กับวิธีการทำงานของคุณดังนั้นคำตอบทั่วไปคือหลีกเลี่ยงเว้นแต่จะปลอดภัยจริงๆ Btw. ฉันแก้ไขคำตอบของฉันแล้วดังนั้นหากปัญหาได้รับการแก้ไขฉันจะยินดีมากหากคุณลบการลงคะแนนของคุณออก
โผล่

48

คำตอบนี้ได้รับการแก้ไขเนื่องจากความเข้าใจแผนภาพและข้อสรุปของฉันไม่ถูกต้อง


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

ตัวอย่างเช่นคนสองคนทำงานในสาขาเดียวกัน สาขาเริ่มต้นด้วย:

...->C1

คนแรกทำงานเสร็จและผลักดันไปที่สาขา:

...->C1->C2

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

...->C1->C3

หากการดึงถูกตั้งค่าให้ผสานที่เก็บบุคคลที่สองจะมีลักษณะดังนี้

...->C1->C3->M1
      \      /
       ->C2->

โดยที่ M1 คือการรวมคอมมิต ประวัติสาขาใหม่นี้จะถูกผลักไปที่ repo ในกรณีนี้การดึงถูกตั้งค่าเป็นฐานใหม่ repo ในเครื่องจะมีลักษณะดังนี้:

...->C1->C2->C3

ไม่มีการรวมคอมมิต ประวัติศาสตร์ถูกทำให้เป็นเส้นตรงมากขึ้น

ทั้งสองทางเลือกสะท้อนถึงประวัติศาสตร์ของสาขา git ช่วยให้คุณสามารถเลือกประวัติที่คุณต้องการได้

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

คุณสามารถตั้งค่า branch.autosetuprebase = always เพื่อให้ git สร้าง remote branch ของคุณโดยอัตโนมัติเป็น rebase แทน master

git config --global branch.autosetuprebase always

การตั้งค่านี้ทำให้ git สร้างการตั้งค่าคอนฟิกสำหรับแต่ละสาขาระยะไกลโดยอัตโนมัติ:

branch.<branchname>.rebase=true

คุณสามารถตั้งค่านี้ด้วยตนเองสำหรับสาขาระยะไกลที่ตั้งค่าไว้แล้ว

git config branch.<branchname>.rebase true

ฉันขอขอบคุณ @LaurensHolst สำหรับการซักถามและติดตามคำชี้แจงก่อนหน้านี้ของฉัน ฉันได้เรียนรู้เพิ่มเติมอย่างแน่นอนเกี่ยวกับวิธีการทำงานของคอมไพล์กับการดึงและผสานคอมมิต

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการกระทำผสานคุณสามารถอ่านที่เอื้อต่อการโครงการในProGit-Book ส่วนPrivate Small Teamแสดงการรวมคอมมิต


7
“ การใช้ rebase แทนการผสานในการดึงจะให้ประวัติที่ถูกต้องไปยังที่เก็บที่แบ่งใช้ การใช้การผสานจะให้ประวัติที่ผิดพลาด” - อะไรคือเหตุผลที่สำรองข้อความที่ค่อนข้างหนานี้? ไม่มีทางที่ประวัติศาสตร์ที่มีการผสานเป็น 'ประวัติเท็จ' เป็นการพรรณนาที่ถูกต้องของลำดับเหตุการณ์ที่เกิดขึ้น สิ่งที่คุณทำโดยการรีเบตเป็นการแก้ไขประวัติเพื่อสร้างเวอร์ชันเชิงเส้นมากขึ้นเล็กน้อย คุณยอมสละความถูกต้องเพื่อความสวยงาม อาจเป็นสิ่งที่คุณชอบทำ แต่ไม่มีทางเป็นจริงมากกว่า
Laurens Holst

2
การใช้ rebase แทนการผสานไม่ได้ลดทอนความถูกต้องเพื่อความสวยงาม เราใช้ --no-ff สำหรับการผสานดังนั้นสุนทรียศาสตร์จึงไม่ใช่ข้อกำหนด ความถูกต้องคือความปรารถนา Rebase ให้ความแม่นยำนั้น
Bill Door

2
วิธีคือประวัติศาสตร์ปรับฐานที่ถูกต้องมากขึ้น? คุณไม่ชี้แจงเรื่องนี้และฉันไม่เห็นว่ามันจะเป็นอย่างไร
Laurens Holst

1
ประวัติคือภาพสะท้อนของเวลาที่เกิดการกระทำในrepo ที่แชร์ วันหนึ่งที่ 1 repo ที่แชร์พบว่ามีการกระทำ C2 ในวันที่ 2 repo ที่แชร์เห็นคอมมิต C3 ถ้า C3 มาก่อน C2 การสะท้อนของเวลาจะไม่ถูกต้อง C3 ไม่มาก่อน C2 rebase ทั้งหมดนั้นจัดระเบียบคอมมิตบนที่เก็บโลคัลอีกครั้งเพื่อแสดงประวัติที่แสดงโดยที่เก็บแบบแบ่งใช้อย่างเหมาะสม
Bill Door

6
คำถามของคุณทำให้ฉันต้องทบทวนความเข้าใจเกี่ยวกับการรวมคอมมิต แผนภาพของฉันไม่ถูกต้อง ฉันกำลังแก้ไขการสนทนา ข้อสรุปของฉันก็ไม่ถูกต้องเช่นกัน ประวัติสำหรับ rebase และ merge นั้นถูกต้องเท่าเทียมกัน คุณสามารถเลือกได้เอง
Bill Door

11

คุณทำได้:

git pull --rebase

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


9

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

git stash
git pull
git stash pop

จากนั้นคุณสามารถแก้ไขข้อขัดแย้งในการผสานหากมี


ที่น่ารำคาญและกังวลที่สุดคือการผสานความขัดแย้ง ฉันค่อนข้างหลีกเลี่ยง
กรี

1
@Green หากคุณกังวลเกี่ยวกับการรวมความขัดแย้งแม้แต่ git pull ก็ไม่ต่างกัน
Zoso

ยกเว้นว่าครั้งหนึ่งเมื่อคุณลืมไปก่อนที่คุณจะstash pullUgh git ต้องการให้ฉันอยู่ในจุดสูงสุดของเกมตลอดเวลา
linuxNoob

จำเป็นต้องgit pull --rebaseรวมการเปลี่ยนแปลงระยะไกลก่อนการเปลี่ยนแปลงภายในเครื่องโดยไม่คำนึงถึง
vonbrand

7

การทำ git pull จะแทรกข้อความ "Merge branch" นั่นคือสิ่งที่ทำ ด้วยการดึงคอมไพล์คุณได้รวมสาขาระยะไกลเข้ากับสาขาในพื้นที่ของคุณ

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

เท่าที่ฉันรู้นั่นเป็นเพียงวิธีการทำงานของคอมไพล์และไม่มีทางหลีกเลี่ยง

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

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