Správa verzí

Miroslav prýmek, [m.prymek at gmail tečka com]


Obsah


Proč kontrola verzí

V zásadě lze odlišit dva hlavní způsoby použití systémů RC (Revision Control):

První použití je jednodušší a jediným jeho cílem je mít možnost označit verze souborů v určité fázi vývoje a kdykoli se k jednotlivým fázím vracet.

Druhé použití je především v oblasti vývoje, kde je potřeba skloubit simultánní úpravy prováděné více vývojáři nad stejným zdrojovým kódem. (A mimo to také zdrojové kódy v aktuálním stavu zpřístupnit světu.)


Systémy

Systémů pro správu verzí existuje mnoho. Porovnání jejich vlastností je nad hranice tohoto referátu (zájemce lze odkázat na tuto wiki page). Uveďme si tedy jen pár nejznámějších:

Základní princip

Zdrojové soubory, které podléhají kontrole verzí jsou ukládány do repository, která obsahuje (především) prvotní verzi + popis změn ve verzích následujících. Je tedy možné z ní vytáhnout libovolnou historickou revizi. Jednotlivé revize jsou označeny komentářem a jednoduchým způsobem lze kontrolovat, kdo, co a kdy změnil. Dnes běžné systémy umožňují přístup po síti - buď pomocí démona (CVS) nebo i bez něj (SVN, klička přez ssh).

Kopie souborů z repository, se kterou uživatel pracuje se nazývá working copy.

CVS je možná nejznámější, má ale některé zásadní nevýhody (přejmenování souborů, potřeba démona pro síťování, commity kompletních dat apod.). Proto si použití RC systému ukážeme na jeho mladším sourozenci SVN.


Scénář: První táhne admin

Scénář našeho příkladu začíná rozhovorem se šéfem...

Šéf: pane Prýmek, zdá se mi, že poslední dobou nějak málo pracujete. Proto jsem se rozhodl, že začnete pracovat na projektu Barbarossa, o kterém jsme mluvili na poradě. Vytvoříte repository na Fíkovníku a do měsíce chci vidět funkční prototyp. Máte k ruce pět lidí.

Nejmenovaný programátor (NP): Ale když správci Fíkovníku jsou strašní flákači, jak je donutím, aby mně tam nainstalovali CVS server?

Šéf: Pochopitelně použijete SVN, ne? Ježkovyvoči!

Nejmenovaný programátor zarputile odchází s poněkud vystrašeným výrazem...


NP po prostudování manuálu SVN začne tím, že si vytvoří repository (pozor na práva!):

[fikovnik ~] svnadmin create /mnt/data/public/svnRepo

Získali jsme adresář svnRepo s vnitřní strukturou, která je pro repository potřeba:

[fikovnik ~] cd  /mnt/data/public/svnRepo
[fikovnik /mnt/data/public/svnRepo] ls 
README.txt  conf        dav         db          format      hooks       locks
[fikovnik  /mnt/data/public/svnRepo] cat README.txt 
This is a Subversion repository; use the 'svnadmin' tool to examine
it.  Do not add, delete, or modify files here unless you know how
to avoid corrupting the repository.

If the directory "db" contains a Berkeley DB environment,
you may need to tweak the values in "db/DB_CONFIG" to match the
requirements of your site.

Visit http://subversion.tigris.org/ for more information.

Pro náš jednoduchý příklad je práce "admina" zmíněným jednořádkovým příkazem skončena.


Scénář: Na tahu je uživatel

Poté co má NP repository připravenou, může začít pracovat na projektu. (Nehodlá se moc přepracovat, takže začne zlehka.)

[fikovnik ~] mkdir -p delme/Barbarossa/trunk
[fikovnik ~] cd delme/Barbarossa/trunk
[fikovnik ~/delme/Barbarossa/trunk] echo A > MyFamousWork.txt

