CVS - III

4-dílný seriál o SCM systému CVS, který má za cíl popsat základní principy práce s tímto systémem. Práce ve vícečlenném týmu, verzování, větve, značky, export projektu a jeho verzí.

6.12.2010 00:00 | Miloslav Ponkrác | přečteno 6078×

Práce ve vícečlenném týmu

Pokud pracujete na projektu, v podstatě to normálně probíhá tak, že provedete v nějakém svém adresáři příkaz checkout, kterým si nahrajete aktuální verzi projektu na svůj disk do nějakého pracovního adresáře. To v podstatě udělají všichni, kteří se na projektu podílejí. Mezitím každý z nich pomocí příkazu commit svojí práci nahrává zpět do systému CVS. Pokud Vás pracuje na projektu více, potřebujete se občas přesvědčit, co se na projektu změnilo, zatímco pracujete. Pokud se chcete pouze přesvědčit, jedno z řešení je použít příkaz status, který porovná soubory ve vašem pracovním adresáři s nejnovější verzí uloženou v systému CVS:

cvs status

Pokud si příkaz vyzkoušíte, program mezi spoustou jiných informací vypíše ke každému souboru File: plus stav vaší pracovní verze. Tento stav je jeden z následujících:

Takto to vypadá jednoduše, problémem ale je, že příkaz status je trochu "ukecanější", takže najít tam výše uvedené informace není až tak jednoduché, nebo pohodlné. Téměř ideální řešení nabízí unixová utilita grep, která dokáže vyřešit problém velice elegantně a odfiltrovat nepotřebný text. Ve Windows standardně neexistuje prostředek, který by byl schopen odfiltrovat nežádoucí informace. Doporučuji si proto někde opatřit verzi utility grep pro Windows, pokud používáte tento systém. Bývá buď součástí překladačů firmy Borland, a nebo lze využít GNU verzi, či verzi dodávanou s freewarovým C/C++ překladačem CygWin pro Windows. Pokud se po této utilitě nechcete pídit, napište mi na moji e-mailovou adresu, a já vám tuto utilitku pošlu ve verzi pro Windows.

S utilitou grep dostanete velmi přehledný výpis použitím:

cvs status | grep File

Později popíšu ještě jedno řešení, jak zjistit stav pracovního adresáře, a to ke konci popisu příkazu update. Toto druhé řešení používám já při své práci, a dávám mu přednost před příkazem status.

Napsal jsem tedy, jak zjistit, zda vaše pracovní kopie sedí s tím, co je nahráno v CVS. Pokud zjistíte, že potřebujete dohrát novější verze, slouží k tomu příkaz update:

cvs update jmeno_souboru

Příkaz update dohraje ze systému CVS novější verzi souboru, pokud jí mezitím někdo z pracovního týmu nahrál příkazem commit do systému CVS. Jméno souboru v příkazu update je možné vynechat, pak se nahrají všechny novější verze souborů v systému CVS do vašeho pracovního adresáře.

Tak se nabízí i trochu drsnější postup, a to vykašlat se na zjišťování stavu pomocí příkazu status, a rovnou natvrdo natáhnout změny z CVS do pracovního adresáře. Protože tvůrcům systému CVS bylo jasné, že existují i takové lidské vlastnosti, jako je lenost, podpořili i tento postup. Proto příkaz update garantuje, že nezničí žádnou vaši práci. Jak přesně příkaz update postupuje v jednotlivých případech při možných konfliktech, a jak je řeší, aby neztratil ani ten nejmenší kousek vaší práce na projektu, či práce dalších lidí v týmu, si ukážeme za chvilku.

Pokud použijete příkaz update, systém CVS vypisuje pro každý soubor jednu řádku, a to zhruba tak, že vypíše nějaké písmeno, a pak po mezeře jméno souboru. Vypadá to například takto:

U soubor.txt
? soubor.bak
A readme.txt

Co tedy znamená první písmeno na každém řádku ve výpisu souboru? Tímto nás CVS informuje o tom, co vlastně provedl, nebo by se mělo provést. Význam tohoto písmene je možné najít v tomto seznamu:

Jak je vidět, příkaz update je celkem bezproblémový, pokud se před jménem souboru neobjeví písmeno C, případně M, které značí konflikt. Znamená to prostě, že více lidí mění stejný soubor. V takovém případě příkaz update konfliktní soubor ve vašem pracovním adresáře zazálohuje. Abych byl trochu konkrétnější, předpokládejme, že konfiktní soubor se jmenuje pokus.c. Vy ho ve svém pracovním adresáři máte ve verzi 1.4. Mezitím někdo jiný nahrál do CVS další verzi, kterou CVS automaticky označil jako 1.5. Vy jste použil příkaz update, který zjistil konflikt. Proto vaši verzi 1.4 přejmenuje na .#pokus.c.1.4, a do souboru pokus.c nahraje jakousi sloučenou verzi, která obsahuje jak novou verzi z CVS, tak i změny, které jste udělal na souboru vy. Dále mohou nastat dva případy, a to buď jde o variantu M, nebo C.

V případě varianty M systém CVS prostě přidal do verze s CVS řádky, které jsou navíc ve vaší verzi. A je spokojený. Ale mezi námi, vyznat se v tom je někdy nad lidské síly, protože musíte pátrat, třeba příkazem diff po tom, co kde spojil. Abych řekl pravdu, jde prostě o to, že se musíte do souboru podívat, dát to do pořádku, a případně vaší novou verzi nahrát do CVS příkazem commit. To samé je nutné i v případě varianty C, která je ale trochu přehlednější. Ve variantě C je totiž jasně vyznačeno, jaký je rozdíl mezi oběma verzemi. Je potom na vás, aby jste dal soubor do pořádku, a nahrál zpět pomocí příkazu commit do CVS. Pro ilustraci uvádím část souboru pokus.c s vyznačenými rozdíly mezi vaší verzí a verzí uloženou v CVS:

fprintf(stderr, "No code generated.\n");
<<<<<<< pokus.c
exit(nerr == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
=======
exit(!!nerr);
>>>>>>> 1.5

Z výpisu je patrné, kterou část jste měl vy ve své původní verzi pokus.c, a která část je nahraná ve verzi 1.5 ze systému CVS. Vy potom vymažete ty řádky, které tam nepatří, nahrajete do CVS použitím příkazu commit, a je to.

Dlužno ovšem říci, že byste se pokud možno měli vyhnout této konfliktní situaci, kdy dva lidé editují stejný soubor. A nebo ji alespoň eliminovat na minimum.

Slíbil jsem také zhruba uprostřed této kapitoly, že ukáži jiný způsob, jak zjistit stav pracovního adresáře, a nepoužít příkaz status. Princip je velice jednoduchý, program cvs umožňuje přidat prakticky ke každému příkazu volbu -n, která vyzkouší příkaz naslepo. Je to takové divadlo, program cvs se tváří, že běží, vypisuje vše, co má, ale ve skutečnosti cvs nic nemění, žádnou akci se soubory nikde neprovádí. A co takhle si vyzkoušet příkaz update naslepo? To je ono, protože tím nám bude zároveň vypsáno, jaký je stav souborů v pracovním adresáři. Použijeme také volbu -q, která trochu krotí cvs ve výpisech, takže dostaneme skutečně jenom to potřebné:

cvs -n -q update

Aby to nebylo tak jednoduché, jak je vidět ze zápisu, volby -n, a -q se musí ptát před příkaz! Tedy v našem případě před slovo update. Příčina je jednoduchá, tyto volby totiž můžete použít pro každý příkaz, a proto se píší před příkaz. A volby, které slouží jenom pro konkrétní příkaz se píší za příkaz.


Číslování verzí, nastavení čísla verze

Pokud jste pokročili až sem, už toho pro vlastní práci znáte poměrně mnoho. Proto se naučíme některá kouzla, která vám umožní nastavit číslo verze.

Pokud již se systémem CVS již nějakou dobu děláte, všimli jste si, že CVS automaticky čísluje verze. Začíná na 1.1, po první změně v nějakém souboru označí soubor jako verzi 1.2, po další jako 1.3, atd. CVS prostě pořád zvyšuje poslední číslici ve verzi. CVS také umožňuje nastavit číslo verze. Pokud tedy nastavíte, že soubor má verzi 3.5, potom po změně ji CVS zvýší automaticky na 3.6, po další změně na 3.7, a tak dále. Je také možné nastavit číslo verze třeba na 2.3.0.5, jak je to obvyklé třeba ve Windows. A CVS potom dodržuje stejnou logiku, po každé změně zvýší poslední číslo za poslední tečkou. Všechny ostatní číslice nemění. Takže v tomto případě se dočkáme po změnách verze 2.3.0.6, a tak dále. Pokud chcete změnit i číslice předtím, musíte to udělat ručně.

Číslo verze se dá nastavit pomocí příkazu commit, a to pokud zároveň použijeme volbu -r, za kterou po mezeře přidáme číslo verze. Takže následující příkaz nastaví všechny soubory v projektu na verzi 2.0:

cvs commit -r 2.0

Po této akci označí všechny soubory v projektu na verzi 2.0, a CVS bude dále zvyšovat při každé změně poslední číslo. Je samozřejmé, že se vám číslování začne trochu "rozcházet", protože v projektu to obvykle vypadá tak, že některé soubory změníte jednou, některé vícekrát. Soubor, který jste změnili jednou pak bude mít verzi 2.1, po další změně 2.2, a tak dále. Ale CVS vám mění pouze poslední číslici, vy víte, že se všechno týká 2. verze.

Je samozřejmě možné nastavit číslo verze jenom u jednoho souboru, a to tak, že jméno souboru uvedete na konci příkazu commit při nastavování čísla verze:

cvs commit -r 3.0 jmeno_souboru

Je jasné, že pokud budete často přečíslovávat verzi, můžete si v projektu vyrobit i velice slušný zmatek. Proto vám CVS nedovolí nastavit všechno, co si namanete. Především vám nedovolí snížit verzi. Pokud se například pokusíte nastavit číslo verze u nějakého souboru například na 1.5, když samotný soubor je v CVS uložen jako verze 1.10, systém CVS vám to nepovolí. Prostě se vám to nepovede. Je tedy jasné, že verze s vyšším číslem je vždy novější. Nemůže to být jinak, protože CVS vám dovolí pouze zvyšovat číslo verze směrem nahoru, ale nikdy ne směrem dolů.

Snad jenom poznámku, tímto způsobem je možné nastavit jenom verzi se dvěma číslicemi, pokud nemáte založenou tzv. větev. Proto zatím používejte jenom čísla verzí se dvěma číslicemi, jako je např. 1.5.

Důležitá poznámka: Při změně čísla verze počítejte s tím, že budete donuceni znovu založit pracovní adresář. Proveďte tedy nejdříve commit všech změn, potom commit na nové verze souboru. Hned poté přejmenujte, nebo jinak zazálohujte váš dosavadní pracovní adresář, a znovu vytvořte novou verzi pracovního adresáře pomocí checkout. A začněte pracovat v novém pracovním adresáři. Pokud toto neuděláte, budete mít nejspíše problémy při další práci s CVS.


Větve - práce na několika verzích současně

Při práci na projektu se obvykle postupuje tak, že se založí projekt. Tím začne vývoj první verze. Než bude k dispozici funkční projekt v první verzi, tak mezitím pracovníci uloží do CVS řadu meziverzí. Poté je oficiálně ohlášena první verze. Mezitím začne vývoj na další verzi. Dále se může stát, že z první verze vznikne několik větví. Například častým případem je, že z hotové první verze se začne vyvíjet druhá verze, a zároveň se ještě první verze opravuje, aby se vychytaly poslední drobné chyby. Někdy třeba z první verze vznikne několik produktů. Takto vzniká potřeba spravovat více souběžných verzí. Proto nabízí CVS prostředek nazývaný větve (v manuálu CVS nazývaná jako branch).

Větev představuje jakousi novou odnož projektu. Pro ilustraci jaké verze mohou při použití větve vznikat, uvádím takový malý náčrtek:

                        větev 1.3.2.2.3 ->   +--|1.3.2.2.3.1|--|1.3.2.2.3.2|---- atd.
                                            /
           větev 1.3.2 ->   +--|1.3.2.1|--|1.3.2.2|--|1.3.2.3|--|1.3.2.4|---- atd.
                           /
                          /
    ----|1.1|--|1.2|--|1.3|--|1.4|--|1.5|--|1.6|---- atd.   <- zde je hlavní větev
                               \
                                \
               větev 1.4.4 ->   +--|1.4.4.1|--|1.4.4.2|--|1.4.4.3|---- atd. 


Na náčrtku je celkem jasné, jak vznikají jednotlivé větve. Prostě si kdykoli řeknete, že začnete novou větev, a můžete na ní pracovat. Kdykoli v budoucnu je potom možné větev ukončit, případně spojit s jinou větví a spojit tak dohromady třeba výsledky práce více týmů. Pro projektové manažery, a pro lepší představu všech bude lepší, když si větve představíte jako jakési subprojekty - dílčí podprojekty většího projektu.

Větev můžeme v základě založit dvěma způsoby, buď tak, že za novou větev prohlásíme přesně to, co teď máme v pracovním adresáři:

cvs tag -b jmeno_vetve

Při tomto způsobu vlastně odstartuje větev, a jako první verze souborů v této větvi budou uloženy verze, které právě máme v pracovním adresáři. Příkaz vyžaduje, abychom větev pojmenovali nějakým jménem.

Druhým způsobem, jak odstartovat novou větev je vytvořit jí jako kopii již nějaké verze souborů uložených v CVS. Tento způsob nevyžaduje, abychom byli v pracovním adresáři projektu, a proto vyžaduje i jméno projektu:

cvs rtag -b -r jmeno_znacky jmeno_vetve jmeno_projektu

Takže, aby to bylo jasné, někde v projektu musíme mít verzi, kterou jsme si označili nějakým jménem. Potom následuje jméno větve, prostě si novu větev nějak pojmenujeme. A nakonec přidáme jméno projektu, ve kterém teď vytváříme novou větev. Nutno říci, že tato druhá verze příkazu už je trochu větší sousto, něž první způsob vytváření větve, a asi si na něj troufnete, až budete mít CVS trochu zažité.

Jak jste asi pochopili, každá větev má své jméno. Dokonce i hlavní větev má své jméno, které jste zadali při založení nového projektu příkazem import:

cvs import  jmeno_noveho_projektu  jmeno_hlavni_vetve  jmeno_prvni_verze

Podstatné je, že toto jméno větve budete potřebovat při práci. Dá se také říci, že jméno větve je vlastně jméno subprojektu, na kterém pracujete.

Takže dál už je to jednoduché. Pokud chci pracovat na větvi (tedy subprojektu), vytáhnu si pracovní verzi:

cvs checkout -r jmeno_vetve jmeno_projektu

Podobně pracuje i příkaz export.

Pokud jsem v pracovním adresáři, mohu si  uprgradovat  svojí verzi na jinou větev pomocí příkazu:

cvs update -r jmeno_vetve

Pokud provedete příkaz commit, systém CVS automaticky správně rozezná, na které větvi děláte, a nahraje vaše změny správně, takže stačí obyčejné cvs commit.


Značky - příkaz tag

Teď se trochu rozepíšu o značkách (v originální mluvě manuálů k CVS se nazývají tagy). O co jde? Jak vyplyvá z předchozího textu, systém CVS si automaticky čísluje verze tím, že zvyšuje automaticky poslední číslici při každé změně. Zároveň vy si můžete u libovolného souboru změnit číslo verze, takže se vám může stát, že nejnovější verze souborů mají nejrůznější čísla verzí. Například projekt může mít pět souborů s tím, že mají následující čísla verzí: 1.1, 2.3, 2.4, 2.5, 3.2. Chcete si pro budoucí účely označkovat právě tuto současnou verzi. Můžete to udělat všelijak, třeba si můžete zapsat datum a čas, a poté si vytáhnout verzi přesně s tímto datumem a časem. (Jak vytáhnout starší verzi bude napsáno později.) Jenomže to nepracuje vždy. Ačkoli jsem se o tom zatím podrobněji nerozepisoval, je možné vyvíjet souběžně několik verzí ve stejném čase.

Zkrátka a dobře, nebudu chodit kolem horké kaše, můžete si současnou verzi označkovat, neboli jí nazvat nějakým jménem. K tomu slouží příkaz tag. Například následující příkaz si označkuje pod jménem znacka_1 současnou verzi projektu:

cvs tag znacka_1

Poměrně užitečná je volba -l, která umožňuje označkovat všechny soubory zaregistrované v adresáři, ale nebude označkovávat soubory v podadresářích:

cvs tag -l znacka_1

Nutno ještě podotknout, že volba -l může být použita pro mnoho jiných příkazů, kde má stejnou funkci. Například nechcete-li nahrát do CVS změny celého projektu, ale jenom souborů v aktuálním adresáři, můžete použít:

cvs commit -l

Ještě užitečnější je, že si můžete vybrat, který soubor budete označkovávat:

cvs tag znacka_1 jmeno_souboru

Můžete takto postupně označit několik souborů v projektu.

Takže již víte, že můžete označkovávat verze. Tyto značky se objeví prakticky všude. Pokud si například necháte vypsat logovací výpis pomocí příkazu log, zjistíte, že se v tomto výpisu jména značek objevují. Je jasné, že značky můžete používat jak často chcete, a můžete si vymyslet klidně stovky různých pojmenovaných značek. Jména značek k určitému souboru zjistíte snadno příkazem status:

cvs status -v jmeno_souboru

Tento příkaz vypíše mimo jiných údajů i řádek s názvem Existing Tags:, pod kterým jsou seřazeny všechny značky, které patří k zadanému souboru:
   Existing Tags:
         znacka_1                (revision: 2.0)
         importovana_verze       (revision: 1.1.1.1)
         ponny                   (branch: 1.1.1)

Samotný příklad konce výpisu tedy ukazuje o značkách mnoho. Okomentuji tedy tento výpis. V prvním řádku je psáno, že existuje značka s názvem znacka_1, a že takto byla označkována verze 2.0. Další řádky jsou ale mnohem zajímavější. Abych vám usnadli pochopení, napíšu, že jsem vypsal soubor z projektu ph, který byl předtím založen pomocí následujcího příkazu import:

cvs import -m "zalozeni projektu" ph ponny importovana_verze

A teď tedy přesně vidíte, co znamenají všechna povinná slova u příkazu import. V podstatě jsem založil projekt s názvem ph, a o založení jsem učinil komentář "zalozeni projektu". Za názvem projektu ph následuje jméno větve ponny. A posledním slovem je název značky, v našem případě má název importovana_verze. Je tedy vidět, že vás CVS již při zakládání projektu donutí vymyslet si jméno značky, které použije pro označkování prvních verzí souborů. To mimo jiné znamená, že můžete kdykoli přesně zjistit, se kterými soubory jste založili projekt.

Poměrně velký počet příkazů programu cvs vám dovoluje použít volbu -r, za kterou po mezeře následuje jméno značky. Tím dostáváte mnoho pomůcek pro práci s projektem. Předem ale musím upozornit, že musíte vědět co děláte. To je potřeba pořádně zdůraznit!


Získání starších verzí souborů z projektu

V některých případech se chcete vrátit ke starší verzi projektu, ať už z jakéhokoli důvodu. A nebo jí prostě chcete mít pro zákazníka, který si nazaplatil nejnovější verzi.

Je například možné vytáhnout soubory z dříve označkované verze:

cvs checkout -r jmeno_znacky jmeno_projektu

Tento příkaz vám vytvoří adresář s názvem ph, a uloží do něj soubory z projektu ph přesně ve verzi, kterou jste si označili značkou se jménem znacka_1. Znovu říkám, buďte opatrní, protože pracujete nejspíše na starší verzi! Používejte toto opatrně, zvláště, chcete-li potom změny nahrávat do CVS příkazem commit! Pokud se vám takto podaří omylem nahrát starší verze souborů, budete muset podniknout určité kroky na uvedení projektu do původního stavu.

Asi častější případ bude potřeba prostě získat soubory samotné, nikoli v pracovní verzi pro potřeby vývoje, ale prostě jenom samotné soubory. Potom se hodí příkaz export, který se používá stejně jako příkaz checkout, ale na rozdíl od něho příkaz export nevytváří pracovní verzi, ale jenom adresář se všemi soubory patřící do projektu. Například získat nejnovější verze souborů projektu lze takto:

cvs export jmeno_projektu

Automaticky se nabízí, jak vytáhnout označkovanou verzi projektu:

cvs export -r jmeno_znacky jmeno_projektu

Tip: Protože při založení projektu příkazem import udáváte i jméno značky, které je povinné. Takže možná, aniž jste to tušili, jste si automaticky označkovali verzi souborů při založení projektu. Pokud jste například založili projekt třeba takto:

cvs import -m "zalozeni projektu" prvniprojekt poc-tym poc-verze

Potom jste automaticky označkovali všechny soubory, se kterými jste založili projekt značkou se jménem poc-verze. Potom si kdykoli můžete vytáhnout přesně stejné soubory příkazem:

cvs export -r poc-verze prvniprojekt

Je samozřejmě také možné vytáhnout i verze podle data, třeba takto:

cvs export -D "01/01/2000 00:00" jmeno_projektu

Tento příkaz vytáhne verzi souborů, které byly v CVS 1. ledna 2000 o půlnoci, aby jste mohli zákazníkovi dokázat, že tehdejší verze nemohla způsobit problém Y2K. Datum se zadává v pořadí měsíc, den, rok.

Licence: Tento dokument lze volně šířit pro nekomerční účely, bude-li zachováno jméno autora a copyright. Pro komerční účely pouze s písemným svolením autora.

Online verze článku: http://www.linuxsoft.cz/article.php?id_article=1739