Subversion Jakub Vlček
Obsah Konflikty Strukturální(stromové) konflikty Sparse directories
Konflikty Vyskytují se při aktualizaci dvou souborů s různými změnami Konflikt nenastane pokud jsou úpravy na jiných místech Kdy nastane konflikt? Pokud SVN detekuje konflikt, nabídne různé způsoby, jak ho vyřešit edit otevře soubor z úložiště v editoru diff-full zobrazí všechny změny v souboru z úložiště resolved přijmeme soubor z úložiště display-conflict zobrazí všechny konflikty mine-conflict moje aktualizace přepíší aktualizace z úložiště their-conflict aktualizace souboru z úložiště přepíší mé mine-full přijme celý můj soubor (i nekonfliktní části) theirs-full přijme celý soubor z úložiště (i nekonfliktní části) postpone označí konflikt k vyřešení později launch spustí externí nástroj k řešení konfliktů show all zobrazí tento seznam
Zobrazení konfliktů Pomocí příkazu diff-full nebo diff-conflict Select: (p) postpone, (df) diff-full, (e) edit, (mc) mine-conflict, (tc) theirs-conflict, (s) show all options: df ---.svn/text-base/sandwich.txt.svn-base Tue Dec 11 21:33:57 2007 +++.svn/tmp/tempfile.32.tmp Tue Dec 11 21:34:33 2007 @@ -1 +1,5 @@ -Just buy a sandwich. +<<<<<<<.mine +Go pick up a cheesesteak. +======= +Bring me a taco! +>>>>>>>.r32 Na prvním řádku je původní soubor, na druhém mé změny a na posledním změny v souboru z úložiště. diff-conflict je podobný, ale zobrazí jen konfliktní části a má jiný výpis (zobrazení všech tří stavů)
Řešení konfliktů 2 způsoby, kdy můžu konflikty řešit jednotlivě edit launch Zbytek preferuje jen jednu verzi Celý soubor mine-full their-full Jen konfliktní části mine-conflict their-conflict Pokud neumím vyřešit konflikt, hodí se příkaz postpone
Neinteraktivní režim Pomocí --non-interactive Konfliktí soubory označeny písmenem C po dokončení update můžu mezi soubory vybírat manuálně Pokud SVN rozhodne, že mohou být dva knfliktní soubory spojeny, označí konfliktní místa specialními řetězci (conflict-markers) Pro každý konfliktní soubor vytvoří SVN neverzovanou verzi Filename.mine Filename.rOLDREV Filename.rNEWREV
Příklad Pokud jsem upravil soubor sandwitch.txt, ale někdo ho mezitím upravil na serveru, SVN se chová následovně $ svn update Updating '.': Conflict discovered in 'sandwich.txt'. Select: (p) postpone, (df) diff-full, (e) edit, (mc) mine-conflict, (tc) theirs-conflict, (s) show all options: p C sandwich.txt Updated to revision 2. Summary of conflicts: Text conflicts: 1 $ ls -1 sandwich.txt sandwich.txt.mine sandwich.txt.r1 sandwich.txt.r2 Dokud nesmažu tři pomocně soubory (.mine,.r1,.r2), nelze provést commit
Řešení konfliktu Pomocí svn resolve a možnosti --accept s následujícími možnostmi base potvrdí původní verzi beze změn mine-full potvrdí celý můj soubor theirs-full potvrdí soubor z úložiště working originální soubor (bez přípony), v kterém jsem konflikty vyřešil ručně svn resolve s --accept smaže všechny dočasné soubory
Ruční editace - příklad $ cat sandwich.txt Top piece of bread Mayonnaise Lettuce Tomato Provolone <<<<<<<.mine Salami Mortadella Prosciutto ======= Sauerkraut Grilled Chicken >>>>>>>.r2 Creole Mustard Bottom piece of bread
V souboru jsou vidět 3 speciální značky složené z <, > a = Mezi < a = jsou mé změny Mezi = a > jsou změny z úložiště Pokud chci konflikt odstranit, musím tyto speciální značky odstranit Při svn update musím explicitně uvést řešení všech konfliktů
Strukturální konflikty Rozdílné od klasických konfliktů Smazání Přesunutí Přejmenování Záleží na verzi Před 1.6 více možností Od 1.6 je pracovní soubor označen jako konflikt
Strukturální konflikty - popis Před verzí 1.6 Lokálně modifikovaný objekt x přejmenování/přesunutí v úložišti(repository) Zkontroluje přejmenovaný soubor kvůli změnám Smaže starý soubor, ale pokud byl soubor lokálně upraven, nechá ho na lokálním disku jako neverzovaný Přejmenovaný soubor z úložiště přidá do lokálního úložiště PROBLÉM neverzovaný soubor v lokálním úložišti Od verze 1.6 Problémový soubor je označen jako konfliktní
Příklad Takto vypadá projekt: $ svn list -Rv svn://svn.example.com/trunk/ 13 harry Sep 06 10:34./ 13 harry 27 Sep 06 10:34 COPYING 13 harry 41 Sep 06 10:32 Makefile 13 harry 53 Sep 06 10:34 README 13 harry Sep 06 10:32 code/ 13 harry 54 Sep 06 10:32 code/bar.c 13 harry 130 Sep 06 10:32 code/foo.c $
V další verzi někdo přejmenuje bar.c na baz.c, ale já provedu jiné změny (i v souboru bar.c) $ svn diff Index: code/foo.c =================================================================== --- code/foo.c (revision 13) +++ code/foo.c (working copy) @@ -3,5 +3,5 @@ int main(int argc, char *argv[]) { printf("i don't like being moved around!\n%s", bar()); - return 0; + return 1; } Index: code/bar.c =================================================================== --- code/bar.c (revision 13) +++ code/bar.c (working copy) @@ -1,4 +1,4 @@ const char *bar(void) { - return "Me neither!\n"; + return "Well, I do like being moved around!\n"; } $
Z logu to vypadá, že někdo změnil bar.c, ale commit nelze provést: $ svn commit -m "Small fixes Sending code/bar.c svn: E155011: Commit failed (details follow): svn: E155011: File '/home/svn/project/code/bar.c' is out of date svn: E160013: File not found: transaction '14-e', path '/code/bar.c $
Při příkazu svn update odhalíme strukturální konflikt, svn ho korektně označí písemeny C a A: $ svn update Updating '.': C code/bar.c A code/baz.c U Makefile Updated to revision 14. Summary of conflicts: Tree conflicts: 1 $ $ svn status M code/foo.c A + C code/bar.c > local edit, incoming delete upon update Summary of conflicts: Tree conflicts: 1 $
Přesun/přejmenování V SVN jde o zkopírování a následné smazání původního souboru SVN umí upozornit na smazání lokálně upraveného souboru Jednoduše nelze zjistit, zda jde o přesunutí souboru nebo samostané smazání, což je ovšem potřeba -> vyplatí se číst logy $ svn log -r14 ^/trunk ------------------------------------------------------------------------ r14 harry 2011-09-06 10:38:17-0400 (Tue, 06 Sep 2011) 1 line Changed paths: M /Makefile D /code/bar.c A /code/baz.c (from /code/bar.c:13) Rename bar.c to baz.c, and adjust Makefile accordingly. ------------------------------------------------------------------------ $
svn info Ukáže informace o konfliktních souborech Left lokální soubor Right příchozí soubor $ svn info code/bar.c tail -n 4 Tree conflict: local edit, incoming delete upon update Source left: (file) ^/trunk/code/bar.c@4 Source right: (none) ^/trunk/code/bar.c@5 $ Při pokusu o commit nastane chyba, protože jsme nevyřešili konflikt $ svn commit -m "Small fixes svn: E155015: Commit failed (details follow): svn: E155015: Aborting commit: '/home/svn/project/code/bar.c' remains in conflict $
Řešení Musíme buď souhlasit nebo nesouhlasit se změnou (přesunem) Pokud souhlasím, je můj bar.c zbytečný, můžeme ho smazat a konflikt označit za vyřešený (tím ale ztratím vlastní úpravy) Pokud chci změny zachovat, musím svn explicitně říct, co chci udělat. Pokud chci změny uložit do přesunutého souboru Nejdříve musíme pomocí svn diff vytvořit patchfile, který pak upravíme tak, aby ukazoval na přejmenovaný soubor
$ svn diff code/bar.c > PATCHFILE $ cat PATCHFILE Index: code/bar.c =================================================================== --- code/bar.c (working copy) +++ code/bar.c (working copy) @@ -1,4 +1,4 @@ const char *bar(void) { - return "Me neither!\n"; + return "Well, I do like being moved around!\n"; } $ ### Edit PATCHFILE to refer to code/baz.c instead of code/bar.c $ cat PATCHFILE Index: code/baz.c =================================================================== --- code/baz.c (working copy) +++ code/baz.c (working copy) @@ -1,4 +1,4 @@ const char *bar(void) { - return "Me neither!\n"; + return "Well, I do like being moved around!\n"; } $ svn patch PATCHFILE U code/baz.c $
Změny ze souboru bar.c se dostanou do baz.c, lokální soubor můžeme smazat $ svn delete --force code/bar.c D code/bar.c $ svn resolve --accept=working code/bar.c Resolved conflicted state of 'code/bar.c $ svn status M code/foo.c M code/baz.c $ svn diff Index: code/foo.c =================================================================== --- code/foo.c (revision 14) +++ code/foo.c (working copy) @@ -3,5 +3,5 @@ int main(int argc, char *argv[]) { printf("i don't like being moved around!\n%s", bar()); - return 0; + return 1; } Index: code/baz.c =================================================================== --- code/baz.c (revision 14) +++ code/baz.c (working copy) @@ -1,4 +1,4 @@ const char *bar(void) { - return "Me neither!\n"; + return "Well, I do like being moved around!\n"; } $
Pokud se změnami nesouhlasím, zjistím se, zda v souboru baz.c nejsou nějaké změny, a následně ho smažu, vrátím zpět úpravy v Makefile $ svn delete --force code/baz.c D code/baz.c $ svn resolve --accept=working code/bar.c Resolved conflicted state of 'code/bar.c $ svn status M code/foo.c A + code/bar.c D code/baz.c M Makefile $ svn diff Index: code/foo.c ===Výpis souboru foo.c=== Index: code/bar.c ===Výpis souboru bar.c=== Index: code/baz.c ===Výpis souboru baz.c=== Index: Makefile =================================================================== --- Makefile (revision 14) +++ Makefile (working copy) @@ -1,2 +1,2 @@ foo: - $(CC) -o $@ code/foo.c code/baz.c + $(CC) -o $@ code/foo.c code/bar.c
Sparse directories svn checkout vytvoří rekurzivně pracovní kopii celé adresářové struktury se všemi soubory z úložiště Od verze 1.5 tzv. sparse directories (shallow checkouts), dovoluje kopii pouze části adresářové struktury Ostatní soubory můžeme aktualizovat později
Sparse directories - příklad Takto vypadá celá adresářová struktura $ svn checkout file:///var/svn/repos mom A mom/son A mom/son/grandson A mom/daughter A mom/daughter/granddaughter1 A mom/daughter/granddaughter1/bunny1.txt A mom/daughter/granddaughter1/bunny2.txt A mom/daughter/granddaughter2 A mom/daughter/fishie.txt A mom/kitty1.txt A mom/doggie1.txt Checked out revision 1. $
Stačí přidat parametr --depth $ svn checkout file:///var/svn/repos momempty --depth empty Checked out revision 1 $
Možné omezení hloubky --depth empty pouze cílový soubor, nikoliv podsložky či soubory ve složce --depth files cílový soubor nebo obsah složky --depth immediates cílový soubor a bezprostřední soubory a složky, složky potomků budou prázdné --depth infinity celý podstrom cílové složky Lokální kopie si pamatuje hloubku rekurze příkazy na ní se provadí do zvolené hloubky Příklady $ svn checkout file:///var/svn/repos mom-files - -depth files A mom-files/kitty1.txt A mom-files/doggie1.txt Checked out revision 1. $ svn checkout file:///var/svn/repos momimmediates --depth immediates A mom-immediates/son A mom-immediates/daughter A mom-immediates/kitty1.txt A mom-immediates/doggie1.txt Checked out revision 1. $
--depth lze použít i u jiných příkazů a omeit tak hloubku --set-depth NEW-DEPTH TARGET nastaví zapamatovanou hloubku pracovní kopie, kterou jsme již získali $ svn update --set-depth files mom-empty A mom-empty/kittie1.txt A mom-empty/doggie1.txt Updated to revision 1. $ svn update --set-depth immediates mom-empty A mom-empty/son A mom-empty/daughter Updated to revision 1. $ svn update --set-depth infinity mom-empty A mom-empty/son/grandson A mom-empty/daughter/granddaughter1 A mom-empty/daughter/granddaughter1/bunny1.txt A mom-empty/daughter/granddaughter1/bunny2.txt A mom-empty/daughter/granddaughter2 A mom-empty/daughter/fishie1.txt Updated to revision 1. $
(ne)výhody sparse directories Pokud mám více projektů v jednom úložišti Můžu pak každý projekt řešit zvlášť Menší datová náročnost v případě velkých úložišť Pokud provedu svn update set-depth empty na pracovní kopii s celou strukturou, nezahodí svn všechny změny ale skončí chybou Nelze explicitně vyloučit zvolené položky, pouze implicitně sjednotit vše ostatní
Otázky?
Zdroje Konflikty: http://svnbook.red-bean.com/en/1.7/svn.tour.cycle.html Stromové konflikty: http://svnbook.red-bean.com/en/1.7/svn.tour.treeconflicts.html Sparse directories: http://svnbook.red-bean.com/en/1.5/svn.advanced.sparsedirs.html
Díky za pozornost