Mercurial – első tapasztalatok egy elosztott verziókezelővel

Már régóta szemezek az elosztott verzió kezelő rendszerekkel. Egyfelől azért, mert úgy látom ez a trend (néhány év múlva az elosztott verzió kezelők fogják átvenni az  SVN helyét, úgy ahogyan annak idején az SVN került az akkoriban elterjedt CVS helyére), másfelől magam is szembesültem már az SVN néhány hátrányával, amiken az elosztott verziókezelő rendszerek felülemelkednek. No de mi is az az elosztott verzió kezelő rendszer?

Feltételezem, hogy az olvasó találkozott már  központi (centralizált) verziókezelő rendszerrel. Ilyen például a hagyományos SVN, vagy a CVS. Központi verziókezelő esetén ugye van egy központi szerver (pl. SVN szerver), a felhasználók pedig innen húzzák le, illetve ide tolják fel a saját változtatásaikat. Minden feltöltést egy letöltésnek kell megelőznie, ami az adott felhasználó gépén összefésüli a szerveren lévő és a lokális változatot. Ha az összefésülés automatikusan megoldható (általában megoldható), akkor azt a rendszer el is végzi, ha nem, akkor kézzel kell összefésülnünk a változatokat, majd az eredményt feltöltjük, és onnantól az lesz az aktuális változat. Az egyes változatokat vissza lehet keresni, egy egy állományt vissza lehet állítani a régi állapotra, és változatonként pontosan nyomon követhetjük, hogy hol mi változott. Nagyon röviden valami ilyesmiről szól egy központi verziókezelő.

Elosztott (decentralizált) verziókezelő esetén más a helyzet. Ott egyetlen központi tároló (repository) helyett minden felhasználónak van egy saját külön tárolója a gépén. A külön tárolónak külön verziókezelése van, tehát nem kell minden egyes változást a központi szerverre tölteni. Itt rögtön látszik is az elosztott verziókezelők egyik nagy előnye az SVN-el szemben. SVN esetén ha valami nagy feladaton dolgozunk, és a feladat megoldása közben menteni szeretnénk egy egy mérföldkövet, azt csak az egyetlen központi tárolóba menthetjük. Így választhatunk, hogy vagy félkész dolgokat mentegetünk a központi tárolóba (ezzel esetleg működésképtelen vagy hibás verziókat hozva létre), vagy mindaddig nem készítünk verziót, amíg el nem készültünk a feladattal (így viszont a feladat ideje alatt elveszítjük a verziókezelésből eredő előnyöket). Mindkét megoldás rossz, de mindenki saját szája íze szerint választhat, hogy melyik a kisebbik. Elosztott verziókezelés esetén nincs ilyen gond, hiszen a saját lokális tárolójába mindenki olyan verziókat hoz létre, amilyet akar (lehetnek ezek között működésképtelen, félkész állapotok is), és csak akkor tölti fel az egészet a központi tárolóba, ha kész van a feladattal (esetleg le is tesztelte, stb.). Így a központi tárolóban mindig egy stabil, használható változat van. Ez már önmagában nagy előny, de mint látni fogjuk, ez csak egyetlen a sok közül. Tehát egy központi tároló helyett itt több tároló van, és mivel nincs is olyan fogalom, hogy “központi” tároló, ezekből a lokális tárolókból tetszőleges hierarchiák kialakíthatóak. Tehát pl. egy projekt 2 nagyobb feladatra osztható, és mindkét feladaton dolgozik 2-2 fejlesztő. Ebben az esetben a két fejlesztőnek van 1-1 saját tárolója, ezekből mindig az adott feladat tárolójába szinkronizálnak, és ha az adott feladat elkészül, akkor tolják ki az egészet a “központi”, stabil tárolóba. De hasonló módon akár az is megoldható, hogy 2 “központi” tárolót tartunk fenn. Az első egy “testing”, a második egy “stabil” változat. Ha elkészül egy feladat, akkor az a “testing” rendszerbe kerül. Itt valaki leteszteli, és ha megfelelőnek találja, kihelyezi a stabil tárolóba. Ez csak néhány példa a teljesség igénye nélkül, de sok más elrendezés is elképzelhető. Például ami nekem nagyon tetszett, hogy nyílt forrású projektek esetén ha a forráskód tárolására SVN-t használnak, akkor két módon lehet beszállni a fejlesztésbe. Az egyik, hogy elérési jogot kérünk a tárolóhoz. Itt ugye az a dolog veszélye, hogy akinek ilyen jogot adunk, abban nagyon meg kell bízni, hisz kontrollálatlanul telepakolhatja a kódot mindenfélével. A másik eset, hogy a felhasználó elvégzi a módosítást, majd generál egy patch-t, amit elküldhet a projekt vezetőjének, aki átnézi azt, és kézzel befésüli az SVN-be. Ez viszont elég kényelmetlen. Elosztott verziókezelő esetén a dolog igen gördülékenyen megy, mivel a felhasználó csinál egy másolatot (klónt) a központi kódbázisról, elvégzi a változtatásokat (itt használhatja a lokális változatának saját verziókezelését), majd ha elkészült, értesíti a projekt gazdáját, hogy húzza át a módosítást a fő kódbázisba. Ez tulajdonképpen olyan mint mikor az ember patch-et küld egy SVN-es projekthez, de sokkal egyszerűbb, és gördülékenyebb.

A legismertebb ilyen elosztott verziókezelő a Git. Ezt a linux kernel fejlesztéséhez hozták létre, de mostanra már sokan mások is használják. Git-ben tárolják pl. az Android forráskódját, a Diaspora-t, az Appcelerator forráskódját, a Facebook is ezt használja a nyílt forrású projektjeihez, és még több ezer projekt, amiket jellemzően a GitHub-on hosztolnak. (A GitHub egy Git alapú code hosting szolgáltatás, olyan mint a Google Code Hosting, vagy a Sourceforge, bár sok szempontból sokkal fejlettebb.) A Git után szorosan második helyen áll a Mercurial. Nem kell szégyenkeznia a Git mellett, hisz olyan projektek használják, mint a Mozilla böngésző, Python programozási nyelv, OpenJDK, Netbeans, stb. Ráadásul a Google Code Hosting-on is használhatjuk az SVN alternatívájaként. Valójában nekem is szimpatikusabb a Mercurial, mint a Git, mivel a Git egy scriptekből és programokból összelapátolt valami, míg a Mercurial tulajdonképpen egy Python program, így ha kell, ebbe jobban bele lehet nyúlni (pl. plugint fejleszteni hozzá), ráadásul az egész valahogy jobban egyben van. Van még néhány elosztott verziókezelő (pl. Bazaar, amit az Ubuntu Linux használ), de mind közül nekem a Mercurial tetszett legjobban, így erről fogok írni.

Akit mélyebben érdekel a Mercurial, a http://hginit.com/ címen találhat egy nagyon jó angol nyelvű összefoglalót, de én is írok róla néhány sort.  Ha ki szeretnénk próbálni ennek a verziókezelő rendszernek a képességeit, legegyszerűbb, ha letöltjük a TortoiseHg klienst. Ez beépül a Windows jobb gombos menüjébe, így a fájlkezelőben könnyen adminisztrálgathatjuk a tárolóinkat. A kísérletezéshez hozzunk létre egy tárolót. Ehhez a TortoiseHg-ban van egy “Create repository here” menüpont. Az első dolog, amit észrevehetünk, hogy maga a tároló egy egyszerű könyvtár néhány speciális fájlal, tehát alapvetően nincs szükség szerverre a működéshez. Ez már önmagában is hasznos lehet. Ha kész a tároló, hozzunk is létre benne néhány fájlt. Eztán ha a tároló könyvtárán jobb gombot nyomunk, feltűnik az ismerős commit parancs. Ezzel az SVN-hez hasonlóan rögzíthetjük a változásokat, és létrehozhatunk egy verziót, ami az SVN-el ellentétben nem egy szerveren, hanem a könyvtárban lévő egyik mappában jön létre. Készítsünk még 1-2 verziót. Van egy Hg Workbench menüpont is, amivel szépen fában látjuk a változatokat, megnézhetjük a különbségeket, stb. Eztán jöhet a trükk, ami az elosztott verziókezelők legnagyobb előnye.  A menüben találunk egy “Clone” parancsot. Ezzel a teljes tárolót lemásolhatjuk még egy példányban, verzió történettel, mindennel együtt. A clone után mér két tárolónk van (két sima könyvtár néhány speciális fájlal és mappával). Most csináljunk néhány verziót az egyik, majd néhány verziót a másik tárolóban. Ez jelképezi a több fejlesztési ágat. A gyakorlatban ez úgy néz ki, hogy minden egyes fejlesztő klónozza magának a tárolót, és abba dolgozik. Szóval csináljunk néhány verziót mindkét tárolóban. Ha ezzel megvagyunk, akkor jön az, hogy a másodlagos (pl. fejlesztési) tárolót fésüljük vissza az elsődleges tárolóba. Ezt két módon tehetjük meg. Vagy a cél tárolóba húzzuk (pull) a változásokat a forrás tárolóból, vagy a forrás tárolóból nyomjuk (push) a cél tárolóba a dolgokat. Mindkét módozatnak van értelme. A push-ra jó példa, amikor mondjuk egy fejlesztő befejezett egy feladatot a saját lokális tárolójában, és ezt betolja a központi fejlesztői tárolóba (kb. az SVN commitnak felel meg). A pull használata pedig például akkor lehet hasznos, ha a stabil szál felelőse áthúzza a változásokat a fejlesztői szálból. Például GitHubon (ez Git alapú, de a mechanizmus ugyanaz) úgy szállhatunk be egy nyílt forrású projekt fejlesztésébe, hogy klónozzuk a projekt tárolóját, megcsináljuk a változtatásokat (ehhez semmilyen interakció nem kell ugye a projekt gazdájával), majd ha megvagyunk, küldünk egy pull request-et (ez kb. egy üzenet, hogy “kérlek, húzd át a változásokat az én tárolómból”) a projekt gazdájának, aki átnézi, hogy mit változtattunk, és ha mindent rendben talál, áthúzza a változásokat a projekt fő tárolójába. Ez nagyon gördülékeny módja a nyílt forrású projekthez való hozzájárulásnak, sokkal kényelmesebb, mint SVN hozzáférést kunyerálni, vagy patch-eket küldeni. A példa kedvéért tehát nyissuk meg az elsődleges tárolónkat a Hg Workbench-ben, és húzzuk át a változásokat a másodlagosból. Ha ez megvan, láthatjuk a Workbench-ben, hogy a másodlagos tároló történettel, mindennel együtt egy új ágként megjelent a mi tárolónk történetében (magyarul látszik, hogy ott ketté vált a fa). Ez már majdnem jó, már csak egyesíteni kell a két ágat. Ehhez van a workbench-ben egy merge művelet. Ez igazából ugyanúgy megy, mint SVN-ben a merge-ölés, ha lehet, automatikusan merge-öl a rendszer, ha nem, akkor kézzel kell ezt megtenni. (Elvileg a Mercurial mindenféle metaadatot gyűjt a merge segítésére, de ezt a részét annyira nem próbáltam.) Ha megvan a Merge, jöhet egy commit, és rögtön egy szálon megy tovább az egész. Tehát ha a fejlesztés végén ránézünk a fára, lépten-nyomon kis elágazásokat és visszacsatolásokat fogunk látni, amik az egyes fejlesztések.

Úgy nagyon dióhéjban ennyi lenne a Mercurial bemutatása. Feltűnhetett, hogy minden műveletet a fájlrendszerben végeztünk, de ahogyan SVN esetén, természetesen itt is megvan a lehetősége annak, hogy egy repository-t egy szerveren tároljunk, amit HTTP-n, HTTPS-en, vagy SSH-n keresztül lehet elérni. A dolgok mechanizmusán ez nem sokat változtat, egyszerűen az ilyen tároló nem a fájlrendszerben van, hanem egy távoli szerveren, de ugyanúgy lehet klónozni, lehúzni (pull) róla a változásokat (ami az SVN update-hez hasonló), vagy felnyomni (push) oda a változásokat (ami az SVN commit-hoz hasonló). Célszerűen csak a fejlesztő lokális tárolóját érdemes a fájlrendszerben tartani, minden olyan tárolót, amit többen használnak (közös fejlesztési ág, stabil ág, stb.), szerveren érdemes tartani.

Remélem ezzel a kis ismertetővel sikerült kicsit kedvet csinálni az elosztott verzió kezelő rendszerek, azon belül is a Mercurial használatához.

10 Responses to “Mercurial – első tapasztalatok egy elosztott verziókezelővel”

  1. Gondolatok (Fazekas László blogja) » HgEclipse – Mercurial az Eclipse-ben

    […] írtam egy rövid bejegyzést a Mercurial elosztott verziókezelő rendszerről. Ott a TortoiseHg-n keresztül mutattam be a […]

    Válasz
  2. mhmxs

    Hali!

    SVN-nél is van lehetőség branchek létrehozására, és akkor nem veszíted el a verziókezelést, illetve a végén a fő ágba vissza tudod olvasztani a nagyobb fejlesztéseket.

    Válasz
    • admin

      Igen, ez mondjuk igaz, de SVN-nél ez sokkal macerásabb. Mondjuk ezt a részét annyira nem próbáltam, de magából a felépítésből eredően gondolom, hogy ott problémásabb ezt kezelni, meg aztán a végén visszafésülni az eredeti ágba, stb. Ezek az elosztott verziókezelők viszont erre vannak kitalálva, itt a működés alapja az, hogy orrba-szájba branch-elve van minden. SVN esetén eleve ugye ott kezdődik, hogy jogosultságot kell adnod az SVN-hez mindenkinek, aki használja, itt viszont a branch egy teljesen külön álló repository. Aztán szerintem ilyen pull-t sem tudsz csinálni, hogy megy a 2 branch párhuzamosan, és az egyikből áthúzod a változásokat a másikba. Tehát képzeld el azt a helyzetet, hogy van egy stabil ág, és egy testing és egy aktív fejlesztési ág (mint mondjuk a debian linuxnál, vagy mozzilánál, vagy bárhol). Ha elkészül egy mérföldkő, az átkerül testing állapotba, és ha már jól kitesztelték, akkor az lesz a következő stabil verzió, és a következő mérföldkő fejlesztései lesznek a testing ág. Előfordulhat viszont, hogy valami hiba átcsúszott a stabil ágba, és ott bugfixeled. Namost ezt vissza kell húzni a testingbe, hogy a következő verzióba is bekerüljön a változás. Ugyanígy a testing repo-ban is előjönnek hibák, amiknek a javítását az aktuális fejlesztési repository-ba kell visszahúzni. Ilyesmit SVN-el szerintem nem tudsz megoldani. Vagy csak problémásan, mindenféle patch-ek generálásával, stb. De ezen kívül van még egy rakás dolog, ami SVN-ben nem vagy csak bonyolultan, elosztott verziókezelővel egyszerűbben megoldható. Én mindenképp ezt látom a fejlődés irányának. Ha más nem, elég azt megfigyelni, hogy a nyílt forrású projektek egyre nagyobb része a GitHub-on van (szerintem az újabb projektek szinte kivétel nélkül, a régebbieknél maradt az SVN, gondolom leginkább megszokából). A Google Code-on is van néhány Mercurial repo, de ott a feature-ök még nagyon elmaradnak a GitHub mellett (pl. pull request támogatás, meg úgy az egésznek akommunikációja), pedig a Mercurial szerintem eggyel kulturáltabb rendszer is,mint a Git. Az én jóslatom, hogy open source projektek esetén főleg a Git, belső használatra (céges repo) pedig a Mercurial fog elterjedni, és néhány éven belül leváltja az SVN-t. De persze majd meglátjuk …

      Válasz
  3. mhmxs

    ja lemaradt, Köszi az írást 🙂

    Válasz
  4. mhmxs

    Teljesen igazad van, és az elosztott verziókezelés sokkal rugalmasabb, én csak felhívtam a figyelmed, hogy svn-be is lehet branchelni, ott is akárhány branchen folyhat a fejlesztés, ráadásul kb akármelyik reviziót mergelheted akármelyik revizióval (kötegelten is) független attól melyik ágban van. Nyilván az itt is fenáll, hogy kell jogosultság branch létrehozására. Ha már elválasztjuk a pull-t meg push-t, akkor már inkább pusholni nem tud, de svn-be megadsz két reviziót aztán összefésüli, és lehet reverse mergelni is.

    Válasz
  5. admin

    @mhmxs

    Igen, köszi, ezt a részét annyira nem ismerem az SVN-nek, de mindenképp rugalmasabbnak és átláthatóbbnak tűnik a Mercurial rendszere. Sőt még egy új dolog is eszembe jutott, amit már régóta szeretnék megoldani. Eddig az SVN repo-im a saját szerveremen voltak, de szeretnék átállni virtuális szerverek használatára, ahol már kicsit paranoiásabb az ember, hogy valaki beleláthat a "szupertitkos" ( 🙂 ) projektjeibe, hiszen egy számodra ismeretlen infrastruktúrán tárolod az adataidat, és nem tudhatod, hogy ez mennyire biztonságos. Tehát tök jó lenne, ha lehetne kódoltan tárolni a repo-t. Mivel Mercurial-nál használhatsz csak helyi repo-kat, ezért felépítheted úgy a rendszert, hogy minden a helyi repo-ban van, és csak biztonsági mentéseket csinálsz a szerverre, ami már mehet kódoltan. Arra kell figyelni, hogy egy repo-nak egy gazdája legyen, tehát egy ember írhassa csak, hiszen a backup-nál már nem tudsz repo-kat merge-ölni, a változásokat meg mindig a repo gazdája húzza be pull-al a saját repository-jába. Így biztonságban tudhatod a szupertitkos kódjaidat, még akkor is, ha feltörnék a szervert. Sőt, mivel csak online backupról beszélünk, elég alá egy sima tárhely szolgáltatás. Ez csak úgy bónuszba eszembe jutott. 🙂

    Válasz
  6. mhmxs

    erre a biztonság dologra hirtelen nem tudok mit mondani, talán csak annyit, hogy svn-el is lehet file:// protokollt használni, szóval nem kell hozzá szerver. Szóval jó a mercurial, de nem a szent grál 😉

    Válasz
  7. admin

    @mhmxs

    Megnéztem, és tényleg, csak kicsit nehezebb megtalálni. Ezt jó tudni. És az is igaz, hogy branch-ekkel végül is lehet csinálni olyasmit, mint a Mercurial különálló repo-i, de azért még mindig azt mondom, hogy a Mercurial ebből a szempontból jobban kézre áll. Szóval a klónozott saját repo-kkal, a default fájlrendszer leképzéssel, stb. jobban adja magát a dolog. És ugye nyílt forrású fejlesztéseknél ott az előny, hogy nem kell hozzáférést adni a repo-hoz, és pull-olni egyszerűbb, mint patch-eket küldeni. De igaz, hogy ha akarod, bele tudsz mindent suvvasztani az SVN modelljébe is, kérdés, hogy mekkora vele a macera. Például ha a bejegyzésben említett többfejlesztős modellt akarod megvalósítani saját verziókkal (a központi repo-ban csak kész módosítások vannak), akkor le kell branch-elned minden fejlesztőnek a repo-t, revision-önként merge-ölni ide-oda. Megoldható, de elég macerásan hangzik. (Mondjuk tényleg igaz, hogy konkrétan ilyet nem próbáltam SVN-el megvalósítani, de az SVN logikájából adódóan macerásabbnak tűnik, mint a clone-pull.) Szóval tényleg nem a szent grál, de tartom magam ahhoz, hogy azért mégis eggyel jobb, mint az SVN. 😉

    Válasz
  8. Gondolatok (Fazekas László blogja) » GitHub, avagy közösségi kódolás

    […] Git egy elosztott verziókezelő rendszer. Ilyenekről már írtam kicsit a Mercurial kapcsán. Röviden annyi a lényeg, hogy más központosított rendszerekhez képest (pl. SVN) itt […]

    Válasz

Hozzászólás írása