Subversion w akcji

Nadszedł czas, aby przejść od streszczenia do konkretów. W tej sekcji, wyświetlimy jak wykorzystywać Subversion w praktyce.

Adresy URL repozytorium Subversion

W niniejszej książce, Subversion używa adresów URL w celu zidentyfikowania wersji plików i katalogów w repozytorium Subversion. W większości tych adresów używa się standardowej składni, umożliwiając określenie nazwy serwera i portu jako część adresu URL:

$ svn checkout http://svn.example.com:9834/repos
…

Jednak istnieją pewne niuanse w obsłudze adresów URL przez Subversion, które są godne uwagi. Na przykład adresy zawierające file:// (metoda dostępu używana dla lokalnego repozytorium) muszą zawierać albo nazwę serwera localhost lub bez żadnej nazwy:

$ svn checkout file:///var/svn/repos
…
$ svn checkout file://localhost/var/svn/repos
…

Ponadto, użytkownicy korzystający z URL file:// na platformie Windows będą musieli korzystać z nieoficjalnie „standardowej” składni dostępu do repozytoriów, które są na tej samej maszynie, ale na innym dysku niż kopia robocza. Oba poniższe przykłady będą działać w przypadku dysku o literze X:

C:\> svn checkout file:///X:/var/svn/repos
…
C:\> svn checkout "file:///X|/var/svn/repos"
…

W drugim przykładzie adres URL musi być objęty cudzysłowem, tak aby pionowa kreska nie była interpretowana (jako pipe). Należy również pamiętać, że w adresie URL zastosowano ukośniki zamiast backslash.

[Notatka] Notatka

Nie możesz korzystać z URL file:// w swojej przeglądarce, ponieważ przeglądarka będzie próbowała zlokalizować konkretny plik na dysku. Subversion korzysta z własnego systemu plików (zobacz „Repository Layer”), a przeglądarka nie wie jak z niego korzystać.

Klient Subversion automatycznie zakoduje adresy URL jak konieczne, tak jak w przeglądarce internetowej. Na przykład, jeśli adres URL zawiera spacje lub ogonki, jak w następujących przykładach:

$ svn checkout "http://host/path with space/project/españa"

Subversion zamieni znaki specjalne na to co poniżej:

$ svn checkout http://host/path%20with%20space/project/espa%C3%B1a

Jeśli adres URL zawiera spacje, należy umieścić go wewnątrz cudzysłowu tak, aby powłoka shell traktowała wszystko jako jeden argument do programu svn.

W Subversion 1.6, wprowadzono nowy znak (^), który służy jako zamiennik dla „adresu URL w kopi roboczej”. Dla przykładu:

$ svn list ^/tags/bigsandwich/

W tym przykładzie, skonstruowano adres URL dla /tags/bigsandwich w głównym katalogu repozytorium. Zauważ, że ten mechanizm działa wyłącznie kiedy znajdujesz się w katalogu, który jest kopią roboczą repozytorium. Klient svn sam pobiera dokładny adres URL repozytorium z wcześniej zapisanych metadanych.

Kopie robocze repozytorium

Już czytałeś o kopiach roboczych, teraz zobaczysz w jaki sposób klient Subversion tworzy i używa je.

Kopia robocza klienta svn jest zwykłym drzewem katalogów na dysku lokalnym, zawierający zbiór plików. Możesz edytować te pliki, a w przypadku gdy jest to kod źródłowy, możesz skompilować program w standardowy sposób. Kopia robocza jest twoim prywatnym miejscem na wprowadzanie zmian. Subversion automatycznie nie prześle tych zmian do innych użytkowników, dopóki nie zażądasz tego sam poprzez wykonanie odpowiedniej komendy svn. Możesz mieć wiele kopi roboczych tego samego projektu.

Po wprowadzeniu pewnych zmian do plików i sprawdzeniu, że działają poprawnie, Subversion udostępnia komendy pozwalające na „opublikowanie” zmian innym użytkownikom poprzez zapisanie tych zmian do repozytorium. W przypadku gdy inni użytkownicy opublikują swoje zmiany, Subversion udostępnia komendy do ich pobrania i scalenia z twoją kopią roboczą.

Kopia robocza zawiera także dodatkowe pliki, utworzone i utrzymywane przez Subversion. Każdy katalog w kopi roboczej zawiera podkatalog nazwany .svn, zwany również jako katalog administracyjny. Pliki w katalogu administracyjnym (.svn) pozwalają Subversion rozpoznać, które pliki zostały zmienione i które są już nieaktualne z repozytorium.

Zazwyczaj w repozytorium znajduje się kilka projektów jako podkatalogi. W takim wypadku użytkownik może wykonać kopię roboczą tylko jednego konkretnego podkatalogu z repozytorium.

Dla przykładu, załóżmy, że masz repozytorium, które zawiera dwa projekty oprogramowania, paint i calc. Każdy z nich umieszczony w podkatalogu w repozytorium, jak pokazano w Rysunek 1.6, „Struktura repozytorium”.

Rysunek 1.6. Struktura repozytorium

Struktura repozytorium

Aby uruchomić kopie roboczą repozytorium, należy najpierw wykonać check out repozytorium. (Termin check out może brzmieć jak rezerwacja środków lub zwolnienie blokad, ale nie, to po prostu stworzenie prywatnej kopii projektu.) Na przykład, jeśli wykonasz check out /calc, otrzymasz kopie roboczą jak pokazano:

$ svn checkout http://svn.example.com/repos/calc
A    calc/Makefile
A    calc/integer.c
A    calc/button.c
Checked out revision 56.

$ ls -A calc
Makefile  button.c integer.c .svn/

Na powyższej liście znak A po lewej wskazuje, że Subversion dodaje plik/katalog do twojej kopii roboczej. W tym momencie masz kopie roboczą repozytorium z dodatkowym katalogiem .svn, który zawiera dodatkowe informacje wykorzystywane przez Subversion, jak wspomniano wcześniej.

Przypuśćmy, że wprowadzasz zmiany do button.c. Ponieważ katalog .svn zapamiętuje daty ostatniej edycji i zawartość, Subversion może poinformować, że dokonano zmiany w pliku. Jednak musisz wykonać odpowiednie polecenie by zmiany były opublikowane do reszty użytkowników.

Aby opublikować swoje zmiany do repozytorium, używa się polecenia svn commit:

$ svn commit button.c -m "Poprawiono literówkę w button.c."
Sending        button.c
Transmitting file data .
Committed revision 57.

Teraz zmiany w button.c zostały przesłane do repozytorium razem z opisem zmian (poprawiona literówka). Jeśli inny użytkownik pobierze z repozytorium /calc ze zmianami (svn checkout), to będzie on widział wersję pliku z najnowszą poprawką.

Załóżmy, że masz współpracowniczkę, Sally, która pobiera w tym samym momencie co ty, projekt /calc. Gdy wyślesz swoje zmiany do repozytorium, Sally nie będzie tych zmian widzieć dopóki sama nie zsynchronizuje swoją kopie roboczą z repozytorium.

W celu zapewnienia Sally, że jej projekt jest aktualny, może wykonać aktualizację swojej kopii roboczej. Do tego celu przyda się polecenie svn update. Spowoduje to włączenie twoich zmian do jej kopii roboczej, a także pozostał zmian wprowadzanych od ostatniego sprawdzenia projektu.

$ pwd
/home/sally/calc

$ ls -A
Makefile button.c integer.c .svn/

$ svn update
U    button.c
Updated to revision 57.

Wyjście z polecenia svn update wskazuje, że Subversion zaktualizował zawartość pliku button.c. Sally nie musiała określać, który plik chce zaktualizować, Subversion używa informacji zawartych w katalogu administracyjnym (.svn), jak i w samym repozytorium i na podstawie tych informacji Subversion pobiera tylko i wyłącznie te informacje, które są potrzebne do odwzorowania na dysku kopii roboczej repozytorium.

Wersje (Revisions)

Wydanie polecenia svn commit powoduje rozpoczęcie wysłania zmian do wielu plików i katalogów jako pojedyncza operacja. W swoim katalogu kopii roboczej możesz edytować, tworzyć, usuwać, zmieniać nazwy i kopiować pliki jak i katalogi, a następnie wysłać te zmiany jako jedna atomowa operacja (wersja).

Atomowe transakcje oznaczają po prostu to, że: albo wszystkie zmiany zostaną zapisane, albo żadne z nich. Subversion próbuje utrzymać atomowość operacji nawet w obliczu gdy coś ulegnie awarii, system się zawiesi, problemy z siecią lub inne niemiłe zdarzenia.

Za każdym razem, gdy repozytorium akceptuje zmiany od użytkownika, tworzy nowy stan drzewa plików i nazywa tę zmianę wersja nadając unikalny numer wersji (o jeden większy od poprzedniej wersji). Początkowa wersja nosi numer 0 i składa się z pustego głównego katalogu.

Rysunek 1.7, „Repozytorium” przedstawia w prosty sposób repozytorium. Wyobraź sobie szereg numerów wersji, zaczynając od 0, od lewej do prawej. Każda wersja posiada swoje drzewo plików, a każda z nich przedstawia kopię lustrzaną po wgraniu zmian przez użytkownika.

Rysunek 1.7. Repozytorium

Repozytorium

Należy pamiętać, że kopia robocza nie odpowiada dokładnie jednej wersji z repozytorium. Kopia robocza może zawierać pliki z kilku różnych korekt. Na przykład załóżmy, pobierasz projekt z repozytorium, który nosi numer wersji 4:

calc/Makefile:4
     integer.c:4
     button.c:4

W tym momencie, ten katalog kopii roboczej odpowiada dokładnie wersji 4 w repozytorium. Załóżmy jednak, że dokonujesz zmiany w button.c i wysyłasz zmiany do repozytorium. Jeśli nie było wysłanych poprawek w międzyczasie, to w repozytorium jest tworzona wersja 5, a twoja kopia robocza będzie wyglądać następująco:

calc/Makefile:4
     integer.c:4
     button.c:5

Załóżmy, że w tym momencie Sally przesyła własne zmiany do integer.c, tworząc wersję 6. Jeśli wykonasz svn update by synchronizować kopię roboczą z repozytorium, to będzie wyglądać następująco:

calc/Makefile:6
     integer.c:6
     button.c:6

Zmiany Sally w integer.c będą widoczne w twojej kopii roboczej, a twoja zmiana w button.c będzie nadal widoczna. W tym przykładzie, zawartość Makefile jest identyczna w wersjach 4,5 i 6, ale Subversion oznaczy plik wersją 6, aby oznaczyć, że jest on nadal aktualny.

Jak kopie robocze współpracują z repozytorium

Dla każdego pliku w katalogu, Subversion zapisuje dwie istotne informacje w .svn:

  • Z której wersji plik się wywodzi. (jest to tak zwana robocza wersja pliku)

  • Data i czas ostatniej modyfikacji danego pliku na dysku lokalnym podczas aktualizacji z repozytorium

Biorąc pod uwagę te informacje, podczas odpytywanie repozytorium, Subversion może stwierdzić, które z następujących stanów odpowiada danemu plikowi:

Bez poprawek, aktualny z repozytorium

Plik jest niezmieniony w katalogu, a także nie zostały przesłane żadne poprawki do repozytorium od ostatniej wersji. Polecenie svn commit i svn update pominą plik i nic z nim nie zrobią.

Wprowadzone poprawki lokalnie, aktualny z repozytorium

Plik został zmieniony w katalogu, natomiast żadne zmiany nie pojawiły się w repozytorium od ostatniej aktualizacji. Istnieją lokalne zmiany, które nie zostały włączone do repozytorium, poprzez wykonanie polecenia svn commit. Wykonanie polecenie svn commit prześle poprawki lokalne do repozytorium, a polecnie svn update nie zrobi nic w przypadku tego pliku.

Bez poprawek, nieaktualne z repozytorium

Plik nie został zmieniony w katalogu kopii roboczej, ale został zmieniony w repozytorium. Plik mógłby być zaktualizowany w celu uzyskania identycznej zawartości pliku jak w repozytorium. Polecenie svn commit pozostawi plik bez jakiejkolwiek zmiany, a svn update wprowadzi zmiany do pliku znajdujące się w repozytorium.

Wprowadzone poprawki lokalnie, nieaktualne z repozytorium

Plik został zmieniony zarówno lokalnie w kopii roboczej jak i w repozytorium. Polecenie svn commit zakończy się niepowodzeniem z błędem „out-of-date (nieaktualny)”. Plik powinien być najpierw zaktualizowany za pomocą polecenia svn update, Subversion będzie starał się automatycznie scalić zmiany z twoja wersją pliku. Jeśli Subversion nie uda się ten proces, zostawi zmiany oznaczając je jako konflikt. Jak wcześniej wspomniano konflikty rozwiązuje użytkownik ręcznie.

Może to brzmi skomplikowanie, ale polecenie svn status pokaże stan jakiejkolwiek pozycji w kopii roboczej. Aby uzyskać więcej informacji na temat tego polecenia, zobacz „Zobacz przegląd zmian”.

Mieszane wersje w kopii roboczej

Ogólnie, Subversion stara się być elastycznym dla użytkownika jak to tylko możliwe. Jednym rodzajem z tej elastyczności jest możliwość przechowywania w kopii roboczej kilku wersji danych. Niestety, ta elastyczność może zmylić wielu nowych użytkowników. Jeśli poprzedni przykład pokazujący mieszane wersje wprawił cie w zakłopotanie, to prezentujemy wytłumaczenie dlaczego ta funkcja istnieje i jak z niej korzystać.

Operacje pobierania (update) i publikowania (commit) zmian z/do repozytorium są rozłączne

Jedną z podstawowych zasad jest to, że Subversion wykonując operację „publikowania” to te działanie nie powoduje „pobrania” zmian, ani na odwrót. Publikując nowe zmiany do repozytorium, nie oznacza to, że jesteś gotowy pobrać poprawki od innych użytkowników. A jeśli jesteś w toku wprowadzania zmian to polecenie svn update nie opublikuje je, tylko pobierze nowe zmiany od innych użytkowników.

Głównym efektem ubocznym tej zasady jest fakt, że Subversion musi zapisywać dodatkowe informacje w postaci wersji plików. Jest to bardziej skomplikowane ze względu na to, że katalogi również są wersjonowane.

Załóżmy, że masz kopię roboczą w wersji numer 10. Edytujesz plik foo.html, a następnie wykonujesz polecenie svn commit, które tworzy wersję 15 w repozytorium. Po poprawnym wykonaniu się polecenia, wielu nowych użytkowników spodziewało by się, że cała kopia robocza będzie w wersji 15, ale tak się nie stało!Pomiędzy wersją 10 a 15 mogło dojść do kilku lub kilkudziesięciu zmian o których użytkownik nic nie będzie wiedział, ponieważ nie wykonał polecenia svn update, a polecenie svn commit nie pobiera tych zmian do kopii roboczej.Gdyby polecenie svn commit zarówno pobierało zmiany od innych użytkowników, to można by oznaczyć wszystkie pliki w projekcie jako wersja 15. Ale wtedy łamana by była zasada rozdzielenia operacji wysyłania i pobierania. Dlatego też klient Subversion oznacza plik foo.html jako wersja numer 15. Reszta plików i katalogów jako numer wersji 10. Tylko gdy się wykona polecenie svn update, które pobierze zmiany z repozytorium, a wtedy cała kopia robocza może być oznaczona jako numer wersji 15.

Mieszane numery wersji dla plików w kopii roboczej to nic nadzwyczajnego

Faktem jest, że za każdym razem po uruchomieniu polecenia svn commit kopia robocza otrzymuje mieszane numery wersji plików. Te pliki które dopiero co wysłałeś do repozytorium, otrzymują najwyższy numer roboczej wersji. Po kilkunastu wysłanych svn commit otrzymasz w repozytorium miks różnych wersji. Nawet, jeśli jesteś jedyną osobą, korzystającą z repozytorium, będziesz mógł nadal zaobserwować takie zjawisko. Aby zobaczyć dokładnie status twoich plików w folderze kopii roboczej, skorzystaj z polecenia svn status z argumentem --verbose (-v) (zobacz „Zobacz przegląd zmian” po więcej informacji).

Często, nowi użytkownicy są zupełnie nieświadomi, że ich kopie robocze zawierają mieszane wersje. Może to być mylące, ponieważ wiele poleceń jest wrażliwych na zawartość plików i ich wersje. Przykładowo, svn log jest używane do wyświetlenia historii zmin w pliku lub katalogu. (patrz „Generowanie historii zmian w SVN”). Gdy użytkownik wykonuje to polecenie na jakimś obiekcie w katalogu kopii roboczej, spodziewa się, że zobaczy całą historię obiektu. Ale jeśli numer wersji obiektu jest stary (często z powodu nie uruchamiania svn update), to historia będzie dotyczyć starej wersji obiektu.

Mieszane wersje są przydatne

Jeśli twój projekt jest wystarczająco skomplikowany, docenisz czasem możliwość cofnięcia się w czasie w przypadku jakiegoś obiektu. Nauczysz się tego w Rozdział 2, Podstawy użytkowania Subversion. Być może będziesz chciał przetestować jakiś moduł z wcześniejszej wersji, lub będziesz chciał sprawdzić kiedy jakiś błąd powstał pierwszy raz w konkretnym pliku (i w dodatku przez kogo został popełniony). To jest tzw. „wehikuł czasu” funkcja systemów kontroli wersji, która pozwala na przenoszenie jakichkolwiek części projektu w przód i w tył historii.

Mieszane wersje mają ograniczenia

Nawet gdy możesz wykorzystać mieszane numery wersji plików w kopii roboczej, istnieją ograniczenia w tej elastyczności.

Nie możesz przesłać „usunięcia” jakiegoś pliku lub katalogu, które nie są aktualne z repozytorium. Jeśli istnieje nowsza wersja obiektu w repozytorium, to twoje próby usunięcia go zostaną odrzucone, by uniemożliwić przypadkowego zniszczenia zmian, które nie były widziane.

Po drugie, nie można wysyłać zmian metadanych plików i katalogów jeśli nie były aktualne z repozytorium. Będziesz poznawać jak dołączać „opcje” do obiektów w Rozdział 3, Advanced Topics. Katalog roboczy określa zbiór szczególnych zapisów i właściwości, a więc przesłanie opcji (właściwości) dla katalogu nieaktualnego, mogłoby spowodować nadpisanie właściwości nie widzianych przez ciebie.