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 6510×
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.
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.
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.
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!
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.