คุณใช้ Git rebase แทน Git merge เมื่อใด


1548

เมื่อใดจึงแนะนำให้ใช้ Git rebase vs. Git merge?

ฉันยังต้องรวมหลังจากการรีบูตที่ประสบความสำเร็จหรือไม่?



16
นี้เป็นสิ่งที่ดี: atlassian.com/git/tutorials/merging-vs-rebasing
stackexchanger

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

9
@static_rtti: นั่นไม่ใช่ความจริง คุณกำลังใช้โฟลว์รีบาวเดอร์ที่ผิดหากมันขัดขวางคุณจากการผลักดันการเปลี่ยนแปลงเป็นประจำ
juzzlin

5
เป็นเรื่องน่าอายจริง ๆ ที่คำตอบของ Andrew ArnottและคำตอบของPaceไม่ได้ถูกโพสต์ไว้ก่อนหน้านี้เนื่องจากพวกเขาตอบคำถามนี้อย่างละเอียดมากกว่าคำตอบก่อนหน้าซึ่งมีการลงคะแนนจำนวนมากแล้ว
Mark Booth

คำตอบ:


1136

เวอร์ชั่นสั้น

  • ผสานนำการเปลี่ยนแปลงทั้งหมดในสาขาเดียวมารวมเข้าด้วยกันในสาขาอื่นในสาขาเดียว
  • Rebase กล่าวว่าฉันต้องการจุดที่ฉันแยกเพื่อย้ายไปยังจุดเริ่มต้นใหม่

ดังนั้นเมื่อไหร่ที่คุณจะใช้อันใดอันหนึ่ง?

ผสาน

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

rebase

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

105
@Rob กล่าวถึงการรักษาความมุ่งมั่นระหว่างกาลเมื่อรวม ฉันเชื่อว่าโดยค่าเริ่มต้นการรวมสาขา B (สาขาฟีเจอร์ที่คุณทำงานอยู่) ลงในสาขา M (สาขาหลัก) จะสร้างการส่งมอบหนึ่งรายการใน M สำหรับการส่งแต่ละครั้งที่ทำใน B นับตั้งแต่ที่แยกกันแล้ว แต่ถ้าคุณรวมโดยใช้ตัวเลือก --squash ความมุ่งมั่นทั้งหมดที่ทำในสาขา B จะถูก "รวมเข้าด้วยกัน" และรวมกันเป็นคอมมิชชันเดียวในสาขา M ทำให้การบันทึกในสาขาหลักของคุณดีและสะอาด การสควอชอาจเป็นสิ่งที่คุณต้องการหากคุณมีนักพัฒนาจำนวนมากที่ทำงานอย่างอิสระและผสานกลับคืนเป็นหลัก
spaaarky21

19
ฉันเชื่อว่าข้อสันนิษฐานของ @ spaaarky21 เกี่ยวกับการรวมกันไม่ถูกต้อง หากคุณรวมสาขา B เข้ากับ M หลักจะมีการคอมมิตเพียงครั้งเดียวใน M (แม้ว่า B มีหลายคอมมิท) โดยไม่คำนึงว่าคุณใช้คอมไพล์ธรรมดาหรือ - สควอชผสาน อะไร - สควอชจะทำคือกำจัดการอ้างอิงถึง B เป็นผู้ปกครอง การสร้างภาพที่ดีอยู่ที่นี่: syntevo.com/smartgithg/howtos.html?page=workflows.merge
jpeskin

14
@jpeskin นั่นไม่ใช่สิ่งที่ฉันเห็น ฉันเพิ่งทำแบบทดสอบเพื่อตรวจสอบ สร้างไดเรกทอรีที่มีแฟ้มข้อความinitrepo ใหม่ไฟล์และadd commitชำระเงินสาขาคุณลักษณะใหม่ ( checkout -b feature.) เปลี่ยนไฟล์ข้อความกระทำและทำซ้ำเพื่อให้มีสองกระทำใหม่ในสาขาคุณสมบัติ แล้วและcheckout master merge featureในlogฉันเห็นความมุ่งมั่นเริ่มต้นของฉันตามหลักแล้วตามด้วยสองสิ่งที่รวมเข้ากับคุณลักษณะ หากคุณmerge --squash featureมีการรวมคุณสมบัติเข้ากับมาสเตอร์ แต่ไม่ได้ทำดังนั้นการมอบหมายใหม่บนมาสเตอร์จะเป็นสิ่งที่คุณทำเอง
spaaarky21

21
@ spaaarky21 ดูเหมือนว่าพวกเราทั้งคู่ถูกต้องแล้ว เมื่อเป็นไปได้อย่างรวดเร็วผสาน (เป็นตัวอย่างของคุณ), git จะเริ่มต้นรวมถึงการกระทำทั้งหมดในสาขาฟีเจอร์ข (หรือตามที่คุณแนะนำคุณสามารถใช้ - สควอชเพื่อรวมกันเป็นคอมมิชชันเดียว) แต่ในกรณีที่มีสาขาที่แตกต่างกันสองสาขาคือ M และ B คุณจะรวมกันคอมไพล์จะไม่รวมการกระทำทั้งหมดจากสาขา B ถ้ารวมเข้ากับ M (ไม่ว่าคุณจะใช้ --squash หรือไม่ก็ตาม)
jpeskin

6
เหตุใดจึงเป็น "(คุณไม่สนใจเกี่ยวกับการรักษาความมุ่งมั่นระหว่างกาลทั้งหมด)" ไว้ในคำตอบนี้ มันไม่สมเหตุสมผลใน '09 และตอนนี้ก็ไม่สมเหตุสมผล นอกจากนี้แน่นอนว่าคุณต้องการที่จะลดราคาหากนักพัฒนารายอื่นทำการเปลี่ยนแปลงที่เกี่ยวข้องที่คุณต้องการ - หากพวกเขาทำการเปลี่ยนแปลงที่ไม่เกี่ยวข้องสาขาฟีเจอร์ของคุณควรผสานได้อย่างง่ายดายโดยไม่มีข้อขัดแย้งอยู่แล้วและประวัติของคุณจะได้รับการดูแล
Mark Booth

372

มันง่ายมาก ด้วย rebase คุณบอกว่าจะใช้สาขาอื่นเป็นฐานใหม่สำหรับการทำงานของคุณ

ตัวอย่างเช่นถ้าคุณมีสาขาmasterคุณจะสร้างสาขาเพื่อนำคุณสมบัติใหม่มาใช้และบอกว่าคุณตั้งชื่อcool-featureสาขานั้นแน่นอนว่าสาขาหลักนั้นเป็นฐานสำหรับคุณลักษณะใหม่ของคุณ

ในตอนนี้คุณต้องการเพิ่มฟีเจอร์ใหม่ที่คุณนำไปใช้ในmasterสาขา คุณสามารถเปลี่ยนเป็นmasterและผสานcool-featureสาขา:

$ git checkout master
$ git merge cool-feature

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

$ git checkout cool-feature
$ git rebase master

แล้วรวมมันเข้า master :

$ git checkout master
$ git merge cool-feature

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


31
but this way a new dummy commit is added, if you want to avoid spaghetti-history- มันแย่ขนาดไหน?
アレックス

6
นอกจากนี้แฟล็ก --no-ff ของการผสานยังมีประโยชน์มาก
Aldo 'xoen' Giambelluca

3
@ アレックスในฐานะผู้ใช้Sean Schofieldใส่ไว้ในความคิดเห็น: "Rebase ก็ดีเพราะเมื่อคุณรวมสิ่งต่างๆเข้าด้วยกันในที่สุด (ซึ่งเป็นเรื่องเล็กน้อยตามที่อธิบายไว้แล้ว) คุณได้นั่งอยู่ที่" บนสุด "ของประวัติศาสตร์ของคุณ โครงการที่อาจมีการเขียนคุณสมบัติ แต่รวมหลายสัปดาห์ต่อมาคุณไม่ต้องการรวมพวกมันเข้ากับนายเพราะพวกเขาได้ "ยัด" เข้าไปในทางกลับในประวัติศาสตร์โดยส่วนตัวแล้วฉันชอบที่จะทำบันทึกคอมไพล์และดู ฟีเจอร์ล่าสุดที่อยู่ด้านบน "ด้านบน" โปรดทราบว่าวันที่ส่งมอบจะถูกเก็บไว้ - การรีบูตจะไม่เปลี่ยนข้อมูลนั้น "
Adrien Be

4
ฉันคิดว่ามันหมีซ้ำนี่ - จำไว้ว่าคำเหล่านี้ทั้งหมด ( merge, rebase, fast-forwardฯลฯ ) จะหมายถึงกิจวัตรที่เฉพาะเจาะจงของชี้นำวัฏจักรกราฟ พวกเขากลายเป็นเรื่องง่ายที่จะให้เหตุผลเกี่ยวกับแบบจำลองทางจิตในใจ
Roy Tinker

10
@Aldo ไม่มีอะไรที่ "สะอาด" หรือ "เป็นระเบียบ" เกี่ยวกับประวัติที่ถูกปฏิเสธ โดยทั่วไปแล้วมันสกปรกและ IMHO น่ากลัวเพราะคุณไม่รู้ว่าเกิดอะไรขึ้น ประวัติ Git "cleanest" เป็นสิ่งที่เกิดขึ้นจริง :)
Marnen Laibow-Koser

269

เพื่อเติมเต็มคำตอบของตัวเองที่กล่าวถึงโดย TSamper ,

  • การ rebase นั้นมักจะเป็นความคิดที่ดีที่จะทำก่อนที่จะทำการผสานเพราะความคิดคือการที่คุณผสานYการทำงานของสาขาBที่คุณจะรวมเข้าด้วยกันในสาขาของคุณ
    แต่อีกครั้งก่อนที่จะรวมคุณแก้ไขข้อขัดแย้งใด ๆ ในสาขาของคุณ (เช่น: "rebase" เช่นเดียวกับใน "เล่นซ้ำงานของฉันในสาขาของฉันเริ่มต้นจากจุดล่าสุดจากสาขาB)
    หากทำอย่างถูกต้องผสานที่สาขาจาก สาขาBสามารถกรอไปข้างหน้า

  • การรวมกันจะส่งผลกระทบโดยตรงต่อสาขาปลายทางBซึ่งหมายถึงการรวมที่ดีกว่านั้นไม่สำคัญมิฉะนั้นสาขาBอาจจะต้องกลับไปสู่สถานะที่มั่นคง (เวลาที่คุณแก้ไขข้อขัดแย้งทั้งหมด)


เป็นจุดรวมของการรีบูตหรือไม่

ในกรณีที่ฉันอธิบายฉัน rebase Bบนสาขาของฉันเพียงเพื่อมีโอกาส replay งานของฉันจากจุดล่าสุดจากBแต่ในขณะที่อยู่ในสาขาของฉัน
ในกรณีนี้จำเป็นต้องมีการผสานเพื่อนำงาน "replayed" ของฉันไปBใช้

สถานการณ์อื่น ๆ (ซึ่งอธิบายไว้ใน Git Ready ) คือการนำงานของคุณโดยตรงBผ่านการรีบูต (ซึ่งเป็นการประหยัดค่าคอมมิชชันทั้งหมดของคุณหรือให้โอกาสในการสั่งซื้อใหม่ผ่านการรีบูตแบบโต้ตอบ)
ในกรณีนั้น (ที่คุณรีบูตในขณะที่อยู่ในสาขา B) คุณพูดถูก: ไม่จำเป็นต้องรวมอีกต่อไป:

ต้นไม้ Git เป็นค่าเริ่มต้นเมื่อเรายังไม่ได้รวมหรือไม่ได้รีบาวด์

rebase1

เราได้รับจากการรีบูต:

rebase3

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

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

new-featurenew-featuremasternew-feature สาขา).

ดังนั้น:

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

17
การรวมกันหลังจากการรีบูตเป็นไปข้างหน้าอย่างรวดเร็วโดยไม่ต้องแก้ไขข้อขัดแย้ง
obecalp

4
@obelcap: อันที่จริงนี่เป็นแนวคิด: คุณรับปัญหาความขัดแย้งทั้งหมดในสภาพแวดล้อมของคุณ (rebase master ภายในสาขาคุณลักษณะใหม่ของคุณ) จากนั้น co master, ผสานคุณสมบัติใหม่: 1 pico-second (เร็ว - ไปข้างหน้า) ถ้าอาจารย์ไม่มีการเปลี่ยนแปลง
VonC

27
การปฏิเสธก็ดีเช่นกันเพราะเมื่อคุณรวมสิ่งของของคุณกลับคืนสู่ต้นแบบแล้ว (ซึ่งเป็นเรื่องเล็กน้อยตามที่อธิบายไว้แล้ว) คุณจะต้องนั่งอยู่ที่ "สุดยอด" ของประวัติการกระทำของคุณ ในโครงการขนาดใหญ่ที่อาจมีการเขียนคุณสมบัติ แต่รวมหลายสัปดาห์ต่อมาคุณไม่ต้องการรวมมันเข้ากับนายเพราะพวกเขาได้ "ยัด" เข้าไปในทางกลับในประวัติศาสตร์ โดยส่วนตัวแล้วฉันชอบที่จะสามารถบันทึก git และดูคุณสมบัติล่าสุดที่ด้านบน "ด้านบน" โปรดทราบว่าวันที่ส่งมอบจะได้รับการเก็บรักษาไว้ - rebase จะไม่เปลี่ยนข้อมูล
Sean Schofield

3
@Joe: จิตใจคุณกำลังพูดว่า "เล่นซ้ำการเปลี่ยนแปลงใด ๆ ของฉัน (ทำในแยกในสาขาส่วนตัวของฉัน) ที่ด้านบนของสาขาอื่น ๆ แต่ปล่อยให้ฉันในสาขาเอกชนของฉันเมื่อรีบูตเสร็จแล้ว" นั่นเป็นโอกาสที่ดีในการทำความสะอาดประวัติศาสตร์ท้องถิ่นหลีกเลี่ยง "จุดตรวจกระทำ" หักออกเป็นสองเท่าและผลการตำหนิที่ไม่ถูกต้อง ดู "เวิร์กโฟลว์ Git": sandofsky.com/blog/git-workflow.html
VonC

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

229

TL; DR

หากคุณมีข้อสงสัยให้ใช้การผสาน

คำตอบสั้น ๆ

ข้อแตกต่างระหว่าง rebase และ merge คือ:

  • โครงสร้างต้นไม้ที่เกิดขึ้นของประวัติศาสตร์ (โดยทั่วไปจะเห็นได้ชัดเจนเมื่อดูกราฟการกระทำ) จะแตกต่างกัน (หนึ่งจะมีกิ่งไม้อื่น ๆ จะไม่)
  • โดยทั่วไปแล้วการผสานจะสร้างการกระทำพิเศษ (เช่นโหนดในต้นไม้)
  • การผสานและการรีบูตจะจัดการกับความขัดแย้งต่างกัน การปฏิเสธจะนำเสนอความขัดแย้งหนึ่งการกระทำในเวลาที่การผสานจะนำเสนอพวกเขาทั้งหมดในครั้งเดียว

ดังนั้นคำตอบสั้น ๆ คือเลือก rebase หรือผสานตามสิ่งที่คุณต้องการให้ประวัติของคุณเป็นเช่นนั้น

คำตอบยาว ๆ

มีปัจจัยบางประการที่คุณควรพิจารณาเมื่อเลือกการทำงานที่จะใช้

สาขาที่คุณได้รับการเปลี่ยนแปลงจากการแบ่งปันกับนักพัฒนาคนอื่น ๆ นอกทีมของคุณ (เช่นโอเพ่นซอร์สสาธารณะ)?

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

ทีมพัฒนาของคุณมีทักษะแค่ไหน?

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

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

สาขาเองแสดงข้อมูลที่เป็นประโยชน์หรือไม่

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

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

คุณต้องการยกเลิกการรวมด้วยเหตุผลใด ๆ หรือไม่

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

คุณทำงานเป็นทีมหรือไม่? ถ้าเป็นเช่นนั้นคุณยินดีที่จะใช้วิธีการทั้งหมดหรือไม่มีอะไรในสาขานี้?

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

ตำนานทั่วไป

ผสานทำลายประวัติ (สควอชคอมมิชชัน)

สมมติว่าคุณมีการผสานดังต่อไปนี้:

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

บางคนจะกล่าวว่าการผสาน "ทำลาย" ประวัติการกระทำเพราะถ้าคุณดูที่บันทึกของสาขาหลักเท่านั้น (A - D) คุณจะพลาดข้อความการกระทำที่สำคัญที่มีอยู่ใน B และ C

ถ้าเรื่องนี้เป็นความจริงที่เราจะได้มีคำถามเช่นนี้ โดยทั่วไปคุณจะเห็น B และ C เว้นแต่คุณจะขอให้ไม่เห็นพวกเขา (โดยใช้ --first-parent) มันง่ายมากที่จะลองด้วยตัวคุณเอง

Rebase ช่วยให้การรวมที่ปลอดภัย / ง่ายขึ้น

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

Rebase นั้นยอดเยี่ยมกว่า / เซ็กซี่กว่า / เป็นมืออาชีพมากกว่า

หากคุณต้องการนามแฝงrmถึงrm -rf"ประหยัดเวลา" บางทีการรีบูตอาจเหมาะสำหรับคุณ

สองเซ็นต์ของฉัน

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

ประวัติที่ยุ่งเหยิงไม่เคยเป็นปัญหาสำหรับฉันเลย ฉันไม่เคยอ่านประวัติการกระทำของฉันเหมือนนิยายที่น่าตื่นเต้น เวลาส่วนใหญ่ที่ฉันต้องการประวัติฉันจะใช้ตำหนิ Git หรือ Gis bisect ต่อไป ในกรณีดังกล่าวการมีการรวมการกระทำนั้นมีประโยชน์กับฉันจริง ๆ เพราะถ้าการรวมที่นำเสนอปัญหานั่นเป็นข้อมูลที่มีความหมายสำหรับฉัน

