Kaip ir (arba) kodėl Git sujungia geriau nei SVN?

Kai kuriose vietose girdėjau, kad viena iš pagrindinių priežasčių, dėl kurių paskirstytos versijos valdymo sistemos spindi, yra daug geriau derinama nei tradiciniuose įrankiuose, pvz., SVN. Tiesą sakant, tai yra dėl to, kad abiejose sistemose arba specifiniuose DVCS diegimuose, pvz., „Git / Mercurial“, būdingi skirtumai, tik yra protingesni jungimo algoritmai nei SVN?

381
P. 18 марта '10 в 19:32 2010-03-18 19:32 Berniukas kovo 18 '10, 7:32 2010-03-18 19:32
@ 7 atsakymai

Pareiškimas apie tai, kodėl susiliejimas DVCS yra geresnis nei Subversion, iš esmės buvo grindžiamas tuo, kaip filialai ir susiliejimas Subversion veikė prieš kurį laiką. Subversion prieš 1.5.0 nesaugo jokios informacijos apie filialų susijungimą, taigi, kai norėjote sujungti, teko nurodyti, kokie pakeitimų intervalai turėjo būti sujungti.

Tad kodėl „Subversion“ susilieja?

Apsvarstykite šį pavyzdį:

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

Kai norime sujungti , b1 pakeičiami kūnui, kad mes išleisime šią komandą, stovinčią aplanke su ryšio linija, kuri patikrins:

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

... kuris bandys sujungti pakeitimus iš b1 į vietinį darbo katalogą. Tada įvykdysite pakeitimus, pašalinus bet kokius konfliktus ir patikrinkite rezultatus. Nustatant peržiūrą medis atrodys taip:

  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 

Tačiau, kaip apibrėžti versijos medį, šis apibrėžimo intervalų apibrėžimo būdas greitai išnyksta, nes subversyvi veikla neturi metaduomenų apie tai, kada ir kokie pakeitimai sujungti. Pagalvokite, kas nutiks toliau:

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

Iš esmės tai yra problema, susijusi su saugyklos, kuriai Subversion yra sukurta, kūrimui, jums reikia sukurti naują virtualų katalogą saugykloje, kurioje bus jungiamosios linijos kopija, tačiau ji nesaugo jokios informacijos apie tai, kada ir kas vėl susijungė. Tai kartais sukelia nemalonius sujungimo konfliktus. Dar blogiau yra tai, kad „Subversion“ naudojo numatytąjį dviejų krypčių sujungimą, kuriam būdingi tam tikri automatinio susiliejimo apribojimai, kai dvi šakos šakos nėra lyginamos su jų bendru protėviu.

Norėdami sušvelninti šį „Subversion“, dabar saugomi filialo metaduomenys ir sujungimas. Ar tai tinkamai išsprendžia visas problemas?

Beje, „Subversion“ vis dar sucks ...

Centralizuotoje sistemoje, pavyzdžiui, subversijoje, ima virtualūs katalogai. Kodėl? Kadangi kiekvienas turi prieigą, kad galėtumėte juos peržiūrėti ... net ir šiukšlių eksperimentinė. Filialai yra geri, jei norite eksperimentuoti , bet nenorite eksperimentuoti su savo tetomis . Tai yra rimtas pažinimo triukšmas. Kuo daugiau filialų pridėsite, tuo daugiau šūdų pamatysite.

Kuo daugiau vyriausybės filialų turėsite saugykloje, tuo sunkiau bus stebėti visas skirtingas šakas. Taigi klausimas, kurį turėsite, yra tas, kad filialas vis dar vystosi arba yra tikrai miręs, kurį sunku pasakyti bet kurioje centralizuotoje versijos valdymo sistemoje.

Daugeliu atvejų, nuo to, ką mačiau, organizacija pagal nutylėjimą naudos vieną didelį filialą. Koks gėda, nes, savo ruožtu, bus sunku sekti bandymų ir išleidimo versijas, taip pat nieko, kas gera nuo šakotojo.