NP si projekt drze předem umístil do adresáře delme, protože jakmile jej vloží do repository, může jej klidně smazat. Vložení provede takto:

[fikovnik ~/delme] svn import . file:///mnt/data/public/svnRepo/
Adding         Barbarossa
Adding         Barbarossa/trunk
Adding         Barbarossa/trunk/MyFamousWork.txt

A je to. Před dončením příkazu jej svn vyzvalo doplnit popis vkládané revize projektu pomocí $EDITOR (což tady není vydět, protože se to v HTML ukazuje opravdu obtížně). NP projekt s ulehčením smaže z disku, aby ho na desktopu žádná práce nestrašila... ještě je ovšem potřeba obvolat přidělených pět lidí a říct jim, ať na projektu začnou dělat ...a NP se může věnovat zajímavější činnosti - např. hraní Sid Meier's Civilization :)

[fikovnik ~/delme] rm -rf Barbarossa 

...ovšem jen tak dlouho, dokud na chodbě neuslyší přicházet Šéfa. V tom případě potřebuje rychle zdrojáky zpátky a tvářit se, jak usilovně pracuje:

[fikovnik ~/MyMostImportantWork/Barbarossa] svn co file:///mnt/data/public/svnRepo/Barbarossa/trunk
A    trunk/MyFamousWork.txt
Checked out revision 1.
[fikovnik ~/MyMostImportantWork/Barbarossa] ls trunk
MyFamousWork.txt
[fikovnik ~/MyMostImportantWork/Barbarossa] echo "uff..."
uff...

Šéf je ale starý programátorský harcovník. Je mu jasné, že se NP fláká. Dělá tedy že nic, NP dál hraje Civilizaci, dokud před koncem pracovní doby Šéf nepřijde k NP-ovu počítači a nenapíše:

[fikovnik ~/MyMostImportantWork/Barbarossa/trunk] svn log
------------------------------------------------------------------------
r1 | prymek | 2006-12-20 22:29:42 +0100 (Wed, 20 Dec 2006) | 2 lines

Init import.

------------------------------------------------------------------------
[fikovnik ~/MyMostImportantWork/Barbarossa/trunk] svn status
[fikovnik ~/MyMostImportantWork/Barbarossa/trunk] svn up
U    MyFamousWork.txt
Updated to revision 3.
[fikovnik ~/MyMostImportantWork/Barbarossa/trunk] svn log
------------------------------------------------------------------------
r3 | vomacka | 2006-12-20 22:54:16 +0100 (Wed, 20 Dec 2006) | 2 lines

And even more important C added!

------------------------------------------------------------------------
r2 | vomacka | 2006-12-20 22:49:52 +0100 (Wed, 20 Dec 2006) | 2 lines

Most important 'B' added!

------------------------------------------------------------------------
r1 | prymek | 2006-12-20 22:29:42 +0100 (Wed, 20 Dec 2006) | 2 lines

Init import.

------------------------------------------------------------------------
[fikovnik ~/MyMostImportantWork/Barbarossa/trunk] svn diff -r 1
Index: MyFamousWork.txt
===================================================================
--- MyFamousWork.txt    (revision 1)
+++ MyFamousWork.txt    (working copy)
@@ -1 +1,3 @@
 A
+B
+C
[fikovnik ~/MyMostImportantWork/Barbarossa/trunk] echo '!?!?'
!?!?

Následuje výkřik: No to snad nemyslíte vážně! Tak to teda ne. Prototyp nechci mít za měsíc, ale za týden! Tak začněte sakra něco dělat!

Prvním příkazem totiž Šéf zjistil, že NP poslal na server teprve jednu revizi. Druhým příkazem zjistil, že od commitu k této verzi NP ještě nic nepřidal. Třetím příkazem tedy jeho zdrojáky aktualizoval na aktuální revizi. Čtvrtým příkazem zjistil, že od první NP-ho revize už jiný člen týmu (vomacka) vložil dvě revize. A konečně pátým příkazem zjistil, že vomacka zvládl dvakrát tolik práce co NP (protože NP vložil jen první revizi a diff aktuální revize oproti první ukázal, že zatímco NP naprogramoval jenom A, vomacka zvládl přidat B a C).