อัปเดต (4/2017)

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


5
ควรเป็นคำตอบที่ผ่านการตรวจสอบ
Mik378

นี่เป็นคำตอบที่ดีที่สุดอย่างแน่นอน โดยเฉพาะอย่างยิ่งกับคำชี้แจงที่ชัดเจนในการปรับปรุงล่าสุด ช่วยให้ประวัติคอมไพล์สะอาดและชัดเจน แต่ใช้อย่างปลอดภัย
zquintana

5
ฉันรักคำตอบนี้เป็นส่วนใหญ่ แต่การ Rebase ไม่ได้สร้างประวัติศาสตร์ที่ "สะอาด" มันสร้างประวัติศาสตร์เชิงเส้นมากขึ้น แต่นั่นไม่ใช่สิ่งเดียวกันเลยเพราะใครจะรู้ว่า "ดิน" ในแต่ละครั้งที่มีการซ่อนตัวอยู่? ประวัติ Git ที่สะอาดและชัดเจนที่สุดคือประวัติของ Git
Marnen Laibow-Koser

3
"ตำนานทั่วไปคุณจะเห็นความมุ่งมั่นของ B และ C": ไม่จำเป็นต้อง !! คุณจะเห็นเฉพาะ B และ C หากการรวมนั้นเป็นการผสานการกรอไปข้างหน้าและเป็นไปได้ก็ต่อเมื่อไม่มีข้อขัดแย้ง หากมีข้อขัดแย้งคุณจะได้รับความมุ่งมั่น! อย่างไรก็ตาม: คุณสามารถรวมต้นแบบเข้ากับคุณลักษณะก่อนและแก้ไขข้อขัดแย้งที่นั่นและถ้าคุณรวมคุณสมบัติเข้ากับต้นแบบคุณจะได้รับ B และ C และคอมมิชชัน X จากการผสาน (แรก) จากต้นแบบเข้าสู่คุณลักษณะในประวัติของคุณ
Jeremy Benks

คำอธิบายที่ดีมาก! มันจะต้อง upvoted มากขึ้น!
dimmits

185

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

การผสานไม่ทำให้การกระทำของคุณหมดไป ผสานรักษาประวัติศาสตร์! (ดูที่ gitk) Rebase เขียนประวัติศาสตร์ใหม่ซึ่งเป็นสิ่งที่แย่หลังจากที่คุณผลักมัน

ใช้การผสาน - ไม่ใช่การรีบูตเมื่อใดก็ตามที่คุณผลักแล้ว

นี่คือ Linus '(ผู้แต่ง Git) รับหน้าที่ (ปัจจุบันโฮสต์ในบล็อกของฉันเองซึ่งกู้คืนโดย Wayback Machine ) มันเป็นการอ่านที่ดีจริงๆ

หรือคุณสามารถอ่านแนวคิดเดียวกันของฉันด้านล่าง

การสยบสาขาบนมาสเตอร์:

  • แสดงแนวคิดที่ไม่ถูกต้องเกี่ยวกับวิธีการสร้างการผูกพัน
  • ก่อให้เกิดมลภาวะระดับปริญญาโทด้วยการกระทำระดับกลางที่อาจไม่ผ่านการทดสอบอย่างดี
  • สามารถแนะนำตัวแบ่งการสร้างบนคอมมิชชันระดับกลางเหล่านี้เนื่องจากการเปลี่ยนแปลงที่เกิดขึ้นกับต้นแบบระหว่างเมื่อสร้างหัวข้อสาขาดั้งเดิมและเมื่อถูกรีบาวด์
  • ทำให้การค้นหาสถานที่ที่ดีในการชำระเงินเป็นเรื่องยาก
  • ทำให้การประทับเวลาเปิดใช้งานไม่สอดคล้องกับลำดับเหตุการณ์ในต้นไม้ ดังนั้นคุณจะเห็นว่าการกระทำ A นำหน้ากระทำการ B เป็นหลัก แต่การกระทำ B ถูกเขียนขึ้นก่อน (อะไร?!)
  • สร้างความขัดแย้งมากขึ้นเนื่องจากบุคคลที่กระทำในสาขาหัวข้อแต่ละคนสามารถเกี่ยวข้องกับการรวมความขัดแย้งซึ่งจะต้องแก้ไขเป็นรายบุคคล (โกหกเพิ่มเติมในประวัติศาสตร์เกี่ยวกับสิ่งที่เกิดขึ้นในแต่ละกระทำ)
  • เป็นการเขียนประวัติศาสตร์ ถ้าสาขาที่ถูกรีบูทถูกผลักไปทุกหนทุกแห่ง (แชร์กับคนอื่นที่ไม่ใช่ตัวคุณเอง) คุณจะทำให้คนอื่น ๆ ที่มีสาขานั้นโกรธตั้งแต่คุณเขียนประวัติศาสตร์ใหม่

