อย่างไรและ / หรือทำไมการรวมกันใน Git ดีกว่าใน SVN


400

ฉันเคยได้ยินในไม่กี่ที่ที่หนึ่งในเหตุผลหลักที่ว่าทำไมระบบควบคุมเวอร์ชันที่กระจายส่องแสงนั้นเป็นการผสานที่ดีกว่าเครื่องมือแบบดั้งเดิมอย่าง SVN อันนี้เป็นเพราะความแตกต่างโดยธรรมชาติในการทำงานของทั้งสองระบบหรือการใช้งาน DVCS เฉพาะเช่น Git / Mercurial เพียงแค่มีการรวมอัลกอริทึมที่ฉลาดกว่า SVN หรือไม่


ฉันยังไม่ได้รับคำตอบที่สมบูรณ์จากการอ่านคำตอบที่ดีที่นี่ โพสต์ใหม่ - stackoverflow.com/questions/6172037/…
ripper234


มันขึ้นอยู่กับรุ่นของคุณ ในกรณีที่ง่ายกว่า svn มักจะดีกว่าเพราะไม่ได้เรียกการรวมแบบ 2 ทางโดยบังเอิญการรวม 3 ทางเช่น git สามารถทำได้หากคุณกด / ผสาน / ดึง / กดในสาขาการพัฒนาเดียว ดูที่: svnvsgit.com
Erik Aronesty

คำตอบ:


556

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

เหตุใดการโค่นล้มจึงผสานดูด ?

ไตร่ตรองตัวอย่างนี้:

      1   2   4     6     8
trunk o-->o-->o---->o---->o
       \
        \   3     5     7
b1       +->o---->o---->o

เมื่อเราต้องการรวมการเปลี่ยนแปลงของ b1 เข้ากับ trunk เราจะออกคำสั่งต่อไปนี้ในขณะที่ยืนอยู่บนโฟลเดอร์ที่มี trunk ตรวจสอบแล้ว:

svn merge -r 2:7 {link to branch b1}

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

      1   2   4     6     8   9
trunk o-->o-->o---->o---->o-->o      "the merge commit is at r9"
       \
        \   3     5     7
b1       +->o---->o---->o

อย่างไรก็ตามวิธีนี้ในการระบุช่วงของการแก้ไขได้อย่างรวดเร็วเมื่อต้นไม้เวอร์ชันเติบโตขึ้นเนื่องจากการโค่นล้มไม่ได้มีข้อมูลเมตาใด ๆ เมื่อใดและการแก้ไขใดที่ผสานเข้าด้วยกัน ไตร่ตรองว่าจะเกิดอะไรขึ้นในภายหลัง:

           12        14
trunk  …-->o-------->o
                                     "Okay, so when did we merge last time?"
              13        15
b1     …----->o-------->o

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

เพื่อลดการโค่นล้มนี้ตอนนี้เก็บข้อมูล meta สำหรับสาขาและผสาน นั่นจะแก้ปัญหาทั้งหมดใช่ไหม

และโอ้โดยวิธีการโค่นล้มยังคงดูด ...

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

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

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

เหตุใด DVCS เช่น Git, Mercurial และ Bazaar จึงดีกว่าการโค่นล้มในการแยกและรวม?

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

