Hlavní navigace

Stinné stránky CVS

Michal Kára

Tento článek vznikl jako reakce na seriál o CVS. Já sám tento systém používám a už jsem narazil na několik případů, kdy jsem u něj, ač se zpočátku jevil jako dobrý nástroj, narazil na problémy. Proto jsem se rozhodl s vámi o své zkušenosti podělit.

Jen tak pro pořádek: Rozhodně netvrdím, že CVS je k ničemu. Sám jej úspěšně na mnoha projektech používám. Ale jako všechno má svá omezení. Rovněž nejsem příliš velkým odborníkem na „advanced version control featurky“ jako velké využívání větví, a proto z tohoto hlediska nemohu možnosti CVS příliš hodnotit.

Binární soubory

CVS je dosti nevhodné pro spravování binárních souborů. Ty se do něj, pravda, uložit dají. Pokud se specifikuje typ souboru jako binární (-kb), CVS se souborem jako s binárním zachází, nepokouší se na něj pouštět diff atp. Problém ale leží trochu jinde.

CVS totiž předpokládá, že v případě konfliktu (současná změna souboru více uživateli) jsou tyto změny víceméně bez problémů slučitelné (mergeable). A u zdrojových kódů to také platí, pokud zrovna dotyční lidé neupravují stejný kus kódu. Ve většině případů dokonce CVS změny sloučí samo bez cizí pomoci, konflikt, který musí řešit člověk, nastává poměrně zřídkakdy.

Ovšem u binárních souborů je tomu jinak. Nejenže změny v binárních souborech nejdou (krom speciálních případů) sloučit automaticky, ony často nejdou ani sloučit ručně, respektive jejich sloučení se většinou musí dělat tak, že jeden z uživatelů své změny prosadí do CVS na úkor ostatních, ti pak musejí své změny udělat znovu a postupně je přidávat. To je samozřejmě silně neefektivní.

Tento problém je možno řešit zamykáním souborů. Uživatel si soubor zamkne, a dokud na něm pracuje, drží jej zamčený. Pak commitne změny a soubor odemkne (respektive se soubor odemkne tím commitem).

CVS takovéto zamykání souborů podporuje (cvs edit). Jenže – pouze neexkluzivní. Takže uživatel musí explicitně příkazem cvs editors zkontrolovat, zda soubor někdo jiný nemá uzamčený, a pak teprve jej zamknout a začít na něm pracovat. To však nejen přidělává práci, ale hlavně přesunuje zodpovědnost za uzamčení na nespolehlivý lidský faktor.

Řešení jsou dvě. Buď použít CVSNT, nebo si napsat vlastní rozhraní k CVS, které před editací souboru provede kontrolu samo.

Velké soubory

Dalším neštěstím jsou velké soubory. CVS sice samo o sobě nemá žádný limit na velikost souboru, jenže… Díky tomu, že je CVS postaveno nad RCS, se soubor musí vždy při posílání klientovi (t. j. při operaci checkout nebo update) načíst celý do paměti. Mám takový dojem, že paměťové nároky jsou dokonce rovny (dvoj)násobku velikosti souboru. A to i při checkoutu nejnovější (head) revize, která je v souboru uložena přímo.

Za normálních okolností to příliš nevadí, ale pokud máte v CVS i (statická) data programu, můžete klidně skončit se souborem, který má několik set MB. A to je pak už hodně znát, když ho po aktualizaci začne stahovat několik lidí naráz. Tento problém mě v praxi docela trápil a snažil jsem se jej nějak vyřešit, leč marně. CVS je s RCS silně provázáno a celá architektura je tak propletená, že jsem se o naprogramování nějaké „zkratky“ nakonec nepokusil. S největší pravděpodobností by to totiž znamenalo přepsat nebo znovu napsat celý parsing RCS souboru.

Další nepříjemností, na kterou přijdete při zamykání souborů příkazem cvs edit, je fakt, že cvs při této operaci zazálohuje do adresáře CVS/Base původní obsah souboru. To proto, aby při operaci unedit mohlo soubor případně obnovit bez nutnosti komunikace s CVS serverem. Pokud si ale dáte edit na několik velkých souborů, přijdete o citelný kus místa. (CVSNT má nyní díky mému patchi option, který tuto zálohu zakáže.)

Modifikované/ne­modifikované soubory

Při commitu je nutné zjistit, které soubory uživatel změnil. CVS to dělá tak, že si pamatuje čas poslední změny všech souborů a ty, u kterých se čas liší, považuje za změněné.

Pokud souboru pouze změníte čas, CVS se ho pokusí commitnout. Jestliže server zjistí, že se soubor shoduje s nejnovější (head) revizí, soubor jakoby přijme, ale nezvýší číslo revize. To je velmi inteligentní chování. Bohužel se tak děje až po kontrole na konflikty, takže pokud onen soubor mezitím někdo opravdu změnil, commit (jako celek) neprojde. Musíte dát update, „změny“ sloučit a následovat commitem.