ในทางตรงกันข้ามการรวมสาขาหัวข้อเป็นหลัก:

  • เก็บประวัติที่มีการสร้างหัวข้อสาขารวมถึงการผสานใด ๆ จากต้นแบบไปยังสาขาหัวข้อเพื่อช่วยให้เป็นปัจจุบัน คุณได้รับแนวคิดที่ถูกต้องว่าโค้ดใดที่นักพัฒนาซอฟต์แวร์ทำงานด้วยเมื่อพวกเขากำลังสร้าง
  • master เป็นสาขาที่ประกอบด้วยการผสานเป็นส่วนใหญ่และการรวมการกระทำแต่ละอย่างนั้นมักจะเป็น 'คะแนนดี' ในประวัติศาสตร์ที่ปลอดภัยในการตรวจสอบเพราะนั่นคือที่หัวข้อหัวข้อพร้อมที่จะรวมเข้าด้วยกัน
  • ความมุ่งมั่นส่วนตัวของหัวข้อทั้งหมดจะได้รับการเก็บรักษาไว้รวมถึงความจริงที่ว่าพวกเขาอยู่ในหัวข้อสาขาดังนั้นการแยกการเปลี่ยนแปลงเหล่านั้นจึงเป็นเรื่องธรรมดาและคุณสามารถฝึกฝนได้ตามต้องการ
  • ความขัดแย้งในการรวมจะต้องได้รับการแก้ไขเพียงครั้งเดียว (ณ จุดรวม) ดังนั้นการเปลี่ยนแปลงระดับกลางที่กระทำในสาขาหัวข้อไม่จำเป็นต้องได้รับการแก้ไขอย่างอิสระ
  • สามารถทำได้หลายครั้งอย่างราบรื่น หากคุณรวมสาขาหัวข้อของคุณเข้ากับอาจารย์เป็นระยะผู้คนสามารถสร้างสิ่งต่อไปในสาขาหัวข้อและสามารถรวมเข้าด้วยกันได้อย่างอิสระ

3
นอกจากนี้การรวมคอมไพล์ยังมีตัวเลือก "- no-ff" (ไม่มีการกรอไปข้างหน้า) ที่ช่วยให้คุณสามารถย้อนกลับการเปลี่ยนแปลงทั้งหมดที่นำเสนอโดยการรวมบางอย่างได้อย่างง่ายดาย
Tiago

3
เพียงแค่ทำให้ชัดเจนยิ่งขึ้น: คุณอ้างถึงสถานการณ์ 'เมื่อใดก็ตามที่คุณได้ผลัก' - นี้ควรเป็นตัวหนา ลิงก์ไปยังโพสต์ของ Linus นั้นยอดเยี่ยม btw. อธิบายให้ชัดเจน
honzajde

2
แต่ไม่ใช่วิธีที่ดีที่สุดในการ "อัปเดต" จากมาสเตอร์ไปยังสาขาหัวข้อของคุณก่อนที่คุณจะรวมสาขาหัวข้อเป็นมาสเตอร์ผ่าน PR (เพื่อแก้ไขข้อขัดแย้งในสาขาของคุณไม่ใช่มาสเตอร์) เรากำลังทำเช่นนั้นดังนั้นส่วนใหญ่ของหัวข้อจะเป็น "การรวมสาขาหลักเข้ากับหัวข้อ -... " แต่ที่นี่มีการระบุว่าเป็น "ฟีเจอร์" ของการรีบูทและไม่มีใครพูดถึงเพื่อรวม ... ?
ProblemsOfSumit

2
@AndrewArnott "สาขาหัวข้อส่วนใหญ่ควรสามารถผสานโดยไม่ขัดแย้งกับสาขาเป้าหมาย" จะเป็นไปได้อย่างไรเมื่อ 20 devs ทำงานใน 30 สาขา? จะมีการผสานในขณะที่คุณกำลังทำงานอยู่กับคุณ - ดังนั้นคุณต้องอัปเดตสาขาหัวข้อจากเป้าหมายก่อนสร้าง PR ... ไม่?
ProblemsOfSumit

3
ไม่ปกติ @Sumit Git สามารถผสานทิศทางใดทิศทางหนึ่งได้ดีแม้ว่าจะมีการเปลี่ยนแปลงในสาขาใดสาขาหนึ่งหรือทั้งสองสาขา เฉพาะเมื่อมีการแก้ไขรหัสบรรทัดเดียวกัน (หรือใกล้มาก) ในสองสาขาคุณจะได้รับข้อขัดแย้ง หากสิ่งนั้นเกิดขึ้นบ่อยครั้งในทีมใด ๆ ทีมควรคิดใหม่ว่าพวกเขาแจกจ่ายงานอย่างไรเนื่องจากการแก้ไขข้อขัดแย้งเป็นภาษีและทำให้พวกเขาช้าลง
Andrew Arnott

76

TLDR: มันขึ้นอยู่กับสิ่งที่สำคัญที่สุด - ประวัติที่เป็นระเบียบหรือเป็นตัวแทนที่แท้จริงของลำดับการพัฒนา

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

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

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

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

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

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

อีกครั้งที่คุณอาจต้องการรีบูตคือเมื่อคุณต้องการกำจัดการผูกมัดจากสาขาของคุณก่อนที่จะผลักดันอัปสตรีม ตัวอย่างเช่น: คอมมิทที่แนะนำโค้ดการดีบักบางส่วนก่อนหน้าและคอมมิชชันอื่น ๆ เพิ่มเติมเกี่ยวกับการล้างโค้ดนั้น วิธีเดียวในการทำเช่นนี้คือการดำเนินการ rebase เชิงโต้ตอบ:git rebase -i <branch/commit/tag>

อัปเดต: คุณต้องการใช้ rebase เมื่อคุณใช้ Git เพื่อเชื่อมต่อกับระบบควบคุมเวอร์ชันที่ไม่สนับสนุนประวัติที่ไม่ใช่เชิงเส้น ( ตัวอย่างเช่นการโค่นล้ม ) เมื่อใช้สะพาน git-svn เป็นสิ่งสำคัญมากที่การเปลี่ยนแปลงที่คุณรวมกลับไปที่การโค่นล้มเป็นรายการลำดับการเปลี่ยนแปลงที่ด้านบนของการเปลี่ยนแปลงล่าสุดในลำตัว มีเพียงสองวิธีในการทำเช่นนั้น: (1) สร้างการเปลี่ยนแปลงใหม่ด้วยตนเองและ (2) การใช้คำสั่ง rebase ซึ่งเร็วกว่ามาก

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

ปรับปรุง 3: Does one still need to merge after a successful rebase?ใช่คุณทำ เหตุผลก็คือการคืนเงินเป็นหลักเกี่ยวข้องกับ "การเปลี่ยนแปลง" ของการกระทำ ดังที่ฉันได้กล่าวไว้ข้างต้นคอมมิชชันเหล่านี้ถูกคำนวณ แต่ถ้าคุณมี 14 คอมมิตจากการแตกแขนงจากนั้นสมมติว่าไม่มีอะไรผิดปกติกับการรีบูทของคุณคุณจะได้ 14 คอมมิตข้างหน้า rebase เสร็จแล้ว คุณมีสาขาก่อนการลดระดับ คุณจะมีสาขาที่มีความยาวเท่ากันหลังจากนั้น คุณยังคงต้องรวมก่อนที่จะเผยแพร่การเปลี่ยนแปลงของคุณ กล่าวอีกนัยหนึ่ง rebase หลายครั้งตามที่คุณต้องการ (อีกครั้งเฉพาะในกรณีที่คุณไม่ได้ผลักดันการเปลี่ยนแปลงของคุณต้นน้ำ) รวมหลังจากคุณรีบูตเท่านั้น


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

1
@mbx git mergeสนับสนุน--no-ffตัวเลือกที่บังคับให้ทำการรวมคำสั่ง
กาวิน S. Yancey

63

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

เข้าใจการผสานดีขึ้นเล็กน้อย

เมื่อ Git ทำการผสานมันจะค้นหาการกระทำที่สาม:

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

กรอไปข้างหน้าหรือผสาน

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

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

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

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

อย่างไรก็ตามในหลายกรณีทั้งสองสาขาต่างก็ก้าวไปข้างหน้าเป็นรายบุคคล

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

ในการรวมเข้าด้วยกัน Git จะต้องสร้างการคอมมิทใหม่ที่มีความแตกต่างระหว่างการคอมมิทนั่นคือการรวมการคอมมิท

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

ความมุ่งมั่นของมนุษย์และการรวมความมุ่งมั่น

โดยปกติความมุ่งมั่นนั้นถูกสร้างขึ้นอย่างรอบคอบโดยมนุษย์ เป็นหน่วยที่มีความหมายซึ่งห่อหุ้มการเปลี่ยนแปลงที่เกี่ยวข้องเท่านั้นและใส่หมายเหตุประกอบไว้ด้วยความคิดเห็น

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

การรวมเข้ากับ Rebase

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

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

เรามาดูการดำเนินการ rebase ทีละขั้นตอน สถานการณ์เหมือนกันในตัวอย่างก่อนหน้านี้: เราต้องการรวมการเปลี่ยนแปลงจาก branch-B เข้ากับ branch-A แต่ตอนนี้โดยใช้ rebase

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

เราจะทำสิ่งนี้ในสามขั้นตอน

  1. git rebase branch-A // Synchronises the history with branch-A
  2. git checkout branch-A // Change the current branch to branch-A
  3. git merge branch-B // Merge/take the changes from branch-B to branch-A

อันดับแรก Git จะ "เลิกทำ" ทั้งหมดที่ทำกับสาขา A ที่เกิดขึ้นหลังจากที่สายเริ่มแยกออก (หลังจากบรรพบุรุษร่วมกันกระทำ) อย่างไรก็ตามแน่นอนว่ามันจะไม่ทิ้งพวกเขา แต่คุณสามารถคิดได้ว่าพวกเขาจะถูก "ช่วยให้รอด" ชั่วคราว

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

ต่อไปจะใช้ข้อผูกพันจาก branch-B ที่เราต้องการรวม ณ จุดนี้กิ่งทั้งสองมีลักษณะเหมือนกันทุกประการ

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

ในขั้นตอนสุดท้ายการคอมมิชชันใหม่ใน branch-A จะถูกนำมาใช้ใหม่ - แต่ในตำแหน่งใหม่ที่ด้านบนของคอมมิทคอมบิวชั่นจาก Branch-B

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

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

ในที่สุดคุณจะได้สาขาที่สะอาด สาขา-Aไม่มีกระทำที่ไม่พึงประสงค์และสร้างขึ้นโดยอัตโนมัติ

หมายเหตุ:นำมาจากที่น่ากลัวโพสต์git-towerโดย ข้อเสียของrebaseยังดีอ่านในโพสต์เดียวกัน


+1 สำหรับไดอะแกรมที่เจ๋งมาก ฉันอยากจะสามารถแสดงตัวอย่างการไหลของคอมไพล์ในลักษณะที่คล้ายกันโดยไม่มีโชค
Mikayil Abdullayev

60

ก่อนที่จะรวม / รีบูต:

A <- B <- C    [master]
^
 \
  D <- E       [branch]

หลังgit merge master:

A <- B <- C
^         ^
 \         \
  D <- E <- F

หลังgit rebase master:

A <- B <- C <- D' <- E'

(A, B, C, D, E และ F เป็นข้อผูกมัด)

ตัวอย่างเช่นนี้และอีกข้อมูลที่แสดงมากขึ้นเกี่ยวกับ Git สามารถพบได้ในGit พื้นฐานการสอน


30

ประโยคนี้ทำให้เข้าใจ:

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

ที่มา: 3.6 การแยกทาง Git - การรีบูต, Rebase vs. Merge


25

คำตอบนี้เน้นไปที่Git Flow เป็นวงกว้าง ตารางถูกสร้างด้วยASCII Table Generator ที่ดีและแผนผังประวัติด้วยคำสั่งที่ยอดเยี่ยมนี้ ( aliased as git lg):

git log --graph --abbrev-commit --decorate --date=format:'%Y-%m-%d %H:%M:%S' --format=format:'%C(bold blue)%h%C(reset) - %C(bold cyan)%ad%C(reset) %C(bold green)(%ar)%C(reset)%C(bold yellow)%d%C(reset)%n''          %C(white)%s%C(reset) %C(dim white)- %an%C(reset)'

ตารางอยู่ในลำดับย้อนกลับเพื่อให้สอดคล้องกับต้นไม้ประวัติศาสตร์มากขึ้น ดูความแตกต่างระหว่างgit mergeและgit merge --no-ffก่อน (คุณมักจะต้องการใช้git merge --no-ffเพราะมันทำให้ประวัติของคุณดูใกล้เคียงกับความเป็นจริง):

git merge

คำสั่ง:

Time          Branch "develop"             Branch "features/foo"
------- ------------------------------ -------------------------------
15:04   git merge features/foo
15:03                                  git commit -m "Third commit"
15:02                                  git commit -m "Second commit"
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

ผลลัพธ์:

* 142a74a - YYYY-MM-DD 15:03:00 (XX minutes ago) (HEAD -> develop, features/foo)
|           Third commit - Christophe
* 00d848c - YYYY-MM-DD 15:02:00 (XX minutes ago)
|           Second commit - Christophe
* 298e9c5 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git merge --no-ff

คำสั่ง:

Time           Branch "develop"              Branch "features/foo"
------- -------------------------------- -------------------------------
15:04   git merge --no-ff features/foo
15:03                                    git commit -m "Third commit"
15:02                                    git commit -m "Second commit"
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

ผลลัพธ์:

*   1140d8c - YYYY-MM-DD 15:04:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/foo' - Christophe
| * 69f4a7a - YYYY-MM-DD 15:03:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 2973183 - YYYY-MM-DD 15:02:00 (XX minutes ago)
|/            Second commit - Christophe
* c173472 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git merge VS git rebase

จุดแรก: เสมอผสานคุณสมบัติเข้าไปพัฒนาไม่เคย rebase พัฒนาจากคุณสมบัติ นี่เป็นผลสืบเนื่องจากกฎทองของการคืนเงิน :

กฎทองของการgit rebaseคือการไม่ใช้มันในที่สาธารณะสาขา

ในคำอื่น ๆ :

อย่ารีบูทสิ่งที่คุณผลักไป

ผมเองจะเพิ่ม: เว้นแต่จะเป็นสาขาคุณลักษณะและคุณและทีมงานของคุณมีความตระหนักถึงผลกระทบ

ดังนั้นคำถามของgit mergevs git rebaseจะใช้กับสาขาคุณลักษณะเท่านั้น (ในตัวอย่างต่อไปนี้--no-ffถูกนำมาใช้เสมอเมื่อทำการผสาน) โปรดทราบว่าเนื่องจากฉันไม่แน่ใจว่ามีวิธีแก้ปัญหาที่ดีกว่า ( มีการโต้วาที ) ฉันจะให้เฉพาะคำสั่งที่ทำงานทั้งสอง ในกรณีของฉันฉันชอบที่จะใช้git rebaseเพราะสร้างต้นไม้ประวัติที่ดีกว่า :)

ระหว่างสาขาฟีเจอร์

git merge

คำสั่ง:

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- --------------------------------
15:10   git merge --no-ff features/bar
15:09   git merge --no-ff features/foo
15:08                                                                    git commit -m "Sixth commit"
15:07                                                                    git merge --no-ff features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

ผลลัพธ์:

*   c0a3b89 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 37e933e - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| *   eb5e657 - YYYY-MM-DD 15:07:00 (XX minutes ago)
| |\            Merge branch 'features/foo' into features/bar - Christophe
| * | 2e4086f - YYYY-MM-DD 15:06:00 (XX minutes ago)
| | |           Fifth commit - Christophe
| * | 31e3a60 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| | |           Fourth commit - Christophe
* | |   98b439f - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \ \            Merge branch 'features/foo' - Christophe
| |/ /
|/| /
| |/
| * 6579c9c - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 3f41d96 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* 14edc68 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git rebase

คำสั่ง:

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09   git merge --no-ff features/foo
15:08                                                                    git commit -m "Sixth commit"
15:07                                                                    git rebase features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

ผลลัพธ์:

*   7a99663 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 708347a - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * 949ae73 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * 108b4c7 - YYYY-MM-DD 15:05:00 (XX minutes ago)
| |           Fourth commit - Christophe
* |   189de99 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| |/
| * 26835a0 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * a61dd08 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* ae6f5fc - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

จากdevelopไปยังสาขาฟีเจอร์

git merge

คำสั่ง:

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09                                                                    git commit -m "Sixth commit"
15:08                                                                    git merge --no-ff develop
15:07   git merge --no-ff features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

ผลลัพธ์:

*   9e6311a - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 3ce9128 - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| *   d0cd244 - YYYY-MM-DD 15:08:00 (XX minutes ago)
| |\            Merge branch 'develop' into features/bar - Christophe
| |/
|/|
* |   5bd5f70 - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| * | 4ef3853 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| | |           Third commit - Christophe
| * | 3227253 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/ /            Second commit - Christophe
| * b5543a2 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * 5e84b79 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/            Fourth commit - Christophe
* 2da6d8d - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git rebase

คำสั่ง:

Time           Branch "develop"              Branch "features/foo"           Branch "features/bar"
------- -------------------------------- ------------------------------- -------------------------------
15:10   git merge --no-ff features/bar
15:09                                                                    git commit -m "Sixth commit"
15:08                                                                    git rebase develop
15:07   git merge --no-ff features/foo
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

ผลลัพธ์:

*   b0f6752 - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 621ad5b - YYYY-MM-DD 15:09:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * 9cb1a16 - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * b8ddd19 - YYYY-MM-DD 15:05:00 (XX minutes ago)
|/            Fourth commit - Christophe
*   856433e - YYYY-MM-DD 15:07:00 (XX minutes ago)
|\            Merge branch 'features/foo' - Christophe
| * 694ac81 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * 5fd94d3 - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* d01d589 - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

หมายเหตุด้านข้าง

git cherry-pick

เมื่อคุณต้องการการคอมมิชชันที่เฉพาะเจาะจงgit cherry-pickมันเป็นคำตอบที่ดี ( -xตัวเลือกต่อท้ายบรรทัดที่เขียนว่า " (เชอร์รี่ที่เลือกจากคอมมิชชัน ... ) " ไปยังเนื้อหาข้อความคอมมิชชันดั้งเดิมดังนั้นจึงเป็นความคิดที่ดีที่จะใช้git log <commit_sha1>เพื่อดู มัน):

คำสั่ง:

Time           Branch "develop"              Branch "features/foo"                Branch "features/bar"
------- -------------------------------- ------------------------------- -----------------------------------------
15:10   git merge --no-ff features/bar
15:09   git merge --no-ff features/foo
15:08                                                                    git commit -m "Sixth commit"
15:07                                                                    git cherry-pick -x <second_commit_sha1>
15:06                                                                    git commit -m "Fifth commit"
15:05                                                                    git commit -m "Fourth commit"
15:04                                    git commit -m "Third commit"
15:03                                    git commit -m "Second commit"
15:02   git checkout -b features/bar
15:01   git checkout -b features/foo
15:00   git commit -m "First commit"

ผลลัพธ์:

*   50839cd - YYYY-MM-DD 15:10:00 (XX minutes ago) (HEAD -> develop)
|\            Merge branch 'features/bar' - Christophe
| * 0cda99f - YYYY-MM-DD 15:08:00 (XX minutes ago) (features/bar)
| |           Sixth commit - Christophe
| * f7d6c47 - YYYY-MM-DD 15:03:00 (XX minutes ago)
| |           Second commit - Christophe
| * dd7d05a - YYYY-MM-DD 15:06:00 (XX minutes ago)
| |           Fifth commit - Christophe
| * d0d759b - YYYY-MM-DD 15:05:00 (XX minutes ago)
| |           Fourth commit - Christophe
* |   1a397c5 - YYYY-MM-DD 15:09:00 (XX minutes ago)
|\ \            Merge branch 'features/foo' - Christophe
| |/
|/|
| * 0600a72 - YYYY-MM-DD 15:04:00 (XX minutes ago) (features/foo)
| |           Third commit - Christophe
| * f4c127a - YYYY-MM-DD 15:03:00 (XX minutes ago)
|/            Second commit - Christophe
* 0cf894c - YYYY-MM-DD 15:00:00 (XX minutes ago)
            First commit - Christophe

git pull --rebase

ฉันไม่แน่ใจว่าฉันสามารถอธิบายได้ดีกว่าDerek Gourlay ... โดยทั่วไปใช้git pull --rebaseแทนgit pull:) สิ่งที่ขาดหายไปในบทความนี้คือคุณสามารถเปิดใช้งานได้ตามค่าเริ่มต้น :

git config --global pull.rebase true

git rerere

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


15

Pro Gitหนังสือมีคำอธิบายที่ดีจริงๆบนหน้า rebasing

โดยทั่วไปการรวมจะใช้เวลาสองคอมมิชชันและรวมเข้าด้วยกัน

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

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

ด้วยเหตุนี้ฉันจึงรวมเข้าด้วยกันเป็นพิเศษ 99% ของเวลาที่สาขาของฉันไม่ได้แตกต่างกันมากดังนั้นหากมีความขัดแย้งจะมีเพียงแห่งเดียวหรือสองแห่ง


1
การผสานไม่รวมการผูกมัด - นั่นจะเป็นการเขียนประวัติศาสตร์ใหม่ Rebase ทำอย่างนั้น
kellyfj

4

Git rebase ใช้ในการสร้างเส้นทางการแตกสาขาในตัวล้างประวัติและโครงสร้างที่เก็บข้อมูลเชิงเส้น

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

หลังจากทำการ rebase เราก็กำจัดการกระทำพิเศษที่เราเคยดูว่าเราทำการผสานปกติหรือไม่

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


4

หากคุณเป็นนักพัฒนาเพียงคนเดียวคุณสามารถใช้rebaseแทนการรวมเพื่อให้มีประวัติที่ชัดเจน

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


3

ตัวอย่างที่ใช้งานได้จริงบางอย่างเชื่อมโยงกับการพัฒนาขนาดใหญ่ที่Gerritใช้สำหรับการตรวจสอบและรวมการส่งมอบ:

ฉันรวมเมื่อยกระดับฟีเจอร์สาขาของฉันไปยังต้นแบบรีโมทใหม่ นี้จะช่วยให้การทำงานยกน้อยที่สุดและมันเป็นเรื่องง่ายที่จะปฏิบัติตามประวัติศาสตร์ของการพัฒนาคุณลักษณะในตัวอย่างgitk

git fetch
git checkout origin/my_feature
git merge origin/master
git commit
git push origin HEAD:refs/for/my_feature

ฉันรวมเมื่อฉันเตรียมส่งมอบ

git fetch
git checkout origin/master
git merge --squash origin/my_feature
git commit
git push origin HEAD:refs/for/master

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

git fetch
git fetch <gerrit link>
git checkout FETCH_HEAD
git rebase origin/master
git push origin HEAD:refs/for/master

3

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

เมื่อใดที่คุณควรใช้ rebase

  • เมื่อคุณไม่ได้ผลักสาขา / ไม่มีใครทำงานอยู่
  • คุณต้องการประวัติเต็ม
  • คุณต้องการหลีกเลี่ยงการ "รวม .. .. " สร้างข้อความ

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

ตรวจสอบให้แน่ใจว่าคุณใช้git merge feature-branch --ff-onlyเพื่อให้แน่ใจว่าไม่มีข้อขัดแย้งในการสร้างการคอมมิชชันเดียวเมื่อคุณรวมคุณสมบัติของคุณกลับไปยังหลักสิ่งนี้น่าสนใจหากคุณกำลังใช้สาขาฟีเจอร์สำหรับทุกงานที่คุณทำเมื่อคุณได้รับประวัติของฟีเจอร์สาขา แต่ไม่ใช่ "ผสานแล้ว"

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

คุณควรใช้การผสานเมื่อใด

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

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


-4

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


1
@Benjaminhull ขอบคุณ! - ยกเว้นฉันหวังว่าคำตอบของฉันจะเป็นไปตามข้อเท็จจริง ความคิดเห็นของ IMHO นั้นมีอยู่น้อยมากในเรื่องแบบนี้: ความจริงที่ว่าการสูญเสียประวัติศาสตร์ที่แท้จริงของคุณทำให้ชีวิตหนักขึ้นในภายหลัง
Marnen Laibow-Koser

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