สิ่งแรกที่คุณทำเมื่อคุณทำงานกับ DVCS คือการโคลนที่เก็บข้อมูล (git's clone, hg's cloneและ bzr's branch) การโคลนเป็นแนวคิดเหมือนกับการสร้างสาขาในการควบคุมเวอร์ชัน บางคนเรียกว่าฟอร์กกิ้งหรือการแตกกิ่ง (แม้ว่าอันหลังมักจะใช้เพื่ออ้างถึงสาขาที่อยู่ร่วมกัน) แต่มันก็เป็นสิ่งเดียวกัน ผู้ใช้ทุกคนใช้ที่เก็บข้อมูลของตัวเองซึ่งหมายความว่าคุณมีสาขาต่อผู้ใช้ที่เกิดขึ้น

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

ตัวอย่างง่ายๆของการรวมจะเป็นนี้ ลองนึกภาพที่เก็บส่วนกลางเรียกว่าoriginและผู้ใช้อลิซโคลนที่เก็บไปยังเครื่องของเธอ

         a…   b…   c…
origin   o<---o<---o
                   ^master
         |
         | clone
         v

         a…   b…   c…
alice    o<---o<---o
                   ^master
                   ^origin/master

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

อลิซทำงานกับ repo ของเธอกระทำในที่เก็บของเธอและตัดสินใจที่จะผลักดันการเปลี่ยนแปลงของเธอ:

         a…   b…   c…
origin   o<---o<---o
                   ^ master

              "what'll happen after a push?"


         a…   b…   c…   d…   e…
alice    o<---o<---o<---o<---o
                             ^master
                   ^origin/master

วิธีแก้ปัญหาค่อนข้างง่ายสิ่งเดียวที่originพื้นที่เก็บข้อมูลต้องทำคือนำการแก้ไขใหม่ทั้งหมดและย้ายสาขาไปเป็นการแก้ไขล่าสุด (ซึ่ง git เรียกว่า "กรอไปข้างหน้า"):

         a…   b…   c…   d…   e…
origin   o<---o<---o<---o<---o
                             ^ master

         a…   b…   c…   d…   e…
alice    o<---o<---o<---o<---o
                             ^master
                             ^origin/master

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

แล้วคุณจะแสดงตัวอย่างที่มีการผสานที่แท้จริงได้อย่างไร

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

         a…   b…   c…   f…
bob      o<---o<---o<---o
                        ^ master
                   ^ origin/master

                   "can Bob push his changes?" 

         a…   b…   c…   d…   e…
origin   o<---o<---o<---o<---o
                             ^ master

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

ดังนั้น Bob ต้องดึงและรวมการเปลี่ยนแปลง (กับ git's pull; หรือ hg's pulland merge; หรือ bzr's merge) นี่เป็นกระบวนการสองขั้นตอน Bob คนแรกต้องดึงข้อมูลการแก้ไขใหม่ซึ่งจะคัดลอกมันจากที่originเก็บ ตอนนี้เราสามารถเห็นได้ว่ากราฟเบี่ยงเบน:

                        v master
         a…   b…   c…   f…
bob      o<---o<---o<---o
                   ^
                   |    d…   e…
                   +----o<---o
                             ^ origin/master

         a…   b…   c…   d…   e…
origin   o<---o<---o<---o<---o
                             ^ master

ขั้นตอนที่สองของกระบวนการดึงคือการรวมเคล็ดลับการแยกและทำการกระทำของผล:

                                 v master
         a…   b…   c…   f…       1…
bob      o<---o<---o<---o<-------o
                   ^             |
                   |    d…   e…  |
                   +----o<---o<--+
                             ^ origin/master

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

                                 v origin/master
                                 v master
         a…   b…   c…   f…       1…
bob      o<---o<---o<---o<-------o
                   ^             |
                   |    d…   e…  |
                   +----o<---o<--+

                                 v master
         a…   b…   c…   f…       1…
origin   o<---o<---o<---o<-------o
                   ^             |
                   |    d…   e…  |
                   +----o<---o<--+

มีอีกตัวเลือกในการรวมเป็น git และ hg เรียกว่าrebaseซึ่งจะย้ายการเปลี่ยนแปลงของ Bob ไปหลังจากการเปลี่ยนแปลงล่าสุด เนื่องจากฉันไม่ต้องการคำตอบนี้อีกต่อไปฉันจะให้คุณอ่านgit , mercurialหรือbazaar docs เกี่ยวกับสิ่งนั้นแทน

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

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

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


6
ฉันไม่เห็นด้วยกับสาขาของคุณ == โต้แย้งทางเสียง สาขาจำนวนมากไม่สับสนคนเพราะผู้นำนักพัฒนาควรบอกคนที่จะใช้สำหรับฟีเจอร์ใหญ่ ๆ ... ดังนั้นผู้พัฒนาสองคนอาจใช้งานสาขา X เพื่อเพิ่ม "flying dinosaurs", 3 อาจทำงานกับ Y เพื่อ "ให้คุณโยน รถยนต์กับผู้คน "
นายบอยมี. ค.

16
จอห์น: ใช่กิ่งก้านเล็ก ๆ มีสัญญาณรบกวนเล็กน้อยและจัดการได้ แต่กลับมาหลังจากที่คุณได้เห็นสาขาและแท็กมากกว่า 50 สาขาในกรณีที่ถูกโค่นล้มหรือชัดเจนกรณีที่พวกเขาส่วนใหญ่คุณไม่สามารถบอกได้ว่าพวกเขาทำงานอยู่หรือไม่ ปัญหาการใช้งานจากเครื่องมือนอกเหนือ เหตุใดจึงมีสิ่งที่เกลื่อนกลาดอยู่ในที่เก็บ อย่างน้อยใน p4 (เนื่องจาก "เวิร์กสเปซ" ของผู้ใช้เป็นหลักต่อผู้ใช้), git หรือ hg คุณมีตัวเลือกที่จะไม่ให้ทุกคนรู้เกี่ยวกับการเปลี่ยนแปลงที่คุณทำจนกว่าคุณจะผลักพวกเขาอัปสตรีมซึ่งปลอดภัย ป้องกันเมื่อการเปลี่ยนแปลงมีความเกี่ยวข้องกับผู้อื่น
Spoike

24
ฉันไม่ได้รับ "สาขาทดลองจำนวนมากของคุณเป็นอาร์กิวเมนต์เสียงเช่น @Spoike เรามีโฟลเดอร์" ผู้ใช้ "ที่ผู้ใช้ทุกคนมีโฟลเดอร์ของตัวเองเขาสามารถแยกสาขาได้บ่อยเท่าที่เขาต้องการสาขามีราคาไม่แพงในการโค่นล้มและ หากคุณเพิกเฉยต่อโฟลเดอร์ของผู้ใช้รายอื่น (ทำไมคุณถึงต้องใส่ใจพวกเขาต่อไป) คุณจะไม่เห็นเสียงรบกวน แต่สำหรับฉันแล้วการผสานใน SVN ไม่ได้ดูด (และฉันทำบ่อยและไม่เล็กเลย โครงการ) ดังนั้นฉันอาจจะทำผิดพลาด) อย่างไรก็ตามการรวมกันของ Git และ Mercurial นั้นเหนือกว่าและคุณก็ชี้ให้เห็นอย่างชัดเจน
John Smithers

11
ใน svn มันง่ายที่จะฆ่ากิ่งที่ไม่ได้ใช้งานคุณแค่ลบมัน ความจริงที่ว่าผู้คนไม่ลบสาขาที่ไม่ได้ใช้ดังนั้นการสร้างความยุ่งเหยิงเป็นเพียงเรื่องของการทำความสะอาด คุณสามารถปิดท้ายด้วยสาขาชั่วคราวจำนวนมากใน Git ได้เช่นกัน ในที่ทำงานของฉันเราใช้ไดเรกทอรีระดับบนสุด "temp-branch" นอกเหนือจากที่เป็นมาตรฐาน - สาขาส่วนบุคคลและสาขาทดลองไปที่นั่นแทนที่จะยุ่งเหยิงในไดเรกทอรีสาขาที่จัดเก็บรหัสบรรทัด "เป็นทางการ" (เราไม่ ใช้สาขาฟีเจอร์)
เคนหลิว

10
นี่หมายถึงว่านั่นจากการโค่นล้ม v1.5 อย่างน้อยก็สามารถรวมกันเป็นคอมไพล์ได้หรือไม่?
Sam

29

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

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

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


4
คุณมีตัวอย่างที่ svn มีการรวมความขัดแย้ง แต่คอมไพล์ไม่ได้หรือไม่
Gqqnbig

17

ใส่เพียงการดำเนินการผสานจะทำได้ดีกว่าในGitกว่าในSVN ก่อน 1.5 SVN ไม่ได้บันทึกการดำเนินการผสานดังนั้นจึงไม่สามารถทำการรวมในอนาคตได้โดยไม่ได้รับความช่วยเหลือจากผู้ใช้ซึ่งจำเป็นต้องให้ข้อมูลที่ SVN ไม่ได้บันทึก ด้วย 1.5 จะดีขึ้นและแน่นอนว่ารูปแบบการจัดเก็บ SVN นั้นมีความสามารถที่ GAG's DAG เล็กน้อย แต่ SVN เก็บข้อมูลการผสานในรูปแบบที่ค่อนข้างซับซ้อนซึ่งช่วยให้การผสานใช้เวลามากกว่าใน Git - ฉันสังเกตเห็นว่ามีปัจจัย 300 ครั้งในการประมวลผล

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

ในทางกลับกัน Git ไม่ได้ติดตามการเปลี่ยนชื่อ แต่คิดออกหลังจากความจริง (ในเวลารวม) และทำได้อย่างน่าอัศจรรย์

การนำเสนอการผสาน SVN ก็มีปัญหาเช่นกัน ใน 1.5 / 1.6 คุณสามารถรวมจากลำตัวไปยังสาขาได้บ่อยเท่าที่ต้องการโดยอัตโนมัติ แต่จะรวมในทิศทางอื่นที่จำเป็นต้องประกาศ (--reintegrate ) และปล่อยให้สาขาอยู่ในสถานะใช้งานไม่ได้ ในภายหลังพวกเขาพบว่าจริง ๆ แล้วไม่ใช่กรณีนี้และ a) --reintegrate สามารถคำนวณได้โดยอัตโนมัติและ b) สามารถผสานการทำซ้ำทั้งสองทิศทางได้

แต่หลังจากทั้งหมดนี้ (ซึ่ง IMHO แสดงให้เห็นถึงการขาดความเข้าใจในสิ่งที่พวกเขากำลังทำ) ฉันจะ (ตกลงฉัน) ข้อควรระวังอย่างยิ่งที่จะใช้ SVN ในสถานการณ์การแตกกิ่งก้านสาขาที่ไม่สำคัญและพยายามนึกถึงสิ่งที่ Git คิด ผลการรวม

ประเด็นอื่น ๆ ที่ทำในคำตอบในขณะที่การเปิดเผยสาขาทั่วโลกใน SVN นั้นไม่เกี่ยวข้องกับความสามารถในการผสาน (แต่สำหรับการใช้งาน) นอกจากนี้ 'Git เก็บการเปลี่ยนแปลงในขณะที่ร้านค้า SVN (สิ่งที่แตกต่าง)' ส่วนใหญ่จะปิด Git เก็บคอนเซ็ปต์แต่ละแนวคิดเป็นแผนผังแยกต่างหาก (เช่น aไฟล์tar ) จากนั้นใช้ฮิวริสติกจำนวนหนึ่งเพื่อจัดเก็บอย่างมีประสิทธิภาพ การคำนวณการเปลี่ยนแปลงระหว่างการคอมมิทสองครั้งนั้นแยกจากการใช้งานสตอเรจ สิ่งที่เป็นจริงคือ Git เก็บประวัติ DAG ในรูปแบบที่ตรงไปตรงมามากขึ้นซึ่ง SVN ทำ mergeinfo ใครก็ตามที่พยายามเข้าใจสิ่งหลังจะรู้ว่าฉันหมายถึงอะไร

โดยสรุป: Git ใช้แบบจำลองข้อมูลที่ง่ายกว่ามากในการจัดเก็บการแก้ไขมากกว่า SVN และดังนั้นจึงสามารถใส่พลังงานจำนวนมากลงในอัลกอริทึมผสานที่เกิดขึ้นจริงแทนที่จะพยายามรับมือกับการเป็นตัวแทน => การผสานที่ดีขึ้นจริง


11

สิ่งหนึ่งที่ไม่ได้กล่าวถึงในคำตอบอื่น ๆ และนั่นเป็นข้อได้เปรียบที่ยิ่งใหญ่ของ DVCS คือคุณสามารถกระทำภายในเครื่องก่อนที่จะทำการเปลี่ยนแปลง ใน SVN เมื่อฉันมีการเปลี่ยนแปลงฉันต้องการเช็คอินและมีใครบางคนทำข้อผูกพันในสาขาเดียวกันในระหว่างนี้หมายความว่าฉันต้องทำsvn updateก่อนที่ฉันจะสามารถกระทำได้ ซึ่งหมายความว่าการเปลี่ยนแปลงของฉันและการเปลี่ยนแปลงจากบุคคลอื่นจะถูกผสมเข้าด้วยกันและไม่มีวิธีใดที่จะยกเลิกการผสาน (เช่นเดียวกับgit resetหรือhg update -C) เนื่องจากไม่มีข้อผูกมัดที่จะกลับไป หากการผสานนั้นไม่สำคัญหมายความว่าคุณจะไม่สามารถทำงานกับคุณสมบัติของคุณต่อไปได้ก่อนที่คุณจะล้างผลลัพธ์การผสาน

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


10

แก้ไข: นี้เป็นหลักที่อยู่ในส่วนนี้ของคำถาม:
นี่คือจริงเนื่องจากความแตกต่างอยู่ในวิธีการทำงานสองระบบหรือการใช้งานที่เฉพาะเจาะจงเช่น DVCS Git / Mercurial เพียงแค่มีขั้นตอนวิธีการรวมฉลาดกว่า SVN?
TL; DR - เครื่องมือเฉพาะเหล่านั้นมีอัลกอริธึมที่ดีกว่า การเผยแพร่มีประโยชน์ต่อเวิร์กโฟลว์บ้าง
สิ้นสุดการแก้ไข

ฉันอ่านคำตอบที่ยอมรับได้ มันผิดธรรมดา

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

สมมติว่าคุณต้องการทำ "สิ่งที่ฉลาด" Git คือ "ดีกว่าที่" และคุณก็ถูกตรวจสอบใน SVN แล้ว

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

ในตอนท้ายของวันระบบควบคุมเวอร์ชันใด ๆ จะให้ฉัน

1. Generate a set of objects at a given branch/revision.
2. Provide the difference between a parent child branch/revisions.

นอกจากนี้สำหรับการรวมมันยังมีประโยชน์ (หรือที่สำคัญ) ที่จะรู้

3. The set of changes have been merged into a given branch/revision.

หลายใจ , Git และ Subversion (ตอนนี้โดยพื้นฐานแล้วก่อนหน้านี้ใช้ svnmerge.py) สามารถให้ข้อมูลทั้งสามชิ้นได้ เพื่อแสดงให้เห็นถึงสิ่งที่ดีกว่าด้วย DVC โปรดชี้ให้เห็นข้อมูลบางส่วนที่สี่ซึ่งมีอยู่ใน Git / Mercurial / DVC ที่ไม่มีใน SVN / VC ส่วนกลาง

ไม่ได้หมายความว่าพวกเขาไม่ใช่เครื่องมือที่ดีกว่า!


1
ใช่ฉันตอบคำถามในรายละเอียดไม่ใช่พาดหัว svn และ git สามารถเข้าถึงข้อมูลเดียวกัน (จริง ๆ แล้ว svn มีมากกว่า) ดังนั้น svn สามารถทำอะไรก็ได้ที่ git ทำ แต่พวกเขาตัดสินใจออกแบบที่แตกต่างกันและดังนั้นจึงไม่จริง หลักฐานเกี่ยวกับ DVC / รวมศูนย์คือคุณสามารถเรียกใช้คอมไพล์เป็น VC ส่วนกลาง (อาจมีกฎบางอย่างบังคับ) และคุณสามารถเรียกใช้ svn กระจาย (แต่มันแย่มาก) อย่างไรก็ตามทั้งหมดนี้ก็เป็นวิชาการเกินไปสำหรับคนส่วนใหญ่ - git และ hg ทำการแยกและรวมได้ดีกว่า svn นั่นเป็นเรื่องสำคัญเมื่อเลือกเครื่องมือ :-)
ปีเตอร์

5
จนถึงเวอร์ชัน 1.5 การโค่นล้มไม่ได้เก็บข้อมูลที่จำเป็นทั้งหมด เมื่อใช้โพสต์ 1.5 SVN ข้อมูลที่จัดเก็บจะแตกต่างกัน: Git เก็บผู้ปกครองทั้งหมดของการรวมการกระทำ
Jakub Narębski

4
เครื่องมือที่ยากที่จะดำเนินการอีกครั้งในพื้นที่เก็บข้อมูล SVN git merge-baseคือ ด้วย git คุณสามารถพูดว่า "branch a and b split ที่ revision x" แต่ svn เก็บ "ไฟล์ที่ถูกคัดลอกจาก foo to bar" ดังนั้นคุณต้องใช้การวิเคราะห์พฤติกรรมเพื่อหาว่าการคัดลอกไปที่ bar กำลังสร้างสาขาใหม่แทนการคัดลอกไฟล์ภายในโครงการ เคล็ดลับคือการแก้ไขใน svn ถูกกำหนดโดยหมายเลขการแก้ไขและเส้นทางพื้นฐาน แม้ว่ามันจะเป็นไปได้ที่จะสันนิษฐานว่า "ลำต้น" ส่วนใหญ่เวลามันกัดถ้ามีจริงกิ่ง
ดักลาส