Problém nastává u binárních formátů, kde je slučování obtížné. Tam je řešení takové situace dost pracné a musíte při něm být opatrní.

Řešením by bylo držet si u souboru také jeho checksum (a případně délku) a považovat za změněný pouze soubor, u kterého se liší datum poslední změny a délka nebo checksum. Ale to by chtělo patch do CVS :-)

Symbolické odkazy

Velmi nepříjemnou vlastností CVS je fakt, že se nedokáže vypořádat se symbolickými dokazy. Prostě je ignoruje. Pokud je chcete používat, musíte si do projektu přidat nějaký skript, kterým je po checkoutu vytvoříte.

Přejmenovávání souborů/adresářů

CVS nemá žádnou možnost přejmenování souborů a/nebo adresářů. Pokud chcete přesunout soubor, udělejte to na úrovni filesystému a v CVS soubor se starým názvem smažte a nový přidejte.

Bohužel tím přijdete o historii souboru. Respektive nepřijdete, ale bude obsažena v souboru se starým názvem, který si v případě potřeby můžete vyvolat.

Jinak při přesunu doporučuji soubory zkopírovat. CVS totiž odmítne odstranit existující soubor a vypisovat názvy ručně bez shellové tab-completion je občas otrava. Můžete využít přepínač -f příkazucvs remove, který soubor odstraní jak z disku, tak z CVS.

Pokud budete dělat větší reorganizaci stromu, dojdete na to, že CVS neumí odstranit adresář. To je z interních důvodů, neboť repository je strukturované stejně jako strom na disku a v adresářích v repository jsou historie smazaných souborů, takže (tyto adresáře) nejsou prázdné. Pokud jste si jisti, že smazané soubory nebudete potřebovat, můžete je v repository smazat „natvrdo“. Nebo můžete při update používat přepínač -P, který vám zajistí, že CVS nebude vytvářet prázdné adresáře.

Write access znamená shell

CVS zdánlivě vypadá jako síťový systém souborů. Uživatelé přes něj mohou číst a modifikovat určené soubory a nic víc. Bohužel to však není pravda. Pokud někdo může do repository zapisovat, může také s využitím vlastností CVS na cílovém počítači spustit libovolný program. Přístup pouze pro čtení touto nectností netrpí. (Detaily jsem nezkoumal, za dostanečný důkaz považuji to, že se o tom mluví v dokumentaci k CVS, viz například Security considerations with password authentication).

Tomuto problému se dá částečně zabránit spouštění CVS v chrootovaném prostředí (mohu doporučit cvsd). Ale stejně není dobré dávat možnost zápisu do cvs repository každému.

Velikost písmen ve jménech souborů

Pokud používáte CVS v heterogenním prostředí, můžete se dostat do problémů s velikostí souborů. Jeden druh problému nastává, pokud vytvoříte dva soubory, které se liší pouze velikostí písmen. Takové soubory není možné (třeba) na Windows klientech na disku současně mít, proto se vám je tam nepodaří správně stáhnout.

Druhý možný problém nastane, pokud někdo na Windows „opraví“ velikost písmen ve jménu souboru, t.j. přejmenuje ho a přitom pouze změní velikost písmen. Pokud nejprve neodstraní soubor se starým jménem a nepřidá ten s novým, začnou se dít divné věci.

CVS na Windows bude moci soubor normálně otevřít a nic podezřelého nezdetekuje. Pokud je však server na Unixu (unixovém systému souborů), bude nadávat, že žádný takový soubor neexistuje a uživatel bude silně zmaten. Takže pozor na velikost písmenek.

Konce řádků

Nakonec ještě drobná perlička. Pokud je soubor textový, CVS jej porovnává po řádcích. Ale pozor! Konce řádků přitom nebere v úvahu. Takže soubor s řádky zakončenými jen LF je pro CVS identický se souborem, který má řádky zakončené CR LF. To je většinou v pořádku, ale může vás to potrápit v okamžiku, kdy třeba CR LF zkonvertujete na LF pak se budete strašně divit, že si CVS myslí, že jste nic nezměnili.

CVSNT

Několikrát jsem se zde zmínil o CVSNT. To je port CVS na Windows, který byl poté zpětně portován i na unixové systémy. Oproti CVS má několik možností navíc. Viz předchozí text nebo CVSNT Advantages.

Je „víceméně“ kompatibilní i s „obyčejným“ CVS, takže můžete mixovat CVS a CVSNT servery a klienty. Velkou výhodou CVSNT je poměrně pěkné a propracované GUI, kterým disponuje verze pod Windows.

Našli jste v článku chybu?