Proč jsem přešel z Mercurialu na Git

Delší dobu jsem jako hlavní verzovací systém pro své projekty vcelku spokojeně používal Mercurial. Před týdnem jsme se ale po dlouhém rozmýšlení rozhodl přejít na Git, který jsem do té doby považoval (a stále považuju) v mnohých směrech za horší. V tomto článku bych rád popsal, jak se vyvíjely mé úvahy a co mě přimělo ke změně. U čtenářů budu přitom předpokládat porozumění základním principům distribuovaných verzovacích systémů.

Mercurial a Git

Mercurial a Git jsou oba distribuované verzovací systémy založené na myšlence orientovaného acyklického grafu změn a adresaci těchto změn pomocí hashů. Oba vznikly přibližně ve stejné době (jaro 2005), ze stejného důvodu (potřeba vyřešit verzování linuxového kernelu) a celkově u nich najdeme na úrovni koncepce i ovládání víc společných vlastností než rozdílů.

Mercurial je nicméně o něco jednodušší, menší, konzistentnější, elegantnější, a rozšiřitelnější. Je na něm celkově vidět, že nevznikl tolik chaotickým vývojem jako Git, ale že jeho tvůrci při přidávání jednotlivých vlastností mysleli i na celek. Na povrch se to projevuje velice přehledným a logickým ovládáním (myšleno z příkazové řádky) a srozumitelnou nápovědou – ani jedním z toho Git rozhodně nedisponuje. (Pokud vás zajímá detailnější srovnání obou systémů, zabruste k Davidovi Grudlovi nebo se podívejte na video od Scotta Chacona.)

Z těchto důvodů jsem se rozhodl používat Mercurial jako primární verzovací systém pro své projekty. To mi vydrželo do té doby, než jsem začal letos v lednu pracovat na SUSE Studiu (které tvoří tým asi 18 lidí ve velmi rychlém tempu vývoje a které je spravováno Gitem) a pár týdnů na to vydal PEG.js. Na prvním projektu jsem poznal, co je to opravdu distribuovaný vývoj, a na druhém jsem si pořádně uvědomil, že volba verzovacího systému není jen volbou technickou a osobní, ale i sociální. Z obou stránek se Mercurial ukázal jako horší systém.

Shrnuto v bodech, mé důvody k přechodu na Git byly následující:

Pojďme si tyto důvody podrobněji rozebrat.

Důvod první: Lepší podpora rozvětveného vývoje v Gitu

Dobrá podpora rozvětveného vývoje je jedním z nejdůležitějších aspektů verzovacího systému. Dost možná tím vůbec nejdůležitějším. Jakýmsi prubířským kamenem této funkcionality se pro mě stal následující příklad.

Ultimátní VCS use case

Mějme tým několika vývojářů pracujících na společném projektu. Jeden z nich dostane za úkol vyvinout větší funkci (tj. rozprostírající se přes několik commitů). Kód si chce začít psát u sebe jako sadu změn oproti hlavní vývojové větvi, která nebude zatím nikde zveřejněna. Je možné, že během práce zjistí, že na to jde špatně, a bude potřebovat sadu změn zahodit a začít znovu odjinud. Během práce si bude také často potřebovat odskočit zpět k hlavní vývojové větví, např. kvůli napsání nějaké opravy. V neposlední řadě bude občas potřebovat aktualizovat svou sadu změn, aby odpovídala aktuálnímu kódu v hlavní vývojové větvi.

Až vývojář svou funkci dostane do rozumného stavu, bude chtít vytvořenou sadu změn sdílet s ostatními, aby mohli jeho úpravy zrevidovat, okomentovat atd. Výsledkem bude pravděpodobně několik dalších změn. Nakonec bude celá funkce dokončena, začleněna do hlavní vývojové větve a následně nasazena.

Řešení v Mercurialu

Jak si s tímto příkladem poradí Mercurial? Ukazuje se, že je na něj možné jít čtyřmi různými způsoby, z nichž ale ani jeden není ideální.

Větve

Mercurial má vestavěnou podporu větví (branches), se kterou by bylo možné příklad zvládnout, nebýt jedné důležité věci: jakmile je větev jednou vytvořena, nejde ji přejmenovat ani smazat (protože název větve je uložen v commitech). To je v souladu s celkovou filozofií Mercurialu, že co je v repozitáři, to je vytesáno do kamene, ale brání to efektivně používat větve Mercurialu pro menší funkce a věci, u kterých si nejsme jisti, kde nakonec skončí a jestli je úplně nepřepíšeme. V tom případě je totiž nejspíš nebudeme chtít mít v repozitáři na trvalo.

I kdyby permenentnost kódu nevadila ("Tak mám v repozitáři nepoužitý kód, no a co?"), nemožnost mazání a přejmenování větví povede k názvům ve stylu "experimental-feature-try1", "experimental-feature-try2", v čemž se snadno ztratí orientace. Mercurial nám navíc znepříjemňuje práci s repozitářem, ve kterém máme větve, které nechceme sdílet – nefunguje obyčejný hg push a je třeba explicitně říct, kterou větev chceme do cílového repozitáře protlačit. Je to sice drobnost, ale otravná.

Jak je vidět, větve nejsou pro jako řešení našeho příkladu úplně vhodné.

Klon repozitáře

Funkci z příkladu by bylo možné vyvíjet v naklonovaném repozitáři. Tím se vyřeší problémy s experimenty a neměnností repozitáře (pokud chci kód zahodit, smažu klon). Pro sdílení s ostatními stačí klon nahrát na vývojový server.

Problémem se ale stává nutnost přepínání mezi původním repozitářem a klonem. Znamená to např. zavírání otevřeného editoru, v případě webových aplikací restart serveru či dokonce přepisování jeho konfigurace. Tyto problémy lze částečně vyřešit třeba symbolickými odkazy na repozitáře, ale i tak není přepínání mezi více repozitáři příliš pohodlné, zvlášť pokud ho potřebujeme dělat poměrně často. Klonování tedy ideální cesta není.

Bookmarks

Neflexibilitu větví se snaží obejít rozšíření Bookmarks. To definuje koncept záložky, což je jen pojmenování nějakého commitu. Záložky se při změnách automaticky posouvají dopředu, takže fungují podobně jako větve. Jsou ale uloženy mimo repozitář a tudíž nejsou neměnné.

Z uložení záložek mimo repozitář plyne jejich hlavní problém – obtížné sdílení. Není je totiž možné sdílet prostým hg push jako ostatní kód. To způsobí problémy ve chvíli, kdy vývojář bude chtít umožnit ostatním se na kód podívat a případně do něj zasáhnout. Po každé modifikaci bude muset mimo Mercurial zpřístupnit aktualizovaný seznam záložek, což je činnost otravná (jak pro něj, tak pro ostatní) a náchylná k chybám. Záložky se tedy na náš úkol také úplně nehodí.

Mercurial queues

Poslední možností, jak příklad vyřešit, je požít rozšíření Mercurial queues. Změny nebudeme ukládat do repozitáře, ale uložíme si je stranou jako sadu klasických patchů oproti aktuální vývojové větvi. Mercurial queues nám to umožní dělat relativně efektivně a zároveň přimějí Mercurial koukat na uložené patche jako na normální commity. Až budeme chtít změny nasdílet, prostě patche někde vystavíme a při změnách je budeme upravovat či doplníme nové.

S Mercurial queues by šel náš příklad vcelku bez problémů zvládnout. Jedná se ale de facto o další nástroj pro práci se změnami v kódu – se svou vlastní filozofií a samostatnými příkazy. Iluze, že jsou patche normální commity, je jen velmi povrchní a má mnoho děr. Celý systém je v podstatě jeden velký hack okolo toho, že repozitáře v Mercurialu jsou neměnné.

Shrnutí

Jak je vidět, s Mercurialem uvedený příklad sice vyřešíme, nicméně stylem "jde to, ale dře to". Žádný způsob řešení není úplně ideální a elegantní. To je ve výrazném kontrastu s elegancí Mercurialu jako celku.

Při hlubším zamyšlení člověk přijde na to, že za všechny problémy v zásadě může chápání repozitáře jako neměnného – nebýt toho, náš příklad by šel nejspíš vyřešit poměrně snadno. Bohužel toto chápání je základ filozofie Mercurialu a podle mě je to jeho největší slabina na koncepční úrovni. Dá se do značné míry různými způsoby obejít, ale není to ono.

Řešení v Gitu

Na rozdíl od Mercurialu Git náš příklad zvládne levou zadní svými větvemi (branches). Na začátku úkolu si vytvoříme soukromou větev (topic branch), ve které pracujeme. Tu můžeme kdykoliv zahodit a začít znovu, můžeme ji i různě upravovat (přehazovat commity, slučovat je apod.) a měnit bod, ze kterého vychází (git rebase). Až budou změny připraveny ke zveřejnění, není problém je (stále jako větev) nahrát do centrálního repozitáře a dál na nich pracovat. Začlenění zpět do vývojového stromu je také bezproblémové.

Celý proces je tedy oproti Mercurialu naprosto hladký. Jedinou nevýhodou je, že příkazy pro některé operace jsou poněkud kryptické a manuálové stránky k nim naprosto nečitelné. Zde nás ale snadno zachrání buď dobrá knížka nebo Google. Zůstává jen mírná pachuť z páchání magie, které pořádně nerozumíme.

Důvod druhý: Větší rozšířenost Gitu

Podstatná výhoda Gitu proti Mercurialu je množství jím spravovaných projektů a tedy i větší množství uživatelů. Důsledek je, že například u open source projektů je použití Gitu v podstatě očekáváno. Pokud svůj projekt budete spravovat v něčem jiném, ubližujete mu tím, protože jisté množství potenciálních uživatelů či přispěvatelů prostě nebude ochotno se kvůli vašemu projektu učit nový verzovací systém. U Mercurialu tento problém není až tak zásadní, protože je stále relativně dost rozšířený a navíc je Gitu podobný. Nicméně významný faktor to stále je.

U rozšířenějšího systému obecně bývá výhoda i v množství podpůrných nástrojů, snadnějšího řešení problémů (je pravděpodobnější, že s ním nejste první) atd. Zde ale musím říct, že mezi Gitem a Mercurialem nespatřuju významné rozdíly – oba jsou rozšířené dost na to, aby jejich ekosystém fungoval vcelku dobře.

Důvod třetí: GitHub

Důležitým faktorem, který hrál roli při rozšiřování Gitu v posledních dvou letech, je existence GitHubu. Společná kolaborace více lidí na kódu se díky němu stala snadnou záležitostí, což mělo převratné důsledky na množství a rychlost vývoje zejména menších open source projektů (detailní rozbor by byl na samostatný článek). Dá se říct, že na GitHubu má dnes účet a několik projektů skoro každý a existuje okolo něj silná vývojářská komunita.

Mercurial má svůj BitBucket, který je do značné míry (nedokonalou) kopií GitHubu. Klíčová věc – komunita – mu ale chybí. Hezky jsem to mohl pozorovat na svém projektu PEG.js, který byl původně zveřejněn na BitBucketu a cca před týdnem jsem ho přesunul na GitHub. Zatímco na BitBucketu mu trvalo několik týdnů nasbírat 4 followery (lidí, co projekt sledují na úrovni commitů) a jeden fork (kopie repozitáře za účelem modifikací), na GitHubu se totéž podařilo asi za dva dny. A to měl BitBucket výhodu úvodního zveřejnění – přesun na GitHub jsem už jen tiše oznámil v mailing listu. A ne, nebylo to přechodem followerů z BitBucketu an GitHub.

Velikost komunity je klíčová pro jakýkoliv open source projekt, protože znamená větší pravděpodobnost, že se o něj začne někdo zajímat, bude ho testovat či do něj dokonce přispěje kódem. Pokud toto chcete (proč byste nechtěli?), je dnes GitHub jednoznačně nejlepší místem, kam projekt umístit.

Závěr

Výběr verzovacího systému je složitá záležitost. Já jsem svou volbu učinil před víc než rokem a nyní jsem rozhodnutí změnil. Nevnímám to jako chybu v původním úsudku, ale jako posun ve vývoji a přiznání si, že na některých vlastnostech (elegance, konzistence uživatelského rozhraní) záleží zřejmě méně, než bych si přál. Flexibilita Gitu při distribuovaném vývoji některé povrchnější výhody Mercurialu zkrátka trumfne. Navíc je Git rozšířenější a má za sebou silnější komunitu, na čemž záleží nejspíš ještě víc než na technických a uživatelských aspektech.

Dodal bych ještě, že moje kritéria pro rozhodování jsou pochopitelně velmi subjektivní a neúplná. Při zvážení nasazení verzovacího systému např. ve firmě je potřeba přemýšlet šířeji, než jak jsem činil já. Nicméně i tak se domnívám, že moje cesta a její závěry můžou někomu při rozhodování pomoci.

Apr 19, 2010 – 11:00

Comments

che
che

Údaj o sbírání followerů/forků by možná byl směrodatnější, kdyby bylo známo zda ti na githubu za dva dny nasbíraní byli úplně noví příchozí, nebo prostě lide co si projekt za předchozí čtyři týdny našli na BitBucketu a pak jen zaregistrovali změnu.

Jinak coby uživatel gitu za článek děkuji, je dobré vědět že v tom člověk není sám :-)

Vojtěch Kusý

Díky za článek. Mám z Gitu vs Mercurial stejný pocit.

Git je co se týče příkazů (a zvlášť jejich parametrů) nekonzistentní bastl srovnatelný s PHP nebo Bashem. Na druhou stranu je neuvěřitelně flexibilní. K běžnému používání se stačí naučit pár příkazů, pro běžné složitější příkazy si člověk může vytvořit shortcuts / git co, git last apod. (viz zmiňovaná kniha Pro Git).

Ještě bych vypíchnul větší portabilitu Mercurialu. Používání Gitu pod MS Windows ještě není zcela hladké (musí se používat Cygwin nebo Msys shell), v některých případech jsem měl problémy s konverzí konců řádek. GUI klienti také nejsou ještě zcela stabilní. To samé platí i o integraci do Eclipse.

Čím mě ale Git "dostal" je ta správa větví, tento koncept mi také sedí mnohem víc než přístup Mercurialu. // Viz http://nvie.com/git-model - teda s tim rozdílem, že "master" je pro mě dev a "develop" je pro mě stable :-)

Další věc je snadné upravování aktuálního commitu - tzv amend.

To jsou pro mě dost zásadní vlastnosti, kvůli kterým jsem ochoten tu nekonzistenci & ne zcela dokončenou podporu MS Win u Gitu překousnout.

Není čas na Git-Hg Phusion? HGit?

Almad

Celkově souhlasím, respektive jsem si prošel něčím podobným, akoratže se mi prostě pořád líp a pohodlněji pracuje s hg.

Takže jsem skončil na tom, že víceméně osobní projekty (co jsou akorat oss) mám v hg, "skutečné" opensourcy jsou prostě v gitu.

Jinak s tou rozšířeností záleží na komunitě, takoví rubisti jsou jenom na githubu. Nicméně u Pythonu je to třeba trochu jinak, tim že je v hg samostný Python, formuje se spíš komuniat okolo bitbucketu (který je jinak imo objektivně horší než github, což je škoda).

Hackuju okolo toho přes hg-git, ale tak nějak to neni ono.

Co se firmy týče, celkem by mě zajímaly poznatky z praxe. Já zažil jeden přechod svn -> hg a jeden svn -> git s dost podivnými výsledky.

Miloslav Ponkrác

Skvělý článek. Já bych mohl dělat opozici.

Proč jsem skončil s Gitem? S těžkým srdcem, protože Git je opravdu dobrý. Ale je to bastl, který v zásadě nemá stable verzi pro nic jiného, než pro unix.

A protože neprogramuji jen proto Linux, rád bych VCS, který má stable a podporované verze alespoň pro všechny mainstream platformy. A to Git nemá.

Tomáš Linhart
Tomáš Linhart

Super článek. S většinou souhlasím. Jen bych dodal, že Mercurial umí řešit problém, který popisuješ taky elegatně. Řešení je extension local branches - http://mercurial.selenic.com/wiki/LocalbranchExtension Lze si vytvořit lokální branch, mazat je a lehce se mezi nima přepínat. Bohužel jsou jen lokální, což u Gitu není problém, ale zas topic branche asi člověk necommituje do hlavního repozitáře a tam by si vystačil s těma klasickýma co má Mercurial.

David Majda

[1] Nejsem si úplně jistý, jak to myslíš. Pokud jsem dobře koukal, mezi seznamy na BitBucketu a GitHubu nebyl žádný překryv. Projekt ale mohli na GitHubu začít sledovat uživatelé, co o něm věděli už z dřívějška, jen se ho na BitBucketu sledovat nenamáhali (např. proto, že tam neměli účet a nechtěli si ho zakládat).

[2][4] Ano, portabilita může být obecně důležitý faktor rozhodování. Pro mě osobně to faktor nebyl, protože pracuju na Linuxu a tam oba systémy fungují bez problémů. Git navíc na Widnows v zásadě funguje (byť ne tak hezky nativně jako Mercurial).

[3] Variantu "soukromě v Mercurialu a veřejně v Gitu" jsem zvažoval taky (a částečně jsem tak i chvílemi fungoval), ale nakonec jsem se rozhodl, že bude jednodušší používat jen jeden nástroj (pořád jsem se na příkazové řádce pletl).

[5] Toto řešení jsem neznal, díky za doplnění. Úplně elegantní mi ale nepřijde (pokud to dobře chápou, interně se klonuje celý repozitář a není možné tyhle branche snadno sdílet).

che
che

[6] Pokud tam není překryv tak asi o přesun původních lidí nejde, což je možnost kterou jsem měl na mysli -- díky za vysvětlení.

[3] Co do poznatků z praxe -- já jsem zažil a zčásti tlačil jeden přechod svn->git, zhruba ve fázích:

  1. zprovoznění git-svn
  2. propagace gitu, vysvětlování jak funguje
  3. založení centrálního git repository
  4. úprava interních build nástrojů a zobrazovadla verzí, aby byly schopné pracovat i s git repository
  5. usazovací fáze, kdy už část lidí začala vyvíjet featury separovaně v gitu, a po tom review/testování se commitovaly do svn trunku
  6. prohlášení git master větve za autoritativní a jedinou, zamčení svn trunku na read-only
Připadá mi že to vcelku fungovalo.

Andrej Tokarčík
Andrej Tokarčík

Zaujímavý článok.

Výhrady mám jedine k načrtnutému use-casu: podľa mňa je vylíčený prípad (implementácia väčšej funkcie mimo hlavnú vetvu) sťa ideálnym pre využitie štandardných Mercurial vetví. Vieme totiž, že takáto väčšia funkcia je žiadaná, t.j. bude OK vytvorený kód iba prepisovať (resp. re-updatovať na pôvodnú revíziu) a nie zahadzovať.

ale brání to efektivně používat větve Mercurialu pro menší funkce

Samozrejme, na menšie funkcie (opísaný use-case ale spočíva vo väčšej funkcii a nie menšej) je vhodné používať skôr Mercurial bookmarks, t.j. dočasné, súkromné vyčlenenie kódu.

Mimochodom, MQ by sa na vetvenie ani vôbec nemali používať.

Čo sa teda funkčnosti týka, u mňa Mercurial stále vedie. Výhody súvisiace so sociálnymi sieťami a užívateľskou základňou však, žiaľ, nemožno zanedbať.

Relevantným môže byť aj odkaz na článok Jamesa Bennetta na túto tému.

David Majda

Relevantným môže byť aj odkaz na článok Jamesa Bennetta na túto tému.

Děkuji za odkaz, zajímavé čtení.

S filozofií "bookmarky na malé lokální věci a větve na velké" mám dva problémy:

  1. Malá věc se snadno neočekávaně stane velkou. Pak je třeba měnit model za běhu.

  2. I u velké věci se může stát, že bude potřeba kód v nějaké fázi zahodit (prostě zjistíte, že jste se vydali úplně špatnou cestou - třeba že složitá optimalizace nakonec ve výsledku snížila výkon) nebo úplně přepsat. V tom případě nastanou problémy popsané v článku.

Mě se na větvích v Gitu líbí, že je to jeden univerzální, flaxibilní, dobře fungující nástroj. V tomhle je Git oproti Mercurialu elegantnější a lepší. A protože je to klíčová věc, přebilo to u mě nakonec všechny jeho ostatní nedostatky (byť to trvalo rok).

Add Comment

It is not possible to add comments to posts older than one month.