2
Re: "ไม่มีข้อมูลใดที่ git เก็บรักษาไว้หรือสามารถสืบมาได้ว่า svn นั้นไม่ได้เก็บรักษาหรือสามารถสืบมาได้" - ฉันพบว่า SVN จำไม่ได้ว่าเมื่อรวมสิ่งต่าง ๆ เข้าด้วยกัน หากคุณต้องการดึงงานจากลำตัวเข้าไปในสาขาของคุณแล้วไปมาการรวมตัวกันอาจกลายเป็นเรื่องยาก ใน Git แต่ละโหนดในกราฟการแก้ไขจะรู้ว่ามาจากไหน มีผู้ปกครองมากถึงสองคนและมีการเปลี่ยนแปลงในท้องถิ่น ฉันเชื่อว่า Git จะสามารถผสานมากกว่า SVN ได้ หากคุณรวมใน SVN และลบสาขาดังนั้นประวัติสาขาจะหายไป หากคุณรวมใน GIT และลบสาขากราฟจะยังคงอยู่และจะมีปลั๊กอิน "ตำหนิ"
Richard Corfield

1
มันไม่ใช่กรณีที่คอมไพล์และ Mercurial มีข้อมูลที่จำเป็นทั้งหมดในเครื่อง แต่ในขณะที่ svn จำเป็นต้องดูทั้งข้อมูลท้องถิ่นและส่วนกลางเพื่อรับข้อมูล
Warren Dew

8

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

ฉันยังคงใช้ SVN อย่างหนัก แต่ฉันก็ยินดีมากที่ฉันใช้ Git ไม่กี่ครั้ง

เป็นการอ่านที่ดีถ้าคุณมีเวลา: ทำไมฉันถึงเลือก Git


นั่นคือสิ่งที่ฉันอ่านด้วยและนั่นคือสิ่งที่ฉันคาดไว้ แต่ในทางปฏิบัติมันไม่ทำงาน
Rolf

Git ติดตามเนื้อหาของไฟล์จะแสดงเฉพาะเนื้อหาที่มีการเปลี่ยนแปลง
Ferrybig

6

แค่อ่านบทความในบล็อกของ Joel (น่าเสียดายที่เขาเป็นคนสุดท้าย) อันนี้เกี่ยวกับ Mercurial แต่จริงๆแล้วมันพูดถึงข้อดีของระบบ VC แบบกระจายเช่น Git

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

อ่านบทความที่นี่


5
นั่นเป็นหนึ่งในบทความที่ฉันคิดก่อนโพสต์ที่นี่ แต่ "คิดในแง่ของการเปลี่ยนแปลง" เป็นคำที่ฟังดูคลุมเครือเกี่ยวกับการตลาด (จำได้ว่า บริษัท ของ Joel ขาย DVCS ทันที)
Mr. Boy

2
ฉันคิดว่ามันคลุมเครือเช่นกัน ... ฉันคิดเสมอว่าเซ็ตการแก้ไขนั้นเป็นส่วนสำคัญของเวอร์ชัน (หรือรุ่นที่ค่อนข้างจะแก้ไข) ซึ่งทำให้ฉันประหลาดใจว่าโปรแกรมเมอร์บางคนไม่คิดในแง่ของการเปลี่ยนแปลง
Spoike

สำหรับระบบที่ "คิดในแง่ของการเปลี่ยนแปลง" จริง ๆ ลองดู Darcs
Max

@ Max: แน่นอน แต่เมื่อการผลักดันเข้ามา Git ก็มอบความรู้สึกที่ Darcs ให้ความรู้สึกเจ็บปวดราวกับเป็นการโค่นล้มเมื่อมันมาถึงการรวมเข้าด้วยกัน
tripleee

ข้อเสียสามประการของ Git คือ a) มันไม่ดีสำหรับไบนารีเช่นการจัดการเอกสารที่ไม่น่าเป็นไปได้มากที่คนจะต้องการแยกสาขาและรวม b) ถือว่าคุณต้องการโคลนทุกอย่าง c) มันเก็บประวัติของทุกสิ่งในโคลน สำหรับการเปลี่ยนแปลงไบนารีที่ก่อให้เกิดโคลนบ่อยครั้ง ฉันคิดว่า VCS แบบรวมศูนย์นั้นดีกว่าสำหรับกรณีการใช้งานเหล่านั้น Git นั้นดีกว่าสำหรับการพัฒนาตามปกติโดยเฉพาะอย่างยิ่งสำหรับการรวมและการแตกแขนง
locka
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.