NP je zdrcen, protože mu sice končí pracovní doba, ale bude si muset vzít práci ssebou domů. Podívejme se tedy, co bude doma dělat (všimněte si, že NP trpí zvláštním druhem konzolové samomluvy a všechny svoje kroky si komentuje).

prymek@mandlon:~/> # protoze mam na Fikovniku ssh ucet, muzu si stahnout aktualni Barbarossu pomoci
prymek@mandlon:~/> # svn+ssh - na Fikovniku ani nemusi bezet zadny server tak jako napr. u CVS

prymek@mandlon:~/> cd F-ckingWork/Barbarossa

prymek@mandlon:~/F-ckingWork/Barbarossa> svn co svn+ssh://fikovnik/mnt/data/public/svnRepo/Barbarossa/trunk 
Password: 
A    trunk/MyFamousWork.txt
Checked out revision 3.

prymek@mandlon:~/F-ckingWork/Barbarossa> cd trunk
prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> svn info
Path: .
URL: svn+ssh://portal/mnt/data/public/svnRepo/Barbarossa/trunk
Repository UUID: 67c7b1ae-0f25-0410-8d1a-ab94f0aab44b
Revision: 3
Node Kind: directory
Schedule: normal
Last Changed Author: vomacka
Last Changed Rev: 3
Last Changed Date: 2006-12-20 22:54:16 +0100 (Wed, 20 Dec 2006)

prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> # je to dobry, vomacka uz nic nepridal, trouba jeden!
prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> # musim ho trumfnout!

prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> echo F >> MyFamousWork.txt

prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> cat MyFamousWork.txt 
A
B
C
F

prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> # sakra! melo to byt D! No nic, vratim se zpatky


prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> svn revert MyFamousWork.txt 
Reverted 'MyFamousWork.txt'

prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> cat MyFamousWork.txt 
A
B
C

prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> # ani jsem nemusel zadavat heslo a nic se nestahovalo
prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> # jakto?

prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> svn help revert
revert: Restore pristine working copy file (undo most local edits).
usage: revert PATH...

  Note:  this subcommand does not require network access, and resolves
  any conflicted states.  However, it does not restore removed directories.

Valid options:
  --targets arg            : pass contents of file ARG as additional args
  -R [--recursive]         : descend recursively
  -q [--quiet]             : print as little as possible
  --config-dir arg         : read user configuration files from directory ARG

prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> # uz si vzpominam...
prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> cat .svn/text-base/MyFamousWork.txt.svn-base 
A
B
C

Nicméně našeho hrdinu čekají další potíže...

prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> echo D >> MyFamousWork.txt 
prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> svn commit
Password: 
Sending        MyFamousWork.txt
Transmitting file data .svn: Commit failed (details follow):
svn: Out of date: '/Barbarossa/trunk/MyFamousWork.txt' in transaction '4-1'
svn: Your commit message was left in a temporary file:
svn:    '/home/prymek/F-ckingWork/Barbarossa/trunk/svn-commit.tmp'

prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> #???

prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> svn up
Password: 
C    MyFamousWork.txt
Updated to revision 4.

prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> cat MyFamousWork.txt
A
B
C
<<<<<<< .mine
D
=======
Stejne jsem lepsi!
>>>>>>> .r4

prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> # jakej blbec to tam dal?

prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> svn log
Password: 
------------------------------------------------------------------------
r4 | vomacka | 2006-12-20 23:43:30 +0100 (Wed, 20 Dec 2006) | 2 lines

Vomacka's declaration added.

------------------------------------------------------------------------
r3 | vomacka | 2006-12-20 22:54:16 +0100 (Wed, 20 Dec 2006) | 2 lines

And even more important C added!

------------------------------------------------------------------------
r2 | vomacka | 2006-12-20 22:49:52 +0100 (Wed, 20 Dec 2006) | 2 lines

Most important 'B' added!

------------------------------------------------------------------------
r1 | prymek | 2006-12-20 22:29:42 +0100 (Wed, 20 Dec 2006) | 2 lines

Init import.

------------------------------------------------------------------------

prymek@mandlon:~/F-ckingWork/Barbarossa/trunk> # no jo, zas ten vomacka!

A tak se náš hrdina naštval a začal dál studovat manuál - a dokonce zjistil, co je to tajemné trunk, o němž návody říkaly, že by za názvem projektu mělo být....


Další možnosti SVN výčtem

trunk, tags, branch

Adresáře, které je doporučeno vytvořit nad názvem projektu (Projekt/trunk,Projekt/tags,Projekt/branch)

trunk je "Hlavní větev" kódů. Je jen jedna.

tags je adresář obsahující projekt v nějakých podstatných (označených, tagged) stadiích - typicky release verzích (např. "/tags/opensync-0.10" obsahuje trunk ve stavu release 0.10).

branch slouží k umístění "alternativních vývojových verzí". Může sloužit k různým experimentům, které mohou být po otestování spojeny (merge) s trunk větví.

Podstatné je, že SVN (narozdíl od CVS) umí sledovat přesuny souborů apod., takže např. při vzniku nové tagged větve není potřeba nic skutečně kopírovat (úspora místa).

svn add

Přidání nového souboru do projektu

svn blame

Změny se zobrazením autora

[fikovnik ~/MyMostImportantWork/Barbarossa/trunk]  svn blame -r 4 MyFamousWork.txt
     1     prymek A
     2    vomacka B
     3    vomacka C
     4    vomacka Stejne jsem lepsi!

svn {copy|delete|mkdir|move}

Změna souborů zařazených do projektu (obrovská výhoda oproti CVS!). Zachovává pouze rozdílové záznamy, zámky apod.

[fikovnik ~/MyMostImportantWork/Barbarossa/trunk] svn move MyFamousWork.txt MyBoringWork.txt
A         MyBoringWork.txt
D         MyFamousWork.txt

svn export

Vytvoření neverzované kopie projektu (tj. bez adresářů .svn).

svn {lock|unlock}

Zamčení části kódu proti změnám jinými uživateli.

svn status

Vypsání statusu souborů v aktuální working copy (změněný, zamčený, smazaný apod.) Možností je spoustu - viz svn help st

svn merge

Sloučení dvou různých verzí (např. trunk a branch/XY).

svn resolved

Provedeme po (manuálním) vyřešení konfliktních úprav. Odstraní soubory a příznaky týkající se konfliktů.

svn prop*

K souborům můžeme přidávat nejrůznější anotace.

$ svn proplist --verbose foo.c
Properties on 'foo.c':
  svn:mime-type : text/plain
  svn:keywords : Author Date Rev
  owner : sally

Nástroje

S programy na kontrolu verzí se nemusí pracovat jen z příkazové řádky. existuje spousta nástrojů, které podporu verzování integrují do IDE, filemanagerů apod. Problém ale můžeme mít s tím, abychom našli pluginy pro ten který systém právě do všech nástrojů, které používáme (ale vzhledem k tomu, že jsou to vždy jen grafické frontendy k příkazům, tak to není taková tragédie.

Příkladem může být Cervisia

nebo scplugin

a spousta dalších pluginů pro netbeans, eclipse apod.

Úplně samostatnou kapitolou jsou nejrůznější webové procházeče repositories, které někdy slouží i pro širší management životního cyklu softwaru (viz např. trac).


Odkazy

CVS
SVN
trac
Cervisia
scplugin
vcsreport - cvs pro Netbeans
Subclipse - SVN pro Eclipse