===================== VCS systém Subversion ===================== $Author: pepca $ $Rev: 520 $ $Date: 2007-03-23 13:53:17 +0100 (Fri, 23 Mar 2007) $ http://subversion.tigris.org/ (home-page projektu) http://svnbook.red-bean.com/ (SVN-book - základní podrobný manuál) http://subversion.tigris.org/faq.html http://www.abclinuxu.cz/clanky/show/54473 (česky, trochu zastaralé) http://www.developer.com/tech/article.php/3499816 (A Crash Course in Subversion) http://www.developer.com/tech/article.php/3503151 (Part 2) TortoiseSVN - pěkný vizuální klient pro Windows: http://tortoisesvn.tigris.org/ http://www.oucs.ox.ac.uk/oucsweb/tortoisesvn.xml?style=printable (popis TortoiseSVN, ale psaný pro uživatele Oxfordské univerzity) Klienti, instalace ================== Řádkový klient (server i utility, ty ale běžný uživatel nepotřebuje) se dá stáhnout z adresy: http://subversion.tigris.org/project_packages.html Po instalaci (ve Windows doporučuji stáhnout si tu .EXE variantu instalace) je ihned připraven k práci. Vyvolává se řádkově v okně terminálu (viz "svn help"). GUI klient TortoiseSVN je velmi pohodlný. Umí přesně všechny příkazy jako řádková verze, ve Windows se umí zaintegrovat jako shell-extension, takže je s ním velmi snadná práce: http://tortoisesvn.tigris.org/ Základní myšlenky ================= SVN pracuje s touto filozofií: Každý klient na svém lokálním disku obsahuje kopii celé repository (tzv. "pracovní kopie"). V hidden ".svn" adresářích se přitom uchovávají řídící informace - např. originální verze všech souborů, přesně tak, jak byly stažené ze serveru, .. Klient děla ve své pracovní kopii všemožné úpravy, testuje, ladí, opravuje, .. - a když chce výsledky své práce poslat na server ostatním, provede příkaz "commit". Někdy se tomu říká "Copy-modify-merge" přístup. SVN systém umí samozřejmě řešit situace, kdy stejný soubor modifikuje paralelně více uživatelů, většina konfliktů se obyčejně vyřeší automaticky (a správně), v těch nejkomplikovanějších případech je člověk požádán o rozhodnutí, jak to má být správně. (viz později popisované příkazy "status", "diff", "revert", "update", "merge", "commit") Co tam patří? ============= Co dávat do SVN repository: --------------------------- - zdrojáky - dokumentaci ve zdrojovém tvaru (např. TeX nebo XML zdrojáky) - log-file, postup prací, hlášení o chybách, apod. (tj. i interní dokumenty) - projektové soubory, pomocné scripty, Makefiles, Ant scripty, apod. (i pomocná utilitka nebo script se může hodit jiným, je ale nutné ji napsat aspoň trochu slušně a univerzálně - tj. např. žádné absolutní cesty!) - data, která patří k projektu (a např. se to bez nich nedá vyzkoušet). Výjimku *mohou* tvořit nějaká velmi rozsáhlá data (3D soubory, dlouhé zvuky apod.). Tam se můžeme domluvit jinak. Pokud se musíte rozhodovat, preferujte textové soubory. SVN s nimi umí efektivněji zacházet. Co nepatří do SVN repository: ----------------------------- - pracovní a dočasné soubory (*.obj, *.o, *~, *.bak, *.class apod.) Pozor na (veliké) dočasné a konfigurační soubory, které např. používá Microsoft Visual Studio: *.ncb, *.opt, *.plg, *.suo, *.user - ty tam nikdy nedávat! Jsou specifické pro konkrétní instalaci VS a každý je chce mít vlastní! (naopak *.dsw, *.dsp, *.sln, *.vcproj tam patří - většinou jsou dokonce textové!) - cílové soubory, které lze snadno vygenerovat ze zdrojových souborů (*.exe, *.so, Doxygen nebo JavaDoc dokumentace, *.dvi, *.ps apod.) - produkty třetích stran - pomocné knihovny, data, která lze kdykoli z původního zdroje stáhnout (ale návod, jak, kde a co je potřeba stáhnout a nainstalovat, do repository naopak *určitě patří*) Výjimky jsou možné - při vážných důvodech - ale nesmí se to přehánět. Revize ====== SVN na rozdíl od CVS čísluje revize *celé repository*! Jsou to přirozená čísla od 1 ("Initial import"). Tj. když opravím soubor "xx.h" (a odešlu ho na server), vznikne nové číslo revize *celého SVN stromu*. To je výhodné, lze se snadno vracet do určitého časového okamžiku. Dále je dobře, že se jeden "commit" dělá jako nedělitelná databázová transakce - buď se povede celý, nebo se z něj vůbec nic neudělá.. Za jeden den může být u silně vyvíjeného projektu i několik desítek revizí. Revize je třeba chápat jako časovou osu vývoje projektu (spíš než "číslo verze"). Větvení = "branching" ===================== SVN má velmi levnou operaci "branch". Jedná se o jakýsi symbolický odkaz v databázi repository, pokud se jedna větev mění, ukládají se pouze rozdíly. (originální manuály - viz "branching", "merging", "tagging") K čemu se to dá používat: 1. soukromé vývojové větve -------------------------- Pokud plánuji dlouhou práci v nějaké části projektu (např. refaktorizaci, která mi na několik dní rozbije všechny zdrojáky), není dobré dělat ji v "hlavní větvi" (trunk)! Ostatní by museli počkat, až (zda) mi to bude znova chodit.. Vyrobím si vlastní "větev" (branch), kde dělám "pěrestrojku" a ostatním zůstane funkční kód v hlavní větvi. Vtip je v tom, že ostatní třeba mohou ve zdrojáku mezitím najít nějakou chybu a opravit ji. SVN umí docela spolehlivě přenášet takové opravy mezi větvemi - a až moje privátní větev skončí (úspěšně), pomocí operace "merge" se ta větev spojí s (mezitím se vyvíjejícím) hlavním "kmenem" (trunk). 2. trvalé vývojové větve ------------------------ Různé verze HW, varianty SW, zakázky pro různé klienty, apod. Opět se využije schopností SVN přenášet opravy chyb mezi větvemi (teda ne vždycky je to žádoucí, jako uživatelé SVN nad tím však máme kontrolu). 3. označení významné verze - tagging ------------------------------------ Chci v repository označit nějak významnou verzi - třeba přesně soubory, ze kterých vznikl "release 1.03" (někde se tomu říká "snapshot"). Tak prostě vytvořím branch v oblasti "tags" a okopíruji do něj úplně všechno z aktuálního "trunk". Připomínám, že technicky to SVN dělá pomocí symbolických odkazů, takže se nikde data nekopírují - neplýtvám síťovými ani diskovými prostředky! Používané příkazy (viz help): svn copy svn merge svn switch Organizace repository (hrubě) ============================= Souvisí to s "větvemi" (branches) a "tags" (snapshots): /trunk Hlavní vývojová větev - obsahuje vždy aktuální verze zdrojáků a dat. Organizační zásada: musí tam být vždy fungující (aspoň přeložitelný) kód! Výjimky jen v nutných případech Pokud chci něco dlouhodoběji "rozvrtat", udělám si vlastní soukromou větev (viz "/branches"). /tags Označené verze, které se už nesmí měnit (archiv "release" verzí). Jakési zálohy (snapshots) aktuálního stavu hlavní větve ve významných okamžicích.. (pro snadné vracení se k historickým verzím) /branches Vývojové větve pro soukromé účely ("pěrestrojka") nebo příp. trvalé větve pro různé verze HW, SW, atd. Přejmenování ============ Přejmenováním souboru nebo adresáře ("svn move") se neztratí jeho historie, takže odpadá příp. zdlouhavé přemýšlení, jak nějaký soubor pojmenovat .. když nám jméno později nebude vyhovovat, snadno ho lze změnit! Nejdůležitější příkazy ====================== Typicky bude běžný uživatel SVN používat jen některé z nich. Obecně se dá vyvolat help příkazem "svn help" nebo ke konkrétnímu příkazu "svn help ". 1. počáteční načtení repository na lokální disk ----------------------------------------------- (vytvoření první pracovní kopie - člověk to udělá jen jednou) svn checkout (pro nás bude URL = svn://cgg.ms.mff.cuni.cz/ a doporučuji poprvé zadat i "--username ") 2. aktualizace pracovní kopie před začátkem práce ------------------------------------------------- (provádí se pravidelně - začátek "pracovního cyklu") svn update 3. provádění změn ----------------- svn add svn delete svn copy svn move Editace souborů se dělá bez dalších zvláštních procedur. Prostě edituji podle potřeby libovolné soubory. POZOR: chci-li přidat soubor, musím uvědomit SVN systém příkazem "svn add" (až poté, co existuje na disku), naopak - při odstraňování souboru ho nemusím mazat z disku, ale musím zadat "svn delete"! 4. zkoumání provedených změn ---------------------------- svn status Vypíše souhrnný přehled, které soubory jsem proti SVN serveru změnil (upozorní např. i na nově přidané soubory, které nejsou pod kontrolou SVN). svn diff Vypíše rozdíl mé pracovní kopie souboru a repository. svn revert Vrátí původní verzi souboru (jak byla stažená z repository). 5. merge změn provedených mezitím jinými uživateli -------------------------------------------------- Jen pokud se nepodaří rozhodnout automaticky (asi jenom párkrát v životě se mi to stalo - může být častější u větších projektů = více programátorů..). svn merge svn resolved Tyhle dva příkazy jsem moc nepoužíval, vždycky jsem to dělal ručně nebo pomocí TortoiseSVN. SVN do textového souboru vkládá řádky označující obě konfliktní změny, takže je to obvykle poměrně snadné ručně vyřešit. 6. odeslání změn na server -------------------------- svn commit Nezapomeňte na stručnou poznámku, co bylo v této revizi opraveno! SVN klient ani nedovolí příkaz odeslat bez zadání komentáře. Příklady ======== Kroky, které bude typický uživatel dělat: 1. 2. 3. 4. [5.] 6. 2. 3. 4. [5.] 6. .... Tj. pracovní cyklus obsahuje kroky 2. až 6. Neprovádí se vždy všechny příkazy uvedené pod jednotlivými kroky, cyklus může vypadat třeba takto: > svn update > svn add file1.c > svn add file2.c > svn status # jen pro kontrolu A file1.c A file2.c > vi comment.txt # opravim komentar > svn commit -F comment.txt Sending file1.c Sending file2.c Transmitting file data .. Commited revision 5. Nebo další příklad: > vi file1.c # edituji soubor - trva mi to dlouho > svn update # kontroluji, zda ho mezitim nekdo nezmenil G file1.c # zmeny uspesne zmergovany > svn status M file1.c # modifikovany soubor > vi comment.txt # opravim komentar > svn commit -F comment.txt Sending file1.c Transmitting file data .. Commited revision 12. Properties ========== Každý soubor i adresář může mít přiřazenou množinu "atributů" - tzv. "properties" Je to libovolný string označený jménem, můžeme si do něj zapisovat jakékoli dodatečné informace, např. pro automatické vytváření Makefiles, apod. SVN odlišuje "obsah souboru" (contents) od "property". Můžu změnit jen "property" a obsah zůstane stejný ... nebo naopak. Příkazy na práci s "properties": svn proplist svn propget svn propset svn propdel svn propedit Uživatelské "properties" jsem zatím nikdy nepoužíval, ale užitečné jsou některé systémové (začínají "svn:"): "svn:executable" - řeknu tím SVN, že se jedná o EXE soubor, kdyby to systém nepoznal sám "svn:mime-type" - zadám v případě, že to SVN automaticky nepoznal (velmi zřídka) "svn:ignore" - vlastnost adresáře - aby mne neotravoval se soubory, které nejsou pod kontrolou SVN (např. můj "comment.txt" pro zadávání poznámky k revizi - používám "svn commit -F comment.txt") "svn:keywords" - nahrazuje ve zdrojáku "klíčová slova" aktuálními hodnotami: autor poslední změny, datum modifikace, číslo revize, .. Jsou na to zvláštní posloupnosti, např. "$Rev: 520 $" nebo "$Author: pelikan$" (viz help) "svn:eol-style" - ošetření oddělovačů řádek - u textových souborů bychom měli mít nastaveno na "native" Další příkazy ============= Spíše informačního charakteru, občas je používám: svn import Importování (vložení pod kontrolu SVN) najednou celého adresáře (stromu adresářů). svn export Kopie celé hierarchie adresářů na disk - kopírují se jenom vlastní soubory, nikoli interní SVN data. Vznikne tak čistý adresář, který *není* pod kontrolou SVN. svn log Vypíše historii změny daného souboru/adresáře. Lze zadat rozsah revizí.. svn list Vypíše přehledně detailnější informace o daných souborech pod kontrolou SVN, příp. i jejich stav (poslední změna..) svn blame Vypíše řádku po řádce, kdo a kdy (revize) ji naposledy změnil! Kuchařka ======== Jednoduché postupy pro začátačníky, některé příkazy jsou uvedeny přesně tak, jak je zadávají uživatele SVN serveru cgg.ms.mff.cuni.cz: 1. úvodní načtení repository ---------------------------- Tj. vytvoření lokální kopie dat na disku vašeho počítače. Tento příkaz musí každý udělat na začátku práce s projektem pod SVN. Musíte mít nainstalovaného SVN klienta a fungující přístup na Internet. svn checkout --username svn://cgg.ms.mff.cuni.cz/blabla kde je vaše user-name (přiděluji já jako správce serveru) a "blabla" jméno repository. V aktuálním adresáři se založí podadresář "blabla" (který předtím nesmí existovat) a do něj se načte aktuální stav celé repository. GUI klient TortoiseSVN: příkaz "TortoiseSVN/Checkout" vyvolat (pravým tlačítkem myši) v adresáři, kde chci založit lokální kopii projektu "blabla". V okénku vybrat požadované parametry - zejména URL repository. 2. aktualizace projektu ze serveru ---------------------------------- V kořenovém adresáři repository (např. "blabla" z minulého příkladu) zadat příkaz svn update GUI klient TortoiseSVN: příkaz "TortoiseSVN/Update" na kořenovém adresáři projektu. 3. přidání nového souboru do projektu ------------------------------------- Je dobré mít aktuální verzi projektu (viz "svn update"). Pak je možné přidávat do kontroly SVN celé nové podadresáře (včetně *všech*) souborů nebo to dělat postupně. Nejdříve se musí do hierarchie projektu nové soubory/adresáře přidat. Tím se ale automaticky nedostanou pod SVN kontrolu. To udělá až následující příkaz: svn add kde je cesta k souboru/souborům/adresáři, apod. Pozor - nemohu přidat soubory do repository, když tam ještě není jejich adresář! Přidávám-li adresář, mohu použít přepínač "-N" (nebo "--non-recursive"), jestli se mají ignorovat soubory v něm. To je dobré zejména tehdy, obsahuje-li adresář nějaké pomocné soubory (*.ncb, *.obj, *.bak, *~ - ty do repository nepatří!). Příklad doporučeného postupu (přidávám C++ zdrojáky a HTML návod z adresáře "src"): svn add -N src cd src svn add *.cpp svn add navod.html Tím se do projektu přidají jen požadované (= explicitně zadané) soubory. GUI klient TortoiseSVN: Příkaz "TortoiseSVN/Add", je ještě možné zaškrtávat, které soubory/adresáře chcete opravdu přidat.. 4. odeslání změn na server (commit) ----------------------------------- Doporučuje se odesílat změny poměrně často - např. po každé jednotlivé opravě chyby a jejím vyzkoušení nebo po přidání jednoho příkazu apod. Před commitem se doporučuje udělat "update", pokud na projektu pracuje víc lidí. Informace o tom, které soubory byly změněny (nejlépe v kořenovém adresáři projektu): svn status Odeslání změn na server: svn commit -m "poznamka - co bylo zmeneno a proc" Nebo máme-li nějakou delší poznámku už připravenou v souboru "comment.txt": svn commit -F comment.txt Upozorňuji, že je vždy nutné nějakou poznámku zadat. A doporučuje se používat opravdu smysluplné a informativní poznámky - poznámky jsou (kromě data commitu) jediným vodítkem při orientaci v revizích (= časové ose projektu)! Poznámky "ještě tam byla jedna chybka" nebo "oops - to jsem zapomněl" jsou úplně k ničemu! (kdo si po roce vzpomene, co zapomněl..) GUI klient TortoiseSVN: Kontrola provedených změn: "TortoiseSVN/Check for Modifications". Commit: "TortoiseSVN/Commit" na nějakém nadřízeném adresáři. Lze si vybírat soubory, které se mají commitovat (to může být užitečné - rozdělit např. úpravy do několika skupin podle chyby, kterou opravují..). Zadání poznámky v horním editačním okně, .. 5. nastavení vlastností souboru ------------------------------- SVN pozná většinou správně, zda se jedná o textový nebo binární soubor. Konce řádků však implicitně nijak neošetřuje, tj. chová se i k textovému souboru jako k binárnímu (nechává soubor v přesné binární podobě, jak byl commitování). Většinou je vhodné, aby měl pro klienta pracujícího v Linuxu textový soubor právě UNIX-ovské konce řádků (LF), ve Windows zase DOS-ovské (CRLF). To lze zařídit nastavením atributu "svn:eol-style" na hodnotu "native". Udělá se to příkazem svn setprop svn:eol-style "native" kde je daný textový soubor. Další vlastnost, která se hodí, je schopnost SVN nahrazovat ve zdrojovém souboru zvláštní posloupnosti (např. "$Author: pepca $" nebo "$Date: 2007-03-23 13:53:17 +0100 (Fri, 23 Mar 2007) $") skutečnými aktuálními hodnotami, které se mění automaticky při každém commitu toho souboru. Viz čtvrtý řádek tohoto souboru! Pro nejčastěji používanou trojici "autor", "číslo revize" a "datum" je nastavení svn setprop svn:keywords "Date Rev Author" GUI klient TortoiseSVN: V Windows Exploreru: "Vlastnosti" souboru (angl. "Properties"), vybrat záložku "Subversion". Tam je možné vizuálně kontrolovat a zadávat všechny vlastnosti souboru. 6. ignorované soubory --------------------- SVN si ve svém repository (vytvořené původně pomocí "svn checkout") myslí, že by měl spravovat úplně všechny soubory. Ty, které nemá pod palcem, označuje otazníčkem nebo u nich píše "non-versioned". Pokud chceme, aby byly některé soubory trvale systémem SVN ignorovány, je potřeba v *jejich adresáři* nastavit vlastnost "svn:ignore". Např. pro pomocné/dočasné soubory MS Visual Studia (verze 6 nebo .NET) se osvědčilo nastavení: svn setprop svn:ignore "Debug Release *.ncb *.plg *.opt *.suo *.user" Pak se už nikdy nebude SVN snažit na ty soubory/adresáře upozorňovat. Pozn1: lze zadávat libovolné žolíky * nebo ? Pozn2: zadáním příkazu "svn setprop" se přepíše celá daná vlastnost, tj. nelze např. přidávat jednotlivé ignorované masky souborů postupně! Pozn3: i soubory takto ignorované lze později pod správu SVN přidat. Např. chci mít verzovaný jediný textový soubor todo.txt, ostatní (třeba debug-logy apod.) se mají ignorovat: svn setprop svn:ignore "*.txt" svn add todo.txt GUI klient TortoiseSVN: V Windows Exploreru: "Vlastnosti" souboru (angl. "Properties"), vybrat záložku "Subversion". Tam se zvolí (v "combo-boxu") vlastnost svn:ignore a v okénku pod tím lze libovolně editovat obsah atributu. Nakonec se hodnota potvrdí tlačítkem "Set". 7. přejmenování nebo přesunutí souboru/adresáře ----------------------------------------------- SVN dělá přejmenování efektivně, pomocí odkazů ve své interní databázové struktuře, je tedy přejmenování souboru/adresáře laciná operace. Zachovávají se při tom všechny atributy i historie úprav. Příklad přesunutí souboru "frame1.cpp" do jiného adresáře: svn move frame1.cpp ../modules/GUIclient/frame1.cpp Přejmenování souboru: svn move FormView.java DBFViewForm.java Přesunutí celého adresáře - včetně jeho obsahu: svn move src ../modules/client Pozn: je bezpečnější bezprostředně před přejmenováním provést příkaz "svn update". Někdy se příkaz "move" nesnese (v jedné commit-dávce) spolu s jinými příkazy - myslím, že není možné adresář vytvořit "svn add" a hned ho přesunout jinam. Mezi tím musí být commit. Ale třeba je to chyba v současné verzi a bude později opravena.. GUI klient TortoiseSVN: Jsou to dva různé příkazy: "TortoiseSVN/Rename" a "TortoiseSVN/Relocate". 8. vrácení omylem provedené změny --------------------------------- Je-li změna pouze v loální kopii (ještě nebyla commitována), je to jednoduché: svn revert Soubor/adresář se vrátí přesně do stavu, kdy byl naposledy synchronizován se serverem příkazem "svn update", příp. "svn commit". Jesliže byla změna odeslána na SVN server, je již součástí historie projektu (to již změnit nelze). Snadno lze z SVN serveru stáhnout starší verzi souboru a tu znovu commitovat: svn cat -r > Nebo lepším řešením (čistějším - pracuje i s atributy souboru) je aplikovat změny pomocí příkazu "svn merge": svn merge -r : (všude je označení špatné revize, je číslo "správné" revize a příslušný soubor) Potom je pochopitelně potřeba změnu znova commit-nout. GUI klient TortoiseSVN: Ekvivalent "svn revert": "TortoiseSVN/Revert" Vracení commit-nutých oprav: vyvolá se příkaz "TortoiseSVN/Show Log", tam se v seznamu najde revize s chybnými změnami a příkazem "Revert changes from this revision" vrátí ty chybné změny (jen ty chybné změny, funguje to omezeně i v případě, že se mezitím dělaly jiné úpravy..). 9. prohlížení změn ------------------ Změny v aktuální pracovní kopii i v historii lze studovat příkazem "svn diff" (viz help). Kontrola, které soubory byly vůbec v lokální kopii změněny: svn status Porovnání změn jednoho souboru provedených v pracovní kopii: svn diff Porovnání proti dané revizi: svn diff -r Porovnání mezi dvěma revizemi v historii projektu: svn diff -r : GUI klient TortoiseSVN: Které soubory byly v lokální kopii změněny: "TortoiseSVN/Check for Modifications". Pro lokální změnu (proti repository) "TortoiseSVN/Diff", diference mezi jednotlivými revizemi v historii: "TortoiseSVN/Show Log", po výběru jedné revize se objeví možnost "Compare with working copy", při označení právě dvou revizí se objeví "Compare revisions". Veřejná testovací repository ============================ Jen pro naši vlastní potřebu! Můžete tam cokoli zkoušet, přidávat, měnit, apod. Za data se neručí - já databázi občas promažu, když začne zabírat moc místa na disku.. svn://cgg.ms.mff.cuni.cz/test Příklady fungujících repository =============================== Veřejné projekty - read-only přístup pro kohokoli. Nejprve uvedu své projekty :-) 1. JaGrLib ---------- Středně velký projekt v jazyku Java (výukový modulární systém pro počítačovou grafiku). Využívám tam všechny vlastnosti SVN, které znám, jen "branching" jsem ještě nepotřeboval. Properties, keywords, tags, .. už ano. URL: svn://cgg.ms.mff.cuni.cz/JaGrLib 2. VUCAKO Bench --------------- Benchmark pro 32- a 64-bitové systémy (ekvivalentní algoritmy pro jazyky C++ i Java). Spousta naměřených dat na různých HW i SW platformách.. svn://cgg.ms.mff.cuni.cz/bench 3. OpenGL demo knihovna ----------------------- Pro výuku předmětu HW počítačová grafika (PGR019) na MFF UK v Praze. svn://cgg.ms.mff.cuni.cz/ogl 4. Vlastní projekt Subversion ----------------------------- Autoři ho již dlouho používají, prý nikdy nepřišli o žádná data! Dobrá inspirace. Celá repository je dost velká! (pro představu lze načíst jen "trunk"..) http://subversion.collab.net/repos/svn 5. J2EE server Geronimo ----------------------- Apache Geronimo - Javovský server. Ohromná repository, přes 200000 revizí. http://svn.apache.org/repos/asf/geronimo 6. Samba projekt ---------------- Známý projekt - klient a server pro SMB/CIFS služby. svn://svnanon.samba.org/samba 7. PuTTY -------- Oblíbená implementace SSH/telnet protokolů pro Win32. Používají SVN už od roku 1999! svn://ixion.tartarus.org/main/putty 8. Mono ------- .NET prostředí pro jiné platformy (Linux, ..). Velmi rozsáhlý projekt, veliká repository: svn://mono.myrealbox.com/source A mnoho dalších --------------- Viz např. http://subversion.tigris.org/testimonials.html#open-source-projects-using-svn