FK~

Moje odkazy

Ostatní odkazy

Close Windows
Nenajdete mě na Facebooku ani Twitteru
Rozpad EU
Jsem členem FSF
There Is No Cloud …just other people's computers.
Sane software manifesto / Manifest příčetného softwaru

Distribuované verzovací systémy: Mercurial – úvod

vydáno: 24. 11. 2011 21:58, aktualizováno: 10. 8. 2020 10:42

Předchozí díl tohoto seriálu byl věnovaný teorii distribuovaných verzovacích systémů. Dnes se konečně podíváme prakticky na jeden z nich – Mercurial (zkráceně Hg). Kromě úplných základů (přidávání souborů pod správu verzí, mazání, přejmenovávání…) si také ukážeme, jak se vracet ke starším verzím a jak si verze pro větší přehlednost označovat pomocí štítků.

Instalace a nastavení

Instalace programu je v GNU/Linuxových distribucích jednoduchá, použijeme balíčkovací systém a Mercurial si nainstalujeme např. jedním z těchto příkazů:

aptitude install mercurial    # Debian/Ubuntu
yum install mercurial         # Fedora/RedHat

Příkaz pro práci s Mercurialem se jmenuje hgmělo by nám fungovat doplňování a napovídání tabulátorem. Např. napíšeme hg com a stiskneme tabulátor a doplní se na hg commit.

Globální nastavení Mercurialu se nachází v souboru /etc/mercurial/hgrc . Zde nic měnit nemusíme. Jediné, co bychom si měli nastavit, je jméno v našem uživatelském konfiguračním souboru v ~/.hgrc – sem zadáme něco jako:

[ui]
username = Jméno Příjmení <jmeno@example.com>

Při commitování změn se pak toto použije jako jméno autora.

Kromě globálního a uživatelského konfiguračního souboru existuje i nastavení pro jednotlivá úložiště – nachází se uvnitř nich v souboru .hg/hgrc.

Začínáme s verzováním

Dejme tomu, že píšeme článek, diplomku, nějaký svůj program/skript… přestože to nepotřebujeme nikde vystavovat nebo s někým sdílet, může se nám hodit verzovací systém. Možná se vám už taky někdy stalo, že jste něco přepsali a pak jste si vzpomněli, že formulace, kterou jste tam měli ještě před pár dny byla lepší. Nebo třeba jen chcete sledovat, jak vám jde práce hezky od ruky – vidět kolik textu kdy přibylo. Místo toho, abychom si každý týden/den kopírovali vytvořené soubory do nějak pojmenovaného adresáře je začneme verzovat – je to snadné, takže se nemusíme bát použít verzování i v banálních případech – není to pověstný kanón na vrabce – je to naopak jednodušší a můžeme u toho udělat méně chyb, než kdybychom soubory zálohovali/verzovali ručně kopírováním.

Vytvoření úložiště a přidání souborů pod správu verzí

Otevřeme si terminál a vstoupíme do složky se soubory, které chceme verzovat, a zadáme příkaz:

$ hg init

Příkaz nic nevypíše (to je v pořádku) a vytvoří nové mercurialové úložiště – vznikne adresář .hg. Úložiště je zatím prázdné. Následujícím příkazem zjistíme aktuální stav:

$ hg status 
? index.xhtml
? soubor.txt
? video.ogv

Otazník před názvem souborů znamená, že tyto soubory nejsou zatím verzované. Soubory si tedy přidáme pod správu mercurialu:

$ hg addremove 
adding index.xhtml
adding soubor.txt
adding video.ogv
$ hg status 
A index.xhtml
A soubor.txt
A video.ogv

U souborů je teď příznak A a to znamená, že jsou čerstvě přidané a když zadáme hg commit uložíme je trvale do mercurialu jako novou verzi.

Jenže teď si uvědomíme, že video verzovat nechceme – naštěstí se nic nestalo a můžeme se vrátit zpět:

$ hg revert --all
forgetting index.xhtml
forgetting soubor.txt
forgetting video.ogv
$ hg status 
? index.xhtml
? soubor.txt
? video.ogv

A přidáme soubory raději jednotlivě – jen ty, které skutečně chceme verzovat:

$ hg add soubor.txt index.xhtml 
$ hg status 
A index.xhtml
A soubor.txt
? video.ogv

Ignorování nežádoucích souborů

Abychom na to nemuseli pokaždé myslet, vytvoříme si seznam souborů, které se nemají verzovat:

$ echo "video.ogv" >> .hgignore
$ hg add .hgignore
$ hg status 
A .hgignore
A index.xhtml
A soubor.txt

Nežádoucí soubory nám už nepřekáží ve výpisu hg status a nestane se nám, že bychom je omylem postoupili do úložiště (to bychom museli udělat záměrně: hg add video.ogv, ale hromadné přidání/odebrání pomocí hg addremove je bude ignorovat). Samotný soubor .hgignore je rovněž verzovaný – to je dobré jednak proto, že seznam se může v čase měnit (např. soubory, které jsme chtěli ignorovat v prvních verzích teď chceme verzovat a naopak), a jednak proto, že tento seznam se bude šířit společně s ostatními soubory – když uděláme push nebo pull, seznam ignorovaných souborů bude všude stejný.

Soubor .hgignore může obsahovat jak regulární výrazy, tak obyčejné vzory jako v shellu – např. *~. Vždy jeden vzor na jednom řádku. Obvykle budeme ignorovat celé adresáře jako dist/*, build/* a záložní soubory.

Postoupení první verze do úložiště

Ještě jednou si pro jistotu vypíšeme hg status a když jsme s výsledkem spokojeni, můžeme vytvořit svoji první verzi:

$ hg commit

Otevře se nám textový editor, do něj napíšeme popis změn, které daná verze přináší – první řádka by měla být výstižná a stručná (zobrazuje se v krátkých výpisech historie) a na dalších řádcích se můžeme rozepsat klidně trochu víc. Hodně záleží co a pro koho verzujeme – když si verzujeme jen tak pro sebe, asi tam nebudeme psát moc dlouhé romány, ale když pracujeme v týmu, je dobré napsat srozumitelný popis změn (ne každý chce číst zdrojový kód a dělat si diff), nějaké vzkazy pro člověka, který bude dělat revizi naší práce, a pokud používáme systém na správu požadavků/chyb, měli bychom zadat i čísla úkolů, které jsme zde řešili (obvykle se před číslo dává # a systémy jako Trac z toho pak umí udělat odkaz na daný úkol). Platí zde podobné zásady jako pro komentáře v kódu: neměli bychom psát až tak, co jsme udělali (např. „do metody xyz() jsem přidal a = b + 10;“ – to je vidět z diffu, tudíž zbytečná informace), ale proč jsme to udělali a jaký to má smysl (např. „oprava chyby: zdvojování teček v protokolu SMTP“ a ideálně i její #číslo).

Zprávu nemusíme psát do editoru a můžeme ji uvést na příkazové řádce:

$ hg commit -m "Popis změn…"

Také můžeme postoupit jen konkrétní soubory, přestože jich bylo přidáno či změněno více:

hg commit index.xhtml soubor.txt

A když si to úplně na poslední chvíli rozmyslíme, stačí ukončit editor a žádnou zprávu nepsat – Mercurial to pochopí:

abort: empty commit message

a žádnou verzi nevytvoří.

Verzování /etc

Kromě zdrojových kódů nebo různých vlastních souborů můžeme tímto způsobem verzovat i konfiguraci našeho počítače v /etc:

# cd /etc
# hg init
# chown root:root .hg/
# chmod 700 .hg/
# hg addremove
# hg commit -m "prvotní verze konfigurace"

Na chmodchown nesmíme zapomenout – jinak by se mohlo stát, že se k souborům, které může normálně číst jen superuživatel, dostane přes verzovací systém i někdo jiný.

Verze pak můžeme vytvářet při každé ruční změně konfiguračních souborů, případně si tento proces automatizujeme programem etckeeper (verzuje /etc v pravidelných intervalech a při aktualizacích balíčků).

Klonování úložiště

Zatím jsme se pohybovali pouze mezi pracovní kopií (normální soubory v adresáři, které upravujeme) a místním úložištěm (uvnitř adresáře .hg, spravované Mercurialem, zde nic ručně neupravujeme, maximálně konfigurační soubor .hg/hgrc) Pro připomenutí jeden obrázek z minula:

Decentralizované verzovací systémy – typické uspořádání

Jelikož se obvykle verzují důležité a pracně vytvořené věci, bylo by škoda o ně přijít třeba při havárii pevného disku. Proto je potřeba zálohovat – s verzovacím systémem to jde velice snadno.

Přepneme se do adresáře na externím nebo třeba síťovém disku a naklonujeme sem svoje dosavadní úložiště:

$ cd /mnt/externí-disk/
$ hg clone ~/diplomka/
destination directory: diplomka
updating to branch default
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd diplomka

Máme teď kompletní kopii náší práce včetně všech předchozích verzí. Vazba na původní úložiště (odkud jsme klonovali) zůstává zachována – najdeme ji v konfiguračním souboru:

$ cat .hg/hgrc 
[paths]
default = /home/franta/diplomka

Díky tomu nám budou fungovat příkazy hg pushhg pull, pomocí kterých můžeme „synchronizovat“ obě úložiště. Můžeme tedy pracovat střídavě v obou úložištích a třeba i na více počítačích současně (nosit si externí disk s sebou). A zároveň máme ve věcech pořádek – vždy víme, která verze je aktuální, a nestane se nám, že bychom si omylem soubory přepsali nějakou špatnou verzí – i kdyby se nám to stalo, vždy se můžeme vrátit zpět a chybu napravit.

Před stažením změn z druhého úložiště (hg pull) se můžeme podívat, jaké změny čekají na druhé straně:

$ hg incoming 
comparing with /home/franta/diplomka
searching for changes
changeset:   1:87df11cb506b
tag:         tip
user:        František Kučera <franta-hg@example.com>
date:        Thu Nov 24 15:18:08 2011 +0100
summary:     Druhá verze

Vidíme, že provedením hg pull si stáhneme jednu sadu změn, víme kdo ji vytvořil, kdy a vidíme její popis. Pustíme tedy hg pull a následně hg update (tím aktualizujeme pracovní kopii na poslední verzi).

Obdobným způsobem fungují příkazy hg pushhg outgoing, akorát v opačném směru.

Čí je tohle práce?

Příkazem hg log si vypíšeme stručnou historii celého úložiště:

$ hg log
changeset:   1:87df11cb506b
tag:         tip
user:        František Kučera <franta-hg@example.com>
date:        Thu Nov 24 15:18:08 2011 +0100
summary:     Druhá verze

changeset:   0:01c1e32a34f5
user:        František Kučera <franta-hg@example.com>
date:        Thu Nov 24 14:13:04 2011 +0100
summary:     Moje první verze

A příkazem hg annotate index.xhtml zjistíme, z jaké verze pocházejí jednotlivé řádky daného souboru – každý řádek začíná krátkým číslem verze (v našem případě by to byly 0 a 1, protože máme zatím dvě verze a čísluje se od nuly). Díky tomu víme, jak je který řádek starý a který autor ho má na svědomí. Užitečné je to zvlášť při vývoji softwaru – když nějaké části kódu nerozumíme, můžeme jít přímo za konkrétním kolegou a zeptat se, co tím myslel. Ostatně v Subversionu se tato funkce jmenuje svn blame (obvinit).

Pro podrobnější výpis použijeme hg annotate s volbami --changeset--user.

Webový pohled na úložiště a Kompare

Práce na příkazové řádce je sice fajn, ale některé věci jsou přeci jen lépe vidět v GUI. K pokročilejším externím nástrojům se dostaneme v příštím díle – zatím si vystačíme se samotným Mercurialem. Ten disponuje vestavěným HTTP serverem, který zpřístupní dané úložiště.

$ cat ~/bin/hg-náhled
#!/bin/bash
konqueror http://localhost:8000/?style=gitweb &
hg serve -p 8000

Pomocí tohoto skriptu si spustíme www prohlížeč a HTTP server a podíváme se, co je v daném úložišti. Přehledně vidíme všechny verze, můžeme si rozkliknout jednotlivé změny a rozdíly v souborech. K dispozici je i vyhledávání, stromový pohled a další funkce.

Tím můžeme zkoumat změny, které byly již postoupené do úložiště. Pro porovnání pracovní kopie s úložištěm se nám bude hodit následující skript:

$ cat ~/bin/hg-porovnej
#!/bin/bash
hg diff | kompare -o -

Kompare – grafický nástroj pro porovnávání souborů

Tento příkaz je dobré spustit před hg commit a podívat se, co přesně se chystáme odeslat – vidíme nové řádky (modře), změněné (červeně) a smazané (zeleně).

Přesouvání souborů

Při přesouvání souborů je lepší použít příkazů Mercurialu – místo:

$ mv soubor.txt Soubor.TXT
$ hg status 
! soubor.txt
? Soubor.TXT

použijeme raději:

$ hg mv soubor.txt Soubor.TXT
$ hg status 
A Soubor.TXT
R soubor.txt

a soubor se nejen přesune/přejmenuje, ale zároveň se i správně připraví na postoupení do úložiště: původní soubor je ve stavu R (ke smazání) a nový ve stavu A (přidání).

Mercuril si navíc pamatuje, že Soubor.TXT vznikl ze soubor.txt (Soubor.TXT má nastaveno parent 1 soubor.txt@87df11cb506b), takže je historie zachována a lze sledovat změny (např. pomocí hg annotate) zpětně i do dob, kdy se soubor ještě jmenoval jinak. Což by nemuselo fungovat, kdybychom jeden soubor jen smazali a druhý vytvořili bez vědomí Mercurialu (pak by to byly dva úplně jiné nezávislé soubory).

Naštěstí Mercurial je celkem inteligentní, takže se dokáže vypořádat i s tím, když soubor přejmenujeme bez něj a pak dáme hg addremove:

$ hg addremove 
removing soubor.txt
adding Soubor.TXT
recording removal of soubor.txt as rename to Soubor.TXT (100% similar)

Nicméně jistější je ten první způsob (hg mv), protože pak můžeme soubor v jednom kroku přejmenovat i měnit jeho obsah a přesto se neztratí informace, že jde o tentýž soubor.

Mazání souborů

Pokud soubor smažeme obyčejně pomocí rm, Mercurial si všimne, že chybí:

$ rm Soubor.TXT
$ hg status 
! Soubor.TXT

Ale při následujícím hg commit se toto smazání nijak neprojeví. Je to stejné, jako když vytvoříme nový soubor a nepřidáme ho pod správu verzí pomocí hg add. Aby se smazání uložilo v rámci dané verze, musíme dát hg remove (místo obyčejného smazání, nebo dodatečně po něm):

$ hg rm Soubor.TXT
$ hg status 
R Soubor.TXT

Při postoupení změn se tento soubor v úložišti smaže (staré verze tam samozřejmě zůstanou a můžeme se k nim kdykoli vrátit).

Návrat do minulosti

Jedním z důvodů, proč verzovací systémy používáme, je cestování v čase – můžeme se vracet ke starým verzím souborů.

Pomocí hg up -r ? se vrátíme k vybrané verzi (její číslo zjistíme z hg log):

$ hg up -r 0
2 files updated, 0 files merged, 2 files removed, 0 files unresolved

A pomocí hg up bez parametru aktualizujeme pracovní kopii na poslední verzi, která je v úložišti.

Pro označení verzí můžeme samozřejmě používat i hashe:

$ hg up -r 7f906c7d62cc
1 files updated, 0 files merged, 1 files removed, 0 files unresolved

Následujícím příkazem pak zjistíme, kde v čase se právě nacházíme:

$ hg identify 
7f906c7d62cc

Štítky

Odkazovat se na verze pomocí podivných čísel je dost nepohodlné. Proto existují tzv. štítky, kterými si můžeme jednotlivé verze označit. Dejme tomu, že verze 4:7f906c7d62cc je nějakým způsobem zajímavá (např. program v této verzi jde nejen zkompilovat, ale i spustit), tak si ji pojmenujeme:

hg tag --rev 4 "tohle funguje"

A pak se na ni můžeme odkazovat tímto jménem místo čísla:

hg up "tohle funguje"

Všechny štítky si vypíšeme příkazem:

$ hg tags 
tip                                8:89a449ab3cb0
tohle funguje                      4:7f906c7d62cc
třetí verze                        3:07708ca1e12f

A kromě toho je i přehledně vidíme ve webovém rozhraní.

Závěr

Dnešní úvod do Mercurialu byl pro některé možná příliš podrobný a zdlouhavý, ale článek by měl sloužit i těm, kteří zatím žádný verzovací systém nepoužívali a chtěli by s tím začít. Příště se budeme věnovat více týmové práci (stahování ze vzdálených úložišť i zpřístupnění vlastního úložiště pomocí různých protokolů ostatním) a práci s větvemi. Také si ukážeme některé GUI programy, protože příkazová řádka není všechno.

Odkazy a zdroje:

Témata: [verzovací systémy] [softwarové inženýrství]

Komentáře čtenářů

Tento článek zatím nikdo nekomentoval

Přidat komentář

reagujete na jiný komentář (zrušit)
jméno nebo přezdívka
název příspěvku
webová stránka, blog
e-mailová adresa
nápověda: možnosti formátování
ochrana proti spamu a špatným trollům

Náhled komentáře