Podstawowy cykl pracy z Subversion (SVN)

Subversion posiada liczne funkcje, opcje, dzwonki i gwizdki, ale na co dzień zapewne będziesz wykorzystywać zaledwie kilka z nich. W tym rozdziale znajdziesz scharakteryzowane te, które mogą znaleźć się w codziennej pracy z Subversion.

Typowy cykl pracy wygląda tak:

  1. Zaktualizuj kopię roboczą.

    • svn update

  2. Wprowadzanie zmian.

    • svn add

    • svn delete

    • svn copy

    • svn move

  3. Przeglądanie wprowadzonych zmian.

    • svn status

    • svn diff

  4. Być może cofnięcie pewnych zmian.

    • svn revert

  5. Rozwiązywanie konfliktów (scalanie innych zmian).

    • svn update

    • svn resolve

  6. Przesłanie zmian.

    • svn commit

Synchronizacja (aktualizacja) kopii roboczej

Pracując w grupie nad projektem, będziemy musieli pobrać zmian z repozytorium, które wysłali inni uczestnicy projektu. Użyj svn update aby kopia robocza została zsynchronizowana z repozytorium i najnowszymi zmianami:

$ svn update
U  foo.c
U  bar.c
Updated to revision 2.

W tym przypadku najprawdopodobniej ktoś wgrał do repozytorium zmiany w plikach foo.c i bar.c. Zmiany te pojawiły się od ostatniej synchronizacji kopii roboczej z repozytorium.

Podczas gdy serwer wysyła zmiany z repozytorium do kopii roboczej, przy każdym pliku jest wyświetlana litera – kod oznaczający jaka operacja została wykonana na pliku by doprowadzić go do postaci zsynchronizowanej z repozytorium. Aby dowiedzieć się, jakie znaczenie mają te litery, uruchom polecenie svn help update.

Wprowadzanie zmian w kopii roboczej

Teraz można rozpocząć pracę przy projekcie i wprowadzać zmiany w kopii roboczej. To moment odpowiedni na wprowadzanie nowych funkcjonalności, aplikowanie poprawek itp. Podczas tego etapu przydatnymi komendami okazać mogą się następujące: svn add, svn delete, svn copy, svn move, svn mkdir. Jednakże, jeśli edytujesz plik już znajdujący się w Subversion, prawdopodobnie nie użyjesz tych poleceń.

Można dokonać dwóch rodzajów zmian w kopii roboczej: zmiany na plikach oraz zmiany w strukturze katalogowej. Nie potrzeba informować Subversion o zmianach w plikach, wystarczy wykonać zmiany przy użyciu edytora tekstu, grafiki, programu, lub inne narzędzie, które używasz. Subversion automatycznie wykrywa pliki, które uległy zmianie, ponadto, obsługuje pliki binarne równie łatwo jak pliki tekstowe. Zmiany na drzewie (katalogach) są wykonywane natychmiast w kopii roboczej. Możesz usuwać, kopiować, przesuwać katalogi, lecz dopiero po wykonaniu polecenia svn commit, zmiany te będą widoczne w repozytorium.

Oto przegląd pięciu poleceń Subversion, które będziesz używać podczas modyfikowania struktury katalogowej:

svn add foo

Dodaje plik, katalog lub dowiązanie symboliczne foo do kolejki obiektów, które zostaną dodane do repozytorium. Przy kolejnym wykonaniu polecenie svn commit, foo stanie się potomkiem nadrzędnego katalogu. Należy pamiętać, że jeśli foo jest katalogiem, wszystko co w nim jest zawarte, również zostanie dodane do repozytorium. Jeśli chcesz dodać sam katalog foo, przekaż dodatkowo opcję --depth empty.

svn delete foo

Dodaje plik, katalog lub dowiązanie symboliczne foo do kolejki obiektów, które zostaną usunięte z repozytorium. Jeśli foo jest plikiem lub dowiązaniem symbolicznym, jest od razu usuwany z kopii roboczej. Jeśli foo to katalog, jest dopiero usuwany przy wykonaniu polecenia svn commit, zarówno z kopii roboczej jak i z repozytorium. [3]

svn copy foo bar

Tworzy nowy obiekt bar jako duplikat foo i dodaje bar do kolejki obiektów, które zostaną dodane w repozytorium. Podczas wykonywania polecenia svn commit, historia pliku bar będzie identyczna jak pliku foo. svn copy nie tworzy pośrednich katalogów, dopóki nie dodasz opcji --parents.

svn move foo bar

To polecenie działa podobnie jak, svn copy foo bar; svn delete foo. Oznacza to, że bar zostanie dodane do repozytorium jako kopia foo, a foo zostanie usunięte. svn move nie tworzy pośrednich katalogów, dopóki nie dodasz opcji --parents.

svn mkdir blort

Działa identycznie jak wykonanie poleceń: mkdir blort; svn add blort. To znaczy, że nowy katalog jest tworzony i przy kolejnym wykonaniu polecenia svn commit zostanie dodany do repozytorium.

Wyświetlanie i kontrolowanie wprowadzonych zmian za pomocą poleceń SVN

Po zakończeniu wprowadzania zmian, należy przesłać je do repozytorium, ale zanim to zrobisz, warto przeglądnąć co się zmieniło i prześledzić te zmiany. Przeglądając wprowadzone zmiany, można stworzyć dokładniejszą wiadomość opisującą zmiany. Możesz też odkryć błędnie wprowadzoną zmianę i ją cofnąć przed wgraniem do repozytorium. Dodatkowo, to dobry moment by przyjrzeć się wprowadzonym zmianą przed ich opublikowaniem. Przegląd zmian możesz zobaczyć przy użyciu polecenia svn status, a szczegóły tych zmian zobaczysz za pomocą polecenia svn diff.

Subversion został zoptymalizowany by pomóc w realizacji tego zadania, jest w stanie zrobić wiele rzeczy, bez komunikowania się z repozytorium. Dokładniej mówiąc, twoja kopia robocza zawiera ukrytą „nietkniętą” wersję każdego obiektu. Dzięki temu, Subversion może w szybki sposób wyświetlić które pliki zostały zmienione, a nawet pozwala na cofnięcie zmian, bez konieczności łączenia się z repozytorium.

Zobacz przegląd zmian

Aby przeglądać zmiany, będziemy używać polecenia svn status. Prawdopodobnie będzie to najczęściej wykorzystywane polecenie niż jakiekolwiek inne polecenie Subversion.

Po wykonaniu w głównym katalogu kopii roboczej polecenia svn status bez dodatkowych argumentów, wynik przedstawi pliki i katalogi, które uległy zmianie. Poniżej zostały przedstawione przykładowe wyniki wykonania polecenia svn status. (Należy pamiętać, że tekst poprzedzony znakiem # nie jest faktycznie wyświetlony przez svn status, a służy tylko opisowi/komentarzą.)

?       scratch.c           # plik nie jest w ramach kontroli wersji
A       stuff/loot/bloo.h   # plik jest w kolejce do dodania
C       stuff/loot/lump.c   # plik jest w konflikcie po wykonaniu update
D       stuff/fish.c        # plik jest dodany do kolejki plików usuniętych
M       bar.c               # plik bar.c został zmodyfikowany, ale zmiany nie zostały przesłane do repozytorium

W wyniku wykonania polecenia svn status wyświetlane jest sześć kolumn znaków, następnie nazwa katalogu lub pliku. Pierwsza kolumna przedstawia status pliku lub katalogu lub/i zawartości. Wszystkie kody zostały przedstawione szczegółowo poniżej:

A obiekt

Plik, katalog lub dowiązanie symboliczne obiekt został zaplanowany do dodania przy następnym commit.

C obiekt

Plik obiekt jest w stanie konfliktu. Oznacza to, że zmiany otrzymane z repozytorium nakładają/pokrywają się ze zmianami lokalnymi, które wprowadziłeś do kopii roboczej. Konflikt nie został automatycznie rozwiązany. Musisz ręcznie rozwiązać ten konflikt zanim będzie możliwe wgranie lokalnych zmian do repozytorium.

D obiekt

Plik, katalog lub dowiązanie symboliczne obiekt został skolejkowane do usunięcia z repozytorium.

M obiekt

Zawartość pliku obiekt zostało zmodyfikowane.

Jeśli podasz dokładną ścieżkę do polecenia svn status, otrzymasz informacje tylko o konkretnej ścieżce:

$ svn status stuff/fish.c
D      stuff/fish.c

svn status ma również opcje --verbose (-v), dzięki czemu w wyniku zostaną wyświetlone wszystkie obiekty, nawet te bez zmian:

$ svn status -v
M               44        23    sally     README
                44        30    sally     INSTALL
M               44        20    harry     bar.c
                44        18    ira       stuff
                44        35    harry     stuff/trout.c
D               44        19    ira       stuff/fish.c
                44        21    sally     stuff/things
A                0         ?     ?        stuff/things/bloo.h
                44        36    harry     stuff/things/gloo.c

To jest rozszerzona wersja wyniku wykonania polecenia svn status. Znaki w pierwszej kolumnie mają to samo znaczenie jak opisano wcześniej. Natomiast druga kolumna oznacza aktualną wersję obiektu w kopii roboczej. Trzecia i czwarta kolumna oznaczają numer wersji i autora ostatniej edycji.

Żaden z powyższych przykładów nie łączył się z repozytorium – zamiast tego Subversion porównywało pliki z zapisanymi metadanymi w katalogu .svn. Istnieje opcja --show-updates (-u), która łączy się z repozytorium i uzupełnia wynik wykonania się polecenia o informacje o tym czy obiekt jest aktualny:

$ svn status -u -v
M      *        44        23    sally     README
M               44        20    harry     bar.c
       *        44        35    harry     stuff/trout.c
D               44        19    ira       stuff/fish.c
A                0         ?     ?        stuff/things/bloo.h
Status against revision:   46

Zwróć uwagę na dwie gwiazdki: gdybyś w tym momencie uruchomił polecenie svn update, pliki README i trout.c zostałyby zaktualizowane. Te gwiazdki są użyteczną informacją. Musisz pobrać aktualizacje tych plików zanim wykonasz commit. W innym przypadku repozytorium zwróci błąd (out of date).

svn status może wyświetlić o wiele więcej przydatnych informacji. Przedstawione zostały najważniejsze, a resztę możesz zobaczyć w sekcji svn status.

Przeglądanie lokalnie wprowadzonych zmian

Jeszcze inny sposób na przegląd wprowadzonych zmian to polecenie svn diff. Dzięki temu poleceniu możesz dowiedzieć się dokładnie co zostało zmodyfikowane. To polecenie zwraca standardowy format różnic w plikach znany jako unified diff format:

$ svn diff
Index: bar.c
===================================================================
--- bar.c	(revision 3)
+++ bar.c	(working copy)
@@ -1,7 +1,12 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <stdio.h>

 int main(void) {
-  printf("Sixty-four slices of American Cheese...\n");
+  printf("Sixty-five slices of American Cheese...\n");
 return 0;
 }

Index: README
===================================================================
--- README	(revision 3)
+++ README	(working copy)
@@ -193,3 +193,4 @@
+Note to self:  pick up laundry.

Index: stuff/fish.c
===================================================================
--- stuff/fish.c	(revision 1)
+++ stuff/fish.c	(working copy)
-Welcome to the file known as 'fish'.
-Information on fish will be here soon.

Index: stuff/things/bloo.h
===================================================================
--- stuff/things/bloo.h	(revision 8)
+++ stuff/things/bloo.h	(working copy)
+Here is a new file to describe
+things about bloo.

Wyjście tego polecenia jest możliwe dzięki porównaniu twoich plików z plikami w katalogu .svn. Zawartość plików w kolejce do dodania zostanie wyświetlona w całości, a pliki w kolejce do usunięcia zostaną wyświetlone jako zawartość usunięta.

Wyjście polecenia jest formatowane w standardowym formacie diff. To znaczy, linie usunięte poprzedzone są -, dodane poprzedza znak +. Poza tym dodatkowo jest zawarta informacja o pozycji i nazwie pliku, przydatne dla programu patch. Dzięki temu, możesz generować łatki poprzez przekierowanie wyjścia z tego polecenia do pliku:

$ svn diff > patchfile

Dla przykładu, można wysłać załącznik z łatką za pomocą maila do innego programisty, aby przetestował lub sprawdził łatkę zanim wykonasz commit.

Subversion korzysta z własnego silnika wyświetlające różnice pomiędzy plikami. Jeśli chcesz skorzystać z zewnetrznej aplikacji, zadeklaruj opcje --diff-cmd, a także opcje za pomocą --extensions (-x). Dla przykładu, by zobaczyć zmiany w pliku foo.c ignorując zmiany dotyczące zmiany wielkości liter, uruchom polecenie svn diff --diff-cmd /usr/bin/diff -x "-i" foo.c.

Cofanie wproawadzonych zmian przed commitem

Z jakichś przyczyn po przeglądnięciu svn diff stwierdziłeś, że wszystko co wprowadziłeś nie nadaje się na opublikowanie do repozytorium. Może wprowadziłeś błędnie, albo łatwiej będzie zacząć od nowa.

Jest to doskonała okazja do wykorzystania svn revert:

$ svn revert README
Reverted 'README'

Subversion wycofa wprowadzone zmiany do pliku poprzez nadpisanie zmienionego pliku jego pierwotną kopią z katalogu .svn. Pamiętaj, svn revert może cofać wszystkie zmiany, dla przykładu, możesz już nie potrzebować pliku, który jest w kolejce do dodania:

$ svn status foo
?      foo

$ svn add foo
A         foo

$ svn revert foo
Reverted 'foo'

$ svn status foo
?      foo
[Notatka] Notatka

svn revert item działa identycznie jak usunięcie item z kopii roboczej, a następnie wykonanie polecenia svn update -r BASE item. Jest różnica w tych metodach, w przypadku svn revert klient Subversion nie musi się łączyć z repozytorium by odzyskać pierwotną wersję pliku.

Albo przypadkowo usunąłeś plik z kontroli wersji:

$ svn status README

$ svn delete README
D         README

$ svn revert README
Reverted 'README'

$ svn status README

Rozwiązywanie konfliktów (Aplikowanie zmian innych użytkowników)

Już wiemy jak za pomocą svn status -u można przewidzieć/zapobiec wystąpienie konfliktom. Załóżmy, uruchamiasz polecenie svn update, a w wyjściu polecenia pojawiają się takie informacje:

$ svn update
U  INSTALL
G  README
Conflict discovered in 'bar.c'.
Select: (p) postpone, (df) diff-full, (e) edit,
        (h) help for more options:

Nie zwracaj uwagę na znaki U oraz G, te pliki bez problemu „pochłonęły” zmiany z repozytorium. Pliki oznaczone literką U nie posiadały lokalnych zmian, natomiast zaktualizowano je z repozytorium. W przypadku znaku G, svn informuje, że nastąpiło scalenie zmian lokalnych z tymi pochodzącymi z repozytorium (nie pokrywały się).

Kolejne dwie linijki są częścią nowej funkcjonalności (wprowadzonej w Subversion 1.5) zwanej interaktywne rozwiązywanie konfliktu. To oznacza, że zmiany pobrane z repozytorium pokrywają się z lokalnymi poprawkami i masz możliwość rozwiązania tego konfliktu. Wyświetlono najczęściej używane opcje, ale możesz wpisać h by zobaczyć pozostałe:

…
  (p)  postpone    - oznacz jako konflikt do rozwiązania
  (df) diff-full   - wyświetl wprowadzone zmiany do scalonych plików
  (e)  edit        - zmień scalony plik w edytorze
  (r)  resolved    - akceptuj scaloną wersję pliku
  (mf) mine-full   - akceptuj moją wersję zmian (ignoruj zmiany z repozytorium)
  (tf) theirs-full – akceptuj zmiany z repozytorium (porzuć lokalne)
  (l)  launch      - uruchom zewnętrzne narzędzie do rozwiązania konfliktu
  (h)  help        - wyświetl tą listę

Pokrótce scharakteryzujmy każdą z tych opcji zanim przejdziemy do szczegółów, czym dokładnie one się zajmują.

(p)ostpone

Pozostaw plik w konflikcie, który rozwiązany będzie po wysłaniu pozostałych zmian do repozytorium.

(d)iff-(f)ull

Pokaż różnice pomiędzy plikiem lokalnym, a znajdującym się w repozytorium (w standardowym formacie diff).

(e)dit

Otwórz plik w ulubionym edytorze, jak ustawiono w zmiennej środowiskowej EDITOR.

(r)esolved

Po zmianie pliku, przekaż do svn, że rozwiązałeś występujący konflikt i że plik może już w takiej postaci być zapisany w repozytorium.

(m)ine-(f)ull

Odrzuć nowe zmiany z repozytorium i pozostaw lokalnie wprowadzone zmiany dla rozważanego pliku.

(t)heirs-(f)ull

Zignoruj zmiany lokalne dla rozważanego pliku, pozostaw natomiast zmiany otrzymane z repozytorium.

(l)aunch

Uruchom zewnętrzne narzędzie do rozwiązania konfliktu. Wymaga trochę przygotowania przed tym.

(h)elp

Wyświetla wszystkie możliwe polecenia, które możesz użyć podczas rozwiązywania konfliktu.

Teraz opiszemy szczegółowiej każde z tych poleceń, grupując je o podobnej funkcjonalności.

Interaktywne wyświetlanie nachodzących na siebie zmian (konfliktów)

Zanim uderzysz z jakimś rozwiązaniem konfliktu, sprawdź co jest jego powodem – wyświetl różnice za pomocą polecenia diff-full (df):

…
Select: (p) postpone, (df) diff-full, (e) edit,
        (h)elp for more 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
…

Pierwsza linijka w przykładzie pochodzi z wersji lokalnej przed edycją (BASE), kolejna linijka zawiera twoje zmiany, ostatnia pozycja przedstawia zmiany pobrane z repozytorium. Z takimi informacjami jesteś wstanie podjąć decyzje co do rozwiązania konfliktu.

Rozwiązanie konfliktu svn interaktywnie

Istnieją cztery różne drogi rozwiązania konfliktów—dwa z nich pozwalają na selektywny wybór scalanych zmian i ich edycje, pozostałe dwa pozwalają wybrać wersję pliku i zaakceptować zmiany.

Jeśli chcesz wybrać część swoich zmian wprowadzonych lokalnie, użyj polecenia „edit” (e), aby przejść do edytora z wprowadzonymi znacznikami konfliktów. Edycja pliku z „palca” jest jakby niskopoziomowym sposobem rozwiązywania konfliktów (zobacz więcej szczegółów o tym sposobie „Ręczne rozwiązywanie konfliktów”). Większość ludzi używa w tym przypadku ładnych graficznych narzędzi do scalania zmian.

Aby skorzystać z narzędzia do scalania zmian, musisz ustawić zmienną środowiskową SVN_MERGE lub ustawić opcje merge-tool-cmd w pliku konfiguracyjnym Subversion (zobacz szczegóły „Configuration Options”). Subversion automatycznie przekazuje cztery parametry do zdefioniowanego narzędzia: pierwotną (BASE) wersję pliku, wersję otrzymaną z repozytorium, kopię pliku zawierającą lokalnie wprowadzone zmiany oraz jako czwarty parametr scalony plik z znacznikami konfliktów. Po wszystkim, jeśli jesteś zadowolony z wprowadzonych zmian, możesz przekazać do Subversion informacje, że konflikt został rozwiązany. Użyj do tego celu polecenia „resolve” (r).

Jeśli stwierdzisz, że nie ma potrzeby łączenia zmian ze sobą, a chcesz zaakceptować zmiany z wersji własnej lub pobranej z repozytorium, użyj poleceń: dla własnych zmian „mine-full” (mf), by wybrać wersję pliku z repozytorium wpisz „theirs-full” (tf).

Opóźnione rozwiązywanie konfliktów

Podczas rozwiązywania konfliktu możesz ominąć (opóźnić) rozwiązanie konfliktu wpisując p (ang. postpone). Jeśli nie chcesz wykonywać żadnych operacji dodatkowych podczas wykonywania svn update, możesz dodać do polecenia opcje: --non-interactive, co spowoduje, że pliki w konflikcie będą oznaczone znakiem C w wyjściu programu.

Znak C oznajmia iż dany obiekt jest w konflikcie. To oznacza, że zmiany pobrane z repozytorium nadpisały część zmian wprowadzonych lokalnie. Teraz należy przejrzeć wspomniane pozycje by zdecydować, które poprawki są odpowiednie by rozwiązać konflikt. Jeśli opóźnisz rozwiązanie konfliktu (p), svn domyślnie informuje o konflikcie na trzy sposoby:

  • Subversion wyświetla znak C podczas update i zapamiętuje, który plik jest w stanie konfliktu.

  • Subversion doda specjalne znaczniki konfliktu, jeśli uzna, że zmiany mogą być naniesione na siebie. Znaczniki te to tekst rozdzielający „granice” konfliktów, tak by jasno przedstawić gdzie należy sprawdzić plik. (Subversion wykorzystuje svn:mime-type by rozpoznać czy w pliku może nanieść zmiany z znacznikami. Zobacz „File Content Type”.)

  • Dla każdego pliku będącego w konflikcie, Subversion tworzy w kopii roboczej dodatkowo trzy pliki:

    nazwapliku.mine

    To kopia Twojego pliku sprzed wykonania update – czyli bez znaczników. Ten plik zawiera wprowadzone przez ciebie ostatnie zmiany. (Jeśli Subversion uzna plik za nie możliwy do scalenia z zmianami, .mine nie zostanie utworzony, ponieważ byłby identyczny jak oryginalny w kopi roboczej.)

    nazwapliku.rOLDREV

    To wersja pochodząca z ostatniego udanego update. Czyli plik nie zawierający wprowadzonych zmian od ostatniego update.

    nazwapliku.rNEWREV

    Ten plik jest tworzony przez klienta Subversion podczas svn update i zawiera to co jest aktualnie w repozytorium.

    OLDREV jest odpowiednikiem numeru wersji pliku w katalogu .svn. Natomiast NEWREV jest odpowiednikiem numeru wersji aktualnej z repozytorium (HEAD).

Dla przykładu, Alicja wprowadza zmiany w pliku sniadanie.txt, ale jeszcze nie wysyła swoich zmian do repozytorium. Tymczasem, Dawid wysyła swoje zmiany do tego samego pliku. Alicja wykonuje update zanim wykona commit, w wyniku tego otrzymuje informacje o konflikcie, a jego rozwiązanie odkłada na później (p):

$ svn update
Conflict discovered in 'sniadanie.txt'.
Select: (p) postpone, (df) diff-full, (e) edit,
        (h)elp for more options : p
C  sniadanie.txt
Updated to revision 2.
$ ls -1
sniadanie.txt
sniadanie.txt.mine
sniadanie.txt.r1
sniadanie.txt.r2

W tym momencie, Subversion nie zezwoli Alicji na wysłanie zmian z pliku sniadanie.txt, dopóki nie zostaną usunięte tymczasowe trzy pliki:

$ svn commit -m "Dodanie paru nowych rzeczy"
svn: Commit failed (details follow):
svn: Aborting commit: '/home/alicja/svn-work/sniadanie.txt' remains in conflict

Jeśli pozostawiłeś rozwiązanie konfliktu na później, musisz rozwiązać konflikt zanim Subversion pozwoli na wysłanie tych zmian. Użyj komendy svn resolve i np. opcje --accept.

Jeśli chcesz wybrać wersję pliku sprzed wprowadzenia własnych zmian, podaj base jako argument.

Jeśli chcesz wybrać wersję pliku zawierającą wyłącznie wprowadzone zmiany przez ciebie, podaj mine-full jako argument.

Jeśli chcesz wybrać wersję pliku zawierającą wyłącznie zmiany pochodzące z repozytorium, podaj theirs-full jako argument.

Jednakże, gdybyś chciał wyświetlić i wybrać własne zmiany oraz te pochodzące z repozytorium, a następnie je wprowadzić ręcznie (poprzez edycję pliku i znaczników konfliktów znajdujących się w nim), podaj working jako argument.

svn resolve usuwa wspomniane wcześniej trzy pliki tymczasowe i akceptuje wersję pliku, która podasz jako argument do opcji --accept. Subversion oznaczy plik jako nie będący dłużej w konflikcie:

$ svn resolve --accept working sniadanie.txt
Resolved conflicted state of 'sniadanie.txt'

Ręczne rozwiązywanie konfliktów

Łączenie zmian metodą ręczną, może wydawać się za pierwszym razem strasznym przeżyciem. Razem z praktyką, stanie się to coraz łatwiejszym sposobem na rozwiązanie konfliktu.

Dla przykładu. Z powodu niezrozumienia, ty i Alicja oraz współpracownik, edytujecie plik sniadanie.txt w tym samym czasie. Alicja wysyła własne zmiany, a kiedy ty wykonujesz update swojej kopii roboczej, otrzymujesz konflikt. Będziesz musiał wyedytować sniadanie.txt, by rozwiązać konflikt. Po pierwsze, spójrzmy na zawartość tego pliku:

$ cat sniadanie.txt
Top piece of bread
Mayonnaise
Lettuce
Tomato
Provolone
<<<<<<< .mine
Salami
Mortadella
Prosciutto
=======
Sauerkraut
Grilled Chicken
>>>>>>> .r2
Creole Mustard
Bottom piece of bread

Ciąg znaków składający się z znaków mniejszy niż, znaku równości oraz znaków większy niż, są znacznikami konfliktów i nie należą do treści pliku w konflikcie. Musisz pamiętać o ich usunięciu przed wysłaniem poprawek do repozytorium. Treść pomiędzy dwoma pierwszymi znacznikami konfliktu, to zmiany wprowadzone przez ciebie:

<<<<<<< .mine
Salami
Mortadella
Prosciutto
=======

Tekst pomiędzy drugim, a trzecim znacznikiem, to zmiany wprowadzone przez Alicję:

=======
Sauerkraut
Grilled Chicken
>>>>>>> .r2

Zazwyczaj rozwiązanie konfliktu nie będzie polegać tylko na usunięciu znaczników i zmian Alicji—byłaby zdziwiona kiedy by pobrała nową wersje, a jej zmiany by znikły. Po przeglądnięciu zmian, należy je zmodyfikować, połączyć, a następnie usunąć znaczniki konfliktów:

Top piece of bread
Mayonnaise
Lettuce
Tomato
Provolone
Salami
Mortadella
Prosciutto
Creole Mustard
Bottom piece of bread

Teraz wykonaj polecenie svn resolve, teraz możesz już normalnie wysłać plik do repozytorium za pomocą polecenia svn commit:

$ svn resolve --accept working sniadanie.txt
Resolved conflicted state of 'sniadanie.txt'
$ svn commit -m "Moja wersja sniadania"

Zauważ, że svn resolve, wymaga podania nazwy pliku, który ma być wyprowadzony z konfliktu. Zwróć uwagę przy wykonywaniu tego polecenia, ponieważ pliki tymczasowe będą usunięte, a svn pozwoli na wysłanie zmian do repozytorium—nawet jeśli w pliku znajdują się znaczniki konfliktów.

Jeśli kiedykolwiek zamieszasz się podczas edycji pliku w konflikcie, możesz zawsze podglądnąć zawartość trzech plików tymczasowych. Możesz również wykorzystać zewnętrzne narzędzie do analizowania właśnie tych plików.

Odrzucenie własnych zmian na poczet pobranych z repozytorium

Jeśli wprowadzone zmiany powodują konflikt i zdecydujesz, że jednak te zmiany chcesz porzucić i przyjąć to co jest w repozytorium, uruchom polecenie: svn resolve --accept theirs-full ŚCIEŻKA, spowoduje to porzucenie twoich zmian i usunięcie tymczasowych plików:

$ svn update
Conflict discovered in 'sniadanie.txt'.
Select: (p) postpone, (df) diff-full, (e) edit,
        (h) help for more options: p
C    sniadanie.txt
Updated to revision 2.
$ ls sniadanie.*
sniadanie.txt  sniadanie.txt.mine  sniadanie.txt.r2  sniadanie.txt.r1
$ svn resolve --accept theirs-full sniadanie.txt
Resolved conflicted state of 'sniadanie.txt'

Użycie svn revert

Jeśli zdecydujesz, że chcesz porzucić własne zmiany i rozpocząć wprowadzanie zmian od nowa (czy to z powodu konfliktu, czy z innego powodu), po prostu cofnij wprowadzone zmiany:

$ svn revert sniadanie.txt
Reverted 'sniadanie.txt'
$ ls sniadanie.*
sniadanie.txt

Zauważ, że przy wykonaniu svn revert pliku będącego w konflikcie, nie musisz już użyć polecenia svn resolve.

Commitowanie zmian

W końcu! Zakończyłeś edycje, scaliłeś je z zmianami z repozytorium i jesteś gotowy przesłać własne.

Polecenie svn commit wysyła wszystkie wprowadzone zmiany do repozytorium. Kiedy wykonujesz to polecenie, musisz podać wiadomość (log) opisującą zmiany. Wiadomość będzie powiązana z nową wersją w repozytorium. Jeśli wiadomość jest krótka, możesz ją wprowadzić bezpośrednio w linii poleceń, jako wartość opcji --message (-m):

$ svn commit -m "Poprawiono liczbę kawałków sera"
Sending        sniadanie.txt
Transmitting file data .
Committed revision 3.

Natomiast, kiedy zapisujesz informacje o tym co zmieniasz w pliku, możesz przekazać do klienta Subversion wiadomość właśnie z tego pliku. Podaj nazwę pliku do opcji --file (-F):

$ svn commit -F logmsg
Sending        sniadanie.txt
Transmitting file data .
Committed revision 4.

Jeśli zapomnisz podać opcję --message (-m) lub --file (-F), Subversion automatycznie uruchomi ulubiony edytor (zobacz editor-cmd in „Config”) do wprowadzenia wiadomości.

[Podpowiedź] Podpowiedź

Możesz zrezygnować z wykonania commitu podczas wpisywania wiadomości w edytorze. Aby tego dokonać, po prostu zakończ edycję bez zapisywania pliku. Jeśli w międzyczasie zapisałeś plik, usuń jego zawartość i zapisz, a następnie przerwij kontynuacje polecenia svn commit:

$ svn commit
Waiting for Emacs...Done

Log message unchanged or not specified
(a)bort, (c)ontinue, (e)dit
a
$

Repozytorium nie monitoruje zmian pod względem czy mają sens z całością projektu; sprawdza tylko czy ktokolwiek inny nie wprowadził zmian. Jeśli ktoś dokonał zmian, cały commit zostanie przerwany, a svn wyświetli komunikat, że któryś lub któreś pliki są przestarzałe (out of date):

$ svn commit -m "Dodanie nowej pozycji"
Sending        rules.txt
svn: Commit failed (details follow):
svn: File '/sniadanie.txt' is out of date
…

(Komunikat (out of date) jest różny, zależny od protokołu, którego używasz czy też serwera, ale w każdym przypadku oznacza to samo.)

Gdy otrzymasz powyższy komunikat, musisz uruchomić polecenie svn update, połączyć zmiany w wynikłych konfliktach, a następnie ponowić próbę wysłania zmian do repozytorium.

Subversion oferuje dużo więcej funkcjonalności, które pozwalają zarządzać repozytorium i kopią roboczą, ale w codziennej pracy zazwyczaj będziesz używać te wspomniane w tym rozdziale. Dodatkowo opisane zostały te, z których dość często prawdopodobnie będziesz korzystać.



[3] Oczywiście, nic nie jest usuwane całkowicie z repozytorium, tylko z najnowszej wersji. Zawsze możesz wykonać commit lub update do wersji w której, plik lub katalog jeszcze był. Zobacz również „Resurrecting Deleted Items”.

[4] I nie masz karty WLAN. Myślisz, że nas masz? ;-)