Tad kodėl DVCS, pvz., „Git“, „Mercurial“ ir „Bazaar“, yra geriau nei „Subversion“ su šakomis ir sujungimu?

Yra labai paprasta priežastis: šakojimas yra pirmos klasės koncepcija . Nėra virtualių katalogų dizainui, o filialai yra kieti objektai DVCS, kurie turi būti tokie, kad galėtų dirbti tik su saugyklos sinchronizavimu (t.y. stumti ir traukti).

Pirmas dalykas, kurį darote dirbdami su DVCS, yra klonuoti saugyklas (git clone , hg clone ir bzr branch ). Klonavimas yra konceptualiai toks pat kaip filialo sukūrimas versijos valdyme. Kai kurie žmonės tai vadina šakelėmis arba šakėmis (nors pastarieji dažnai naudojami taip pat, kad žymėtų bendrai esančius filialus), tačiau jie yra vienas ir tas pats. Kiekvienas vartotojas valdo savo saugyklą, o tai reiškia, kad jūs ir toliau vartojate kiekvieną vartotoją.

Versijos struktūra nėra medis , o grafikas . Konkrečiau nukreiptas aciklinis grafikas (DAG, tai grafikas, neturintis ciklų). Iš tikrųjų nereikia pasikliauti DAG specifika, išskyrus tai, kad kiekviena komanda turi vieną ar kelias pagrindines nuorodas (kurių pagrindu buvo pagrįstas taisymas). Taigi toliau pateiktose diagramose rodomos rodyklės tarp pataisymų priešinga kryptimi dėl to.

Labai paprastas susijungimo pavyzdys būtų; Įsivaizduokite centrinę saugyklą, pavadintą „Alice“ ir „Alice“, klonuojant saugyklą į savo kompiuterį.

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

Klonavimo metu vyksta tai, kad kiekviena pataisa yra nukopijuota į Alice tiksliai taip, kaip ji buvo (kurią patvirtina unikaliai identifikuojantis maišos identifikatorius), ir pastabas, kuriose yra kilmės šakos.

Tada Alice dirba su savo atpirkimo sandoriu, įsipareigoja savo saugykloje ir nusprendžia daryti pakeitimus:

  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 

Sprendimas yra gana paprastas, vienintelis dalykas, kurį reikia padaryti, yra origin duomenų saugykla, visa nauja pataisa ir jos filialo perkėlimas į naują versiją (kuri sukelia „greitą perėjimą“):

  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 

Jei naudojote anksčiau pateiktą pavyzdį, jums nereikia nieko derinti . Taigi problema tikrai nėra algoritmų sujungimas, nes trijų krypčių sujungimo algoritmas beveik vienodas tarp visų versijų valdymo sistemų. Problema yra daugiau apie struktūrą nei bet kas kitas .

Taigi, kaip jums parodyti man tikrą susijungimo pavyzdį?

Tačiau aukščiau pateiktas pavyzdys yra labai paprastas naudojimo pavyzdys, todėl leidžia jums padaryti daug labiau susuktą, nors ir bendresnį. Atminkite, kad origin prasidėjo trimis versijomis? Na, vaikinas, kuris juos sukūrė, pavadino jį Bobu, dirbo savarankiškai ir padarė savo skliautą:

  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 

Dabar Bobas negali tiesiogiai nukreipti savo pakeitimų į origin saugyklą. Kaip sistema tai aptinka, patikrindama, ar Bobas persvarstys tiesioginius nusileidimus iš origin , kuris šiuo atveju nėra. Bet koks bandymas stumti priverčia sistemą pasakyti kažką panašaus į „ Uh ... aš bijau, kad negalėsiu tai padaryti Bobui “.

Taigi Bobui reikia patraukti ir tada sujungti pakeitimus (naudojant „git pull , „hg pull and merge arba „bzr“ merge ). Tai yra dviejų etapų procesas. Pirma, Bobas turėtų gauti naujas versijas, kurios nukopijuos jas iš origin duomenų saugyklos. Dabar matome, kad grafikas skiriasi:

  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 

Antrasis braižymo proceso etapas yra sujungti skirtingus patarimus ir padaryti rezultatą:

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

Tikimės, kad susiliejimas nesusidurs su konfliktais (jei tikitės, galite atlikti du žingsnius rankiniu būdu, naudodami fetch ir merge ). Dar reikia dar kartą įtraukti šiuos origin pokyčius, kurie sukels pagreitintą susijungimą, nes sujungimo komanda yra tiesioginis pastarojo palikuonis origin saugykloje:

  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<--+ 

Yra dar viena galimybė sujungti į „git“ ir „hg“, vadinamą „rebase“, kuri paskatins „Bob“ pakeitimus po naujų pakeitimų. Kadangi nenoriu, kad šis atsakymas būtų išsamesnis, leisiu jums skaityti git , mercurial ar bazaar dokumentus.

Kaip skaitytojo pratybas pabandykite išsiaiškinti, kaip jis veiks su kitu susijusiu vartotoju. Panašiai tai daroma kaip pavyzdys su Bobu. Sandėlių susiliejimas yra paprastesnis, nei manote, nes visi pataisymai / pataisymai yra unikalūs.

Taip pat kyla problema, kad kiekvienas kūrėjas siunčia pleistrus, o tai yra didžiulė problema „Subversion“, kuri sumažinama „Git“, „hg“ ir „bzr“, naudojant unikalią identifikaciją. Kai kas nors sujungė savo pakeitimus (ty „Made a merge“) ir išsiuntė juos visiems kitiems komandos nariams, kad galėtumėte juos vartoti, paspaudę centrinę saugyklą arba siunčiant pataisas, tada jiems nereikia nerimauti dėl susijungimo, nes jis jau įvyko Martinas Fowleris vadina tokiu būdu, kaip dirbti be diskriminacijos .

Kadangi struktūra skiriasi nuo „Subversion“, ji naudoja DAG, todėl lengviau ir lengviau padaryti filialus ir sujungti, ne tik sistemai, bet ir naudotojui.

539
18 марта '10 в 21:03 2010-03-18 21:03 atsakė „ Spoike “ kovo 18 d. 10 val. 2010-03-18 21:03

Istoriškai „Subversion“ sugebėjo atlikti tiesioginį dviejų krypčių sujungimą, nes nesaugojo jokios informacijos apie susijungimą. Tai apima pakeitimų rinkinį ir jų pritaikymą medžiui. Net ir sujungimo informacija, tai vis dar dažniausiai naudojama sujungimo strategija.

Pagal nutylėjimą „Git“ naudoja trijų krypčių sujungimo algoritmą, kuris apima bendrų protėvių, sujungtų galvomis, suradimą ir naudojimąsi žiniomis, esančiomis abiejose susijungimo pusėse. Tai leidžia „Git“ būti protingesniam, kad būtų išvengta konfliktų.

border=0

Git taip pat turi sudėtingą pervadinti paieškos kodą, kuris taip pat padeda. Ji neišsaugo pakeitimų rinkinio arba nesaugo jokios stebėjimo informacijos - ji tiesiog išsaugo kiekvienos įvykio failų būseną ir naudoja heuristiką, kad galėtų ieškoti pervardų ir kodų judėjimų, kai reikia (saugykla diske yra sudėtingesnė nei tai, tačiau sąsaja yra logiška, tačiau sąsaja yra logiška, bet aptinka stebėjimą).

27
18 марта '10 в 19:59 2010-03-18 19:59 Atsakymą pateikė Andrew Aylett, kovo 18 d., 10 val., 19:59, 2010-03-18 19:59

Paprasčiau tariant, sujungimo įgyvendinimas veikia geriau Git nei SVN . Prieš 1.5, SVN neįrašė sujungimo veiksmo, taigi jis negalėjo atlikti būsimų susijungimų be vartotojo, kuris turėjo pateikti informaciją, kad SVN neįrašė. Su 1,5, jis tapo geresnis, ir iš tiesų, SVN saugojimo modelis yra šiek tiek labiau pajėgus nei Git DAG. Tačiau SVN informaciją apie susijungimą išlaikė gana paini forma, kuri leidžia susijungimams užtrukti daugiau laiko nei Git - vykdymo metu stebėjau koeficientus 300.

Be to, SVN teigia, kad ji seka pervardytus pavadinimus, kad padėtų sujungti perkeltus failus. Tiesą sakant, ji vis dar juos saugo kaip kopiją ir atskirą ištrinimo veiksmą, o sujungimo algoritmas vis dar suklupia juos pakeitimo / pervadinimo situacijose, ty, kai failas pakeičiamas į vieną šaką ir pervadintas į kitą, ir šie filialai turi būti sujungti. Tokios situacijos ir toliau sukels klaidingus sujungimo konfliktus, o jei pervadinsite katalogus, tai netgi nulemia tylų pakeitimų praradimą. (Tuomet SVN žmonės rodo, kad pokyčiai vis dar yra istorijoje, tačiau tai labai nepadeda, kai jie nėra susijungimo, kur jie turėtų atsirasti.

Kita vertus, Gitas net neskaito pavadinimų, bet parodo juos po faktų (per susijungimą) ir daro tai gana stebuklingai.

Taip pat kyla problemų SVN sujungimo rodinyje; 1.5 / 1.6, galite susieti iš kamieno į filialą taip dažnai, kaip jums patinka, automatiškai, bet jūs turėjote pranešti apie susijungimą kitu būdu (- --reintegrate ) ir palikti šaką netinkamoje būsenoje. Daug vėliau jie sužinojo, kad taip nėra, ir kad a) --reintegrate galima apskaičiuoti automatiškai, ir b) galimi pakartotiniai susijungimai abiem kryptimis.

Bet galų gale (kurią IMHO parodo, kad jie nesupranta, ką jie daro), aš (gerai, aš) labai atsargiai naudoju SVN bet kokiame nežeidžiančiame šakos scenarijuje ir idealiai bandau pamatyti, ką Git galvoja apie susijungimo rezultatą.

Kiti atsakymuose pateikti dalykai, pvz., Priverstinis pasaulinis SVN filialų matomumas, nėra susiję su pajėgumų sujungimu (bet siekiant palengvinti naudojimą). Be to, „Git išsaugo pakeitimus, o SVN saugyklos (kažkas kita)“ iš esmės nesutampa. „Git“ konceptualiai taupo kiekvieną įvykį kaip atskirą medį (pavyzdžiui, tar failą), o tada naudoja gana heuristinį efektyviam saugojimui. Dviejų įsipareigojimų pokyčių skaičiavimas skiriasi nuo saugyklos įgyvendinimo. Tiesa, „Git“ saugo DAG istoriją daug paprastesnėje formoje, kurią SVN atlieka su mergeinfo. Kiekvienas, kuris nori suprasti pastarąjį, žinos, ką aš turiu galvoje.

Trumpai tariant: „Git“ naudoja daug paprastesnį duomenų modelį nei SVN, todėl jis gali daug investuoti į realaus pasaulio jungimo algoritmus, o ne bandyti susidoroti su pateikimu => praktiškai geriausiai sujungti.

16
21 марта '13 в 20:02 2013-03-21 20:02 Atsakymą davė Andreas Krey , kovo 21 d. 13 val. 20:02 2013-03-21 20:02

Aš perskaičiau priimtą atsakymą. Tai tiesiog neteisinga.

SVN sintezė gali būti skausmas ir gali būti sudėtinga. Tačiau ignoruokite, kaip jis veikia minutę. Nėra jokios informacijos, kad „ Git“ saugotų arba išvestų, kad SVN neišsaugotų ir neišvestų. Dar svarbiau, kad nėra jokios priežasties, kodėl atskirų (kartais dalinių) versijos valdymo sistemos kopijų saugojimas suteiks jums daugiau naujausios informacijos. Abi struktūros yra visiškai lygiavertės.

Tarkime, kad norite daryti „protingą dalyką“. „Git“ yra „geriau“. Ir jūs pateko į SVN.

Konvertuokite SVN į lygiavertę „Git“ formą, atlikite „Git“ ir patikrinkite rezultatą, galbūt naudodami kelis įsipareigojimus, kai kuriuos papildomus filialus. Jei galite įsivaizduoti automatinį būdą paversti SVN problemą į „Git“ problemą, tada „Git“ neturi esminio pranašumo.

Galų gale, bet kokia versijos kontrolės sistema leis man

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

Be to, susijungimui naudinga (ar kritiška) žinoti

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

„Mercurial“ , „Git“ ir „Subversion“ (dabar iš pradžių, naudojant „svnmerge.py“) gali pateikti visas tris informacijos dalis. Norėdami parodyti kažką iš esmės geriau su DVC, nurodykite ketvirtąją informacijos, esančios „Git / Mercurial / DVC“, dalį, kuri nėra SVN / centralizuotame VC.

Nesakau, kad jie nėra geriausi įrankiai!

11
03 марта '11 в 16:35 2011-03-03 16:35 atsakymą pateikė Peter 03 kovo 11 d. 16:35 2011-03-03 16:35

Vienas dalykas, kuris nebuvo paminėtas kituose atsakymuose ir kuris iš tikrųjų yra didelis DVCS privalumas, yra tas, kad prieš atlikdami pakeitimus galite atlikti vietinius veiksmus. SVN, kai turėjau tam tikrus pokyčius, norėjau užsiregistruoti, ir kažkas jau padarė tą patį filialą, tuo tarpu tai reiškė, kad turėjau atlikti svn update kol galėčiau ją užbaigti. Tai reiškia, kad mano pakeitimai ir pakeitimai iš kito asmens dabar yra tarpusavyje sumaišyti, ir nėra jokio būdo nutraukti susijungimą (pvz., Naudojant git reset arba hg update -C ), nes grąžinti nereikia jokių įsipareigojimų. Jei susiliejimas yra netinkamas, tai reiškia, kad negalite toliau dirbti su savo funkcija tol, kol neatsirasite sujungimo rezultato.

Bet tada, galbūt, tai yra tik pranašumas žmonėms, kurie yra pernelyg kvaili naudoti atskirus filialus (jei teisingai prisimenu, mes turėjome tik vieną filialą, kuris buvo naudojamas kuriant SVN).

9
23 марта '12 в 10:36 2012-03-23 10:36 atsakymą daniel kullmann pateikė kovo 23 d. 12 val. 10:36 2012-03-23 ​​10:36

SVN įrašų failai keičiasi ir „Git“ įrašai keičiasi. . Pakankamai protinga sekti kodo bloką, kuris buvo reorganizuotas iš vienos klasės / bylos į kitą. Jie naudoja du visiškai skirtingus šaltinius.

Aš vis dar naudoju SVN, bet labai džiaugiuosi, kad naudoju Git.

Geras skaitymas, jei turite laiko: Kodėl aš pasirinkau Gitą

8
18 марта '10 в 19:37 2010-03-18 19:37 Atsakymas duotas panaudotas2d. kovo 18, 10, 19:37, 2010-03-18 19:37

Tiesiog perskaitykite Joel dienoraščio straipsnį (deja, jo paskutinis). Tai pasakytina apie „Mercurial“, tačiau iš tikrųjų kalbama apie paskirstytų VC sistemų, pvz., „Git“, privalumus.

Išskirtoje versijos valdymo sistemoje platinama dalis tikrai nėra įdomiausia dalis. Įdomu tai, kad šios sistemos yra vertinamos atsižvelgiant į pokyčius ne pagal versijas.

Skaitykite straipsnį čia .

6
18 марта '10 в 20:09 2010-03-18 20:09 atsakymą pateikė rubayeet kovo 18, 10, 20:09 2010-03-18 20:09

Kiti klausimai apie žymas „ arba užduoti klausimą