Git: Nástroj na snadné zálohování, změny a revize

10. února 2015

V dnešním článku předvedu, jak vám Git může pomoci vyvarovat se všelijakých chyb — a pokud k nim už došlo – jak se z nich rychle zotavit.

Na 10. ledna 2010 nikdy nezapomenu: byl to den, kdy jsme přišli o kompletní historii projektu. Jako systém pro správu verzí jsme používali Subversion, který udržoval historii projektu v centrálním repozitáři na serveru. Tento server jsme pravidelně zálohovali — přinejmenším jsme si mysleli, že tak činíme. Server zkolaboval a následné zálohování se nezdařilo. Nepřišli jsme úplně o celý projekt, ale všechny jeho historické verze byly fuč.

Krátce poté, co ten server zkolaboval, jsme přešli na Git. Já osobně jsem vždycky správu verzí považoval za týrání; všechno bylo příliš složité a natolik pro mne neužitečné, že jsem neviděl, v čem má spočívat její hodnota. Přesto jsem ji používal, z povinnosti. Jakmile jsme však strávili něco času s novým systémem, začal jsem chápat, jak hodně může být Git prospěšný. Od té doby mi už v mnoha situacích zachránil krk.

Zálohu představuje každý člen týmu

Protože je Git distribuovaný systém správy verzí, každý člen týmu, který naklonoval projekt (neboli udělal “checkout”, pokud přicházíte ze Subversion), má automaticky na svém disku zálohu. Tato záloha obsahuje nejnovější verzi projektu, a také jeho kompletní historii.

To znamená, že pokud se zhroutí lokální stroj vývojáře, nebo dokonce centrální server (a z nějakého důvodu nebude fungovat zálohování), zotavíme se z takové situace během několika minut: abychom získali plně funkční náhradu, nepotřebujeme nic víc, než lokální repozitář z disku některého člena týmu.

Větvení odděluje vše, co má být oddělené

Když mi moji odborně zdatnější kolegové říkali, jak “cool” je v Gitu větvení (branching), nezalknul jsem se hned samým štěstím. Zaprvé, musel jsem připustit, že jsem plně nechápal, jaké přednosti vlastně větvení přináší. A za druhé, protože jsem přišel ze Subversion, velice jasně jsem si pamatoval, jak složitá a náchylná k chybám to byla procedura. Protože jsem měl několik nemilých vzpomínek, bál jsem se pracovat s větvemi a snažil jsem se jim vyhýbat, jakmile to jen trochu šlo.

Trvalo mi dost dlouho, než jsem pochopil, že větvení a slučování (branching a merging) fungují v Gitu zcela jinak než ve většině ostatních systémů — zejména pokud jde o snadnost jejich využívání! Takže, pokud je vám znám koncept větví z nějakého jiného systému správy verzí (jako je Subversion), doporučuji, abyste své předchozí vědomosti odhodili v dál a začali s čistým stolem. Především musíte pochopit, proč jsou větve tak důležité. Tím začneme.

Proč jsou větve nutné

Když si vzpomenu na časy, kdy jsem nepoužíval větve, tak jakmile jsem začal pracovat na nějaké nové schopnosti, dostal jsem se do pěkné bryndy. V podstatě jsem mohl volit jeden ze dvou stejně špatných průběhů pracovních operací, neboli workflow:

(a) Už jsem věděl, že mezi dobré zvyky při správě verzí patří vytvářet krátké seznamy několika málo změn jednotlivých souborů (tzv. commity, neboli revize). Pokud bych však tohle dělal, když jsem právě vyvíjel nějakou novou schopnost, každá taková revize by promíchávala mou teprve napůl hotovou schopnost s hlavní kódovou základnou, dokud bych se svou schopností nebyl zcela hotov. Pro ostatní členy týmu by nebylo příliš příjemné, kdyby moje nedodělaná schopnost zanášela do projektu chyby.

(b) Abych se vyvaroval toho, že se mé dílčí výsledky prací budou promíchávat s jinými tématy (mých kolegů nebo mými), musel bych na té schopnosti pracovat ve svém odděleném prostoru. Musel bych si vytvořit kopii složky projektu, se kterou bych mohl pracovat sám v klidu — a dal bych potvrdit schopnost, na které jsem pracoval, teprve tehdy, až bude zcela hotová. Když bych ale dal potvrdit své změny až na samém konci prací, vyprodukoval bych jedinou, gigantickou, přecpanou revizi, která by obsahovala úplně všechny změny. Až bychom se na takovou revizi podívali někdy později, ani mí týmoví spolupracovníci, ani já bychom už přesně nepochopili, co se v ní děje.

Poznenáhlu jsem začal chápat, že se budu muset důvěrně seznámit s větvemi, chci-li se zlepšit v kódování.

Pracujeme v kontextu

Každý projekt má několik kontextů, v nichž se konají různé práce; každá schopnost, oprava chyby, experiment, nebo alternativa produktu jsou v zásadě samy o sobě kontext. Lze to chápat tak, že to je jejich vlastní “téma” jasně oddělené od ostatních témat.

Pokud pomocí větvení jednotlivá témata od sebe jasně neoddělíte, nevyhnutelně tím zvýšíte riziko vzniku všelijakých potíží. Když se do jednoho kontextu směšují různá témata:

  • je obtížnější udržet si o všem přehled — a pokud máte témat hodně, je to téměř nemožné;
  • je obtížnější stornovat něco, o čem se prokázalo, že obsahuje chybu, protože už se to mezitím promíchalo se spoustou jiných věcí;
  • nevybízíte lidi, aby experimentovali a zkoušeli různé věci, protože by jim nastaly těžké časy, až by měli dostat z repozitáře pryč experimentální kód poté, co se už smíchal se stabilním kódem.

Větve mi dodaly sebedůvěru, která už mě neopustila. V případě, že je něco špatně, vždy mohu sáhnout do minulosti, stornovat změny, začít nanovo, nebo přepnout kontexty.

Jak na základní větvení?

Větvení v Gitu zahrnuje jen hrst příkazů. Podívejme se na základní průběh prací, když začínáte.

Chcete-li vytvořit novou větev založenou na aktuálním stavu, stačí, když si vyberete vhodný název a na příkazovém řádku spustíte jediný příkaz. Budeme předpokládat, že chceme začít pracovat na nové verzi kontaktního formuláře, proto vytvoříme novou větev s názvem dejme tomu “contact-form”:

$ git branch contact-form

Když vydáte příkaz git branch, aniž byste specifikovali název, vypíšou se všechny větve, které aktuálně máte (indikátor “-v” poskytuje trochu víc informací, než obvykle):

$ git branch -v

git-branch-v

Asi jste si všimli malé hvězdičky vlevo od větve s názvem “master.” Znamená, že to je momentálně aktivní větev. Takže dřív, než můžeme začít pracovat na kontaktním formuláři, musíme ho učinit aktivním kontextem:

$ git checkout contact-form

Git nyní učinil z této větve aktuální pracovní kontext. (V žargonu Gitu se mu říká “HEAD branch”). Všechny změny a revize, které uděláme odteď, budou mít vliv jen na tento jediný kontext — ostatní kontexty zůstanou netknuté. Pokud bychom potřebovali přepnout kontext na jinou větev, prostě znovu vydáme příkaz git checkout.

V případě, že chceme integrovat změny z jedné větve do jiné, můžeme je „sloučit“ (“merge”) do aktuálního pracovního kontextu. Představte si, že už nějakou dobu pracujete na schopnosti kontaktního formuláře (“contact-form”) a nyní chcete tyto změny integrovat do větve “master”. Stačí se přepnout zpět do této větve a zavolat git merge:

$ git checkout master

$ git merge contact-form

Jak se pracuje s větvemi

Vřele doporučuji, abyste ve své každodenní práci hojně využívali větve. Větve jsou jedním z klíčových konceptů, okolo nichž byl Git vybudován. Vytvářejí se nesmírně levně a snadno, a jednoduše se spravují — navíc existuje spousta zdrojů, pokud se o nich chcete dozvědět víc.

Stornování změn (undo)

Jako programátor vím už dlouhá léta, že k chybám dochází bez ohledu na to, jak jsou lidé zkušení a zdatní. Nemůžete se jich vyvarovat, můžete však mít po ruce nástroje, které pomáhají se z nich zotavit.

Jednou z nejskvělejších schopností Gitu je, že můžete stornovat téměř cokoliv. Právě to mi dodalo sebedůvěru zkoušet všelijaké věci bez obav — protože, alespoň doposud, jsem nezažil, že by něco fakticky zkolabovalo tak, že by se z toho nešlo zotavit.

Oprava poslední revize

I když sestrojujete revize velmi pečlivě, stává se, že zapomenete přidat nějakou změnu, nebo v nějaké zprávě uděláte překlep. Indikátor –amend příkazu git commit Gitu umožňuje změnit úplně poslední (nejnovější) revizi a taková oprava se vykoná velmi jednoduše. Pokud jste například zapomněli přidat nějakou změnu a zároveň v předmětu revize udělali překlep, snadno to napravíte takto:

$ git add nejake/zmenene/soubory

$ git commit –amend -m „Zpráva, tentokrát bez překlepů“

Jen na jedinou věc byste měli dávat pozor: nikdy takto neopravujte revizi, která už byla předaná do vzdáleného repozitáře. Když budete dodržovat toto pravidlo, bude pro vás volba “amend” skvělým malým pomocníkem pro opravu poslední revize.

(Pokud potřebujete další informace k volbě amend, vynikajícího průvodce napsal Nick Quaranto.)

Stornování lokálních změn

Změnám, které nebyly potvrzeny, se říká “lokální”. Všechny modifikace, které jsou momentálně přítomné ve vašem pracovním adresáři, jsou “lokální” nepotvrzené změny.

Odstranit tyto změny má smysl tehdy, když vaše aktuální práce je … hm… horší, než ta, kterou jste vykonali předtím. S Gitem můžete snadno stornovat lokání změny a začít znovu s poslední potvrzenou verzí projektu.

Pokud potřebujete obnovit jen jediný soubor, jde to udělat příkazem git checkout:

$ git checkout — soubor/kterysema/obnovit

Nezaměňujte toto použití příkazu checkout s přepínáním větví (viz výše). Pokud uvedete dvě pomlčky a za nimi (pozor, oddělit mezerou!) cestu k souboru, odstraníte tím nepotvrzené změny v daném souboru.

Může ale také nastat nešťastný to den, kdy budete chtít odstranit všechny své lokální změny a obnovit celý projekt:

$ git reset –hard HEAD

Tím nahradíte všechny soubory, které máte ve svém pracovním adresáři, nejnovější potvrzenou revizí. Podobně jako při užití příkazu checkout výše, odstraní se lokální změny.

Dělejte takovéto operace opatrně: lokální změny ještě nebyly promítnuté do repozitáře a jakmile je odstraníte, nemáte je jak dostat zpět!

Stornování revizí (potvrzených změn)

Stornování změn se samozřejmě neomezuje jen na lokální změny. Můžete také stornovat jisté revize, bude-li to nutné — pokud jste jimi například zavlekli nějakou chybu.

Revizi můžete v zásadě stornovat dvěma hlavními příkazy:

(a) git reset

 git-reset

 

Příkaz git reset je opravdový návrat v čase do minulosti. Řeknete Gitu, ke které verzi se chcete vrátit, a on obnoví přesně tento stav — stornuje všechny změny, které se staly po tomto časovém okamžiku. Stačí dodat hash ID revize, ke které se chcete vrátit:

$ git reset –hard 2be18d9

Volba –hard je nejsnazší a nejčistší přístup, definitivně ale také vymaže všechny lokální změny, které možná stále ještě máte ve svém pracovním adresáři. Než proto vydáte takovýto příkaz, přesvědčte se, že už nemáte žádné lokální změny, po nichž vaše srdce touží.

(b) git revert

git-revert

Příkaz git revert se používá v jiném scénáři. Představte si, že už jste potvrdili něco, o čem jste ale později zjistili, že to tak mít nechcete — ale všechny revize, které přišly poté, jsou rozumné a rádi byste je zachovali. V takovém případě nemůžete použít příkaz git reset, protože by stornoval také všechny pozdější revize!

Účinky jedné konkrétní revize stornujete příkazem revert. Ten však, na rozdíl od příkazu git reset, žádné revize neodstraňuje. Místo toho vytvoří novou revizi; do ní se zanesou změny opačné ke změnám provedeným v té už potvrzené revizi. Pokud jste například odstranili konkrétní řádek kódu, revert vytvoří novou revizi, která znovu zavede přesně stejný řádek.

Příkazu dodáte hash ID potvrzené revize, jejíž účinky chcete stornovat:

$ git revert 2be18d9

Hledání chyb ve změnách

Když dojde na hledání chyb, musím přiznat, že jsem promrhal hodně času tápáním ve tmě. Často jsem věděl, že to někdy před pár dny fungovalo — neměl jsem ale ani ponětí, kde přesně něco šlo šejdrem. Jakmile jsem se ale dozvěděl, že existuje git bisect, mohl jsem dost tento proces urychlit. Příkazem bisect Git poskytuje nástroj pomáhající najít revizi, která do projektu zavlekla nějakou chybu.

Představte si následující situaci: víme, že aktuální verze (označená jako “2.0”) nefunguje. Víme ale také, že o pár revizí dříve (ve verzi “1.9”), bylo ještě všechno v pořádku. Problém musel vzniknout někde mezi nimi.

 git-works-broken

 

To jsou postačující informace, abychom mohli příkazem git bisect zahájit hon na chybu:

$ git bisect start

$ git bisect bad

$ git bisect good v1.9

Poté, co jsme proces nastartovali, řekli jsme Gitu, že aktuální revize obsahuje chybu, a proto je „špatná“ (“bad”). Pak jsme také Git informovali, která z předchozích revizí je rozhodně funkční (jako parametr do příkazu git bisect good).

Git pak obnoví projekt uprostřed mezi známou dobrou a špatnou revizí:

git-middleTuto verzi teď otestujeme (například tím, že spustíme unit testy, sestavíme aplikaci, rozmístíme ji na testovací systém, atd.), abychom zjistili, zda funguje — nebo zda už obsahuje chybu. Jakmile víme, na čem jsme, opět Gitu řekneme, jak to je — buď s git bisect bad, nebo s git bisect good.

Předpokládejme, že jsme mu řekli, že i tato revize je „špatná“ (“bad”). To v podstatě znamená, že chyba musela být zavlečena ještě dřív — a Git opět zúží rozsah revizí připadajících v úvahu:

git-also-broken

Takto zjistíme velmi rychle, kde přesně se vloudila chyba. Jakmile se to dozvíte, je třeba zavolat git bisect reset, abyste hon na chybu odtroubili a obnovili projekt do původního stavu.

Shrnutí

Musím se přiznat, že mé prvotní setkání s Gitem nebyla láska na první pohled. Zpočátku se zdálo, že to dopadne stejně, jako všechny mé předchozí zkušenosti se správou verzí: únavné a neužitečné. Časem se však postupy staly intuitivními a nabytá odvaha a důvěra mě už neopustily.

Konec konců, chybičky se tu a tam vloudí, bez ohledu, kolik zkušeností máme, nebo jak úporně jsme se snažili, abychom se jich vyvarovali. Profíka od začátečníka odlišuje jeho připravenost: má pohotově k dispozici systém, kterému může důvěřovat, pokud se vyskytnou nějaké potíže. Pomáhá mu mít stále nad vším nadhled, zejména ve složitých projektech. Nu a nakonec pomáhá stát se ještě lepším profesionálem.


 

O autorovi

Tobias Günther

Tobias Günther je autor zdarma dostupné online knihy Learn Version Control with Git – A step-by-step guide for the complete beginner. (Naučte se správu verzí s Git – průvodce ve stylu krok za krokem pro úplného začátečníka.) Je také členem týmu stojícím za Tower, populárním klientem Git pro Mac. Tobiase najdete na Twitteru pod @gntr.

Original article: Git the safety net for your projects

  • Translation: RNDr. Jan Pokorný
  • Language and expert collaboration: Marek Machač

Language of translation: Czech (for readers from Czech and Slovak republics). Translated with the permission ofAlistapart.com. Other translations.

 

Mohlo by vás také zajímat

Nejnovější

1 komentář

  1. Jan33

    Úno 10, 2015 v 16:23

    Zajímavé jak mnoho lidí neumělo větve v Subversion používat. Feature branching jsem využíval daleko pred tím než Git vzniknul, ku oboustranné spokojenosti. Přechod ke Gitu neplánuji, přesto díky za článek i když hodně subjektivně zabarveny.

    Odpovědět

Napsat komentář: Jan33 Zrušit odpověď na komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *