Raz na jakiś czas, pojawi się konflikt podczas uaktualnienia/scalania plików z repozytorium lub po przełączeniu kopii roboczej na inny URL. Istnieją dwa rodzaje konfliktów:
Konflikt pliku występuje, gdy dwaj (lub więcej) programiści zmienili te same kilka linijek pliku.
Konflikt drzewa występuje wówczas, gdy programista przeniósł /zmienił nazwę/usunął plik lub folder, który inny programista również przeniósł /zmienił nazwę/usunął lub po prostu zmodyfikował.
Konflikt ma miejsce, gdy dwóch lub więcej programistów zmieniło te same kilka linijek pliku. Jako że Subversion nic nie wie o projekcie, pozostawia programistom rozwiązywanie konfliktów. Obszar konfliktu jest oznaczony w ten sposób:
<<<<<<< nazwaPliku twoje zmiany ======= kod pobrany z repozytorium >>>>>>> wersja
Ponadto dla każdego konfliktu pliku Subversion wstawia w katalogu trzy dodatkowe pliki:
Jest to plik, jaki istniał w waszej kopii roboczej zanim ją zaktualizowaliście - czyli bez znaczników konfliktu. Ten plik zawiera Wasze najnowsze zmiany i nic więcej.
Jest to plik, który był wersją BAZY przed zaktualizowaniem kopii roboczej. Oznacza to, że plik, który był pobrany, zanim wprowadziliście najnowsze zmiany.
Jest to plik, który klient Subversion właśnie otrzymał z serwera podczas aktualizowania kopii roboczej. Ten plik odpowiada wersja HEAD repozytorium.
Można uruchomić zewnętrzne narzędzie scalenia / edytor konfliktów wywołując <<<<<<<
.
Następnie wykonajcie polecenie filename.ext.mine
i filename.ext.r*
, co pozwala na zatwierdzenie własnych zmian.
Jeśli macie konflikty w plikach binarnych, Subversion nie próbuje scalić pliku. Lokalny plik pozostaje bez zmian (dokładnie tak, jak został ostatnio zmieniony) i dostajecie pliki filename.ext.r*
. Jeśli chcecie odrzucić swoje zmiany i pozostawić wersję z repozytorium, użyjcie polecenia Wycofaj. Jeśli chcecie zachować swoją wersję i zastąpić wersję z repozytorium, należy skorzystać z polecenia Rozwiązany, a następnie zatwierdzić wersję.
Możecie użyć polecenia Rozwiązany dla wielu plików, gdy klikniecie prawym przyciskiem myszy na folder macierzysty i wybierzecie
→ Wyświetlone zostanie okno zawierające wszystkie konflikty plików w tym folderze i można wybrać te, które zostaną oznaczone jako rozwiązane.Konflikt atrybutów występuje, gdy dwóch lub większa ilość programistów zmieniło ten sam atrybut. Tak jak dla zawartości pliku, rozwiązanie konfliktu może być dokonane jedynie przez programistów.
Jeśli jedna ze zmian musi nadpisać inne, wybierzcie opcję Rozwiąż używając atrybutu lokalnego lub Rozwiąż używając atrybutu zdalnego. Jeśli zmiany muszą być scalone, wybierzcie Edytuj atrybut ręcznie, wprowadźcie wartość poprawną i oznaczcie atrybut jako rozwiązany.
Konflikt drzewa występuje wówczas, gdy programista przeniósł/ zmienił nazwę/usunął plik lub folder, który w tym czasie inny programista również przeniósł/przemianował/usunął lub po prostu zmodyfikował zawartość. Istnieje wiele różnych sytuacji, które mogą doprowadzić do konfliktu drzewa, a wszystkie z nich wymagają innych czynności w celu rozwiązania konfliktu.
Gdy plik zostanie usunięty lokalnie w Subversion, jest on usuwany z lokalnego systemu plików, więc nawet jeśli jest częścią konfliktu drzewa nie można pokazać nakładki konfliktu i nie można kliknąć prawym przyciskiem myszy na plik, aby konflikt rozwiązać. Użyjcie okna dialogowego Sprawdź zmiany zamiast eksploratora by uzyskać dostęp do opcji Edytuj konflikty.
TortoiseSVN może pomagać znaleźć odpowiednie miejsce do scalenia zmian, ale z reguły niezbędna jest dodatkowa praca by konflikt rozwiązać. Pamiętajcie, że po aktualizacji BAZA robocza zawsze będzie zawierać wersję każdego elementu z repozytorium na ostatnią jego aktualizację. Zatem jeśli wycofacie zmiany, to po aktualizacji element wraca do aktualnego stanu z repozytorium, a nie tego, z którego rozpoczęliście robić własne, lokalne zmiany.
Programista A zmienia zawartość Foo.c
i zatwierdza plik do repozytorium.
Deweloper J w tym samym czasie przeniósł Foo.c
do Bar.c
w kopii roboczej, lub po prostu usunął Foo.c
albo zawierający go folder.
Uaktualnienie kopii roboczej przez programistę J daje w wyniku konflikt drzewa:
Foo.c
został usunięty z kopii roboczej, ale jest oznaczony jako konflikt drzewa.
Jeżeli konflikt wynika ze zmiany nazwy, a nie usunięcia, plik Bar.c
jest oznaczony jako dodany, ale nie zawiera poprawek programisty A.
Programista J musi teraz zdecydować, czy zachować zmiany programisty A. W przypadku zmiany nazwy plików, może on połączyć zmiany z pliku Foo.c
do nowego Bar.c
. Dla prostego usunięcia pliku lub katalogu może wybrać utrzymanie elementu ze zmianami programisty A i odrzucenie usunięcia. Albo, zaznaczając konflikt jako rozwiązany nie robiąc nic, skutecznie usuwa zmiany programisty A.
Dialog edycji konfliktu oferuje scalenie zmian, jeżeli można znaleźć plik oryginalny dla przemianowanego Bar.c
. Jeśli jest wiele plików mogących być źródłem przeniesionego, przy każdym z nich pokazany zostanie przycisk pozwalający wybrać właściwy plik.
Programista A przenosi Foo.c
do Bar.c
i zatwierdza to w repozytorium.
Programista J zmienia zawartość Foo.c
w swojej kopii roboczej.
Lub w przypadku przeniesienia folderu ...
Programista A przenosi folder macierzysty FooFolder
do BarFolder
i zatwierdza to w repozytorium.
Programista J zmienia zawartość Foo.c
w swojej kopii roboczej.
Uaktualnienie kopii roboczej programisty J powoduje konflikt drzewa. W przypadku prostego konfliktu pliku:
Bar.c
zostaje dodany do kopii roboczej jak zwykły plik.
Foo.c
jest oznaczony jako dodany (z historią) i posiada konflikt drzewa.
Dla konfliktu folderu:
BarFolder
zostaje dodany do kopii roboczej jako zwykły folder.
FooFolder
jest oznaczony jako dodany (z historią) oraz posiada konflikt drzewa.
Foo.c
jest oznaczony jako zmieniony.
Programista J musi teraz zdecydować, czy zgodzić się na reorganizację A i scalenie swoich zmian do odpowiedniego pliku w nowej strukturze, albo po prostu wycofać zmiany A i zachować swój plik lokalny.
Aby rozwiązać konflikt, programista J musi odnaleźć, na jaką nazwę pliku został przemianowany w katalogu repozytorium plik Foo.c
będący w stanie konfliktu. Można to zrobić przy użyciu okna dialogowego dziennika. Następnie użyjcie przycisku, który pokazuje poprawny plik źródłowy by rozwiązać konflikt.
Jeśli Programista J zdecyduje, że zmiany A były niewłaściwe, musi wybrać przycisk Oznacz jako rozwiązany w oknie edytora konfliktu. Zaznacza to skonfliktowane pliki/foldery jako rozwiązane, ale zmiany programisty A trzeba usunąć ręcznie. Ponownie okno dziennika pomaga wyśledzić, co zostało przeniesione.
Programista A przenosi Foo.c
do Bar.c
i zatwierdza to w repozytorium.
Programista J przenosi Foo.c
do Bix.c
.
Uaktualnienie kopii roboczej przez programistę J daje w wyniku konflikt drzewa:
Bix.c
zostaje zaznaczone jako dodany z historią.
Bar.c
zostaje dodany do kopii roboczej ze statusem 'zwykły'.
Foo.c
zostaje oznaczony jako usunięty i posiada konflikt drzewa.
Aby rozwiązać konflikt, programista J musi odnaleźć, na jaką nazwę pliku został przemianowany w katalogu repozytorium plik Foo.c
będący w stanie konfliktu. Można to zrobić przy użyciu okna dialogowego dziennika.
Następnie programista J musi wybrać który z dwóch nowych plików Foo.c
pozostawić - ten wykonany przez programistę A, czy wykonany przez siebie poprzez zmianę nazwy.
Po tym jak programista J ręcznie rozwiązał skłócenie, konflikt drzewa musi być oznaczony jako rozwiązany za pomocą przycisku w oknie edytora konfliktu.
Programista A pracując na linii głównej zmienia zawartość Foo.c
i zatwierdza go do repozytorium
Deweloper J pracując na gałęzi przenosi Foo.c
do Bar.c
i zatwierdza to do repozytorium
Scalenie ze zmianami linii głównej programisty A do kopii roboczej gałęzi dewelopera J powoduje konflikt drzewa:
Bar.c
jest już w kopii roboczej ze statusem 'zwykły'.
Foo.c
jest oznaczony jako brakujący z konfliktem drzewa.
Aby rozwiązać ten konflikt, programista A musi oznaczyć plik jako rozwiązany w oknie edytora konfliktu, co usunie go z listy konfliktu. Potem musi zdecydować, czy skopiować brakujący plik Foo.c
z repozytorium do kopii roboczej, czy też scalić zmiany programisty A z Foo.c
do przemianowanego Bar.c
czy też zignorować zmiany, zaznaczając konflikt jako rozwiązany i nie robiąc nic innego.
Zauważcie, że jeśli skopiujecie brakujący plik z repozytorium, a następnie oznaczycie jako rozwiązany, kopia zostanie usunięta. Musicie rozwiązać konflikt w pierwszej kolejności.
Programista A pracując na linii głównej przenosi Foo.c
do Bar.c
i zatwierdza go w repozytorium.
Programista J pracując na gałęzi zmienia Foo.c
i zatwierdza go w repozytorium.
Borgramista A pracując na linii głównej przenosi folder nadrzędny FooFolder
do BarFolder
i zatwierdza to w repozytorium.
Programista J pracując na gałęzi zmienia Foo.c
w kopii roboczej.
Scalenie ze zmianami linii głównej programisty A do kopii roboczej gałęzi dewelopera J powoduje konflikt drzewa:
Bar.c
zostaje zaznaczony jako dodany.
Foo.c
zostaje zaznaczony jako zmieniony z konfliktem drzewa.
Programista J musi teraz zdecydować, czy zgodzić się na reorganizację A i scalenie swoich zmian do odpowiedniego pliku w nowej strukturze, albo po prostu wycofać zmiany A i zachować swój plik lokalny.
Aby scalić miejscowe zmiany z przetasowaniem, Programista J musi najpierw dowiedzieć się, na jaką nazwę plik skonfliktowany Foo.c
został przemianowany/przeniesiony w repozytorium. Można to zrobić za pomocą okna dziennika dla źródła scalenia. Edytor konfliktu pokazuje tylko dziennik kopii roboczej, ponieważ nie wie, jaka ścieżka została użyta scalenia, zatem będzie musiał znaleźć ją sam. Zmiany muszą być połączone ręcznie, jako że nie ma obecnie sposobu na zautomatyzowanie lub nawet uproszczenie tego procesu. Gdy już zmiany zostały naniesione, skonfliktowana ścieżka jest zbędna i może zostać usunięta.
Jeśli programista J decyduje, że zmiana A jest niepoprawna, musi wybrać przycisk Oznacz jako rozwiązany w oknie edytora konfliktu. Zaznacza to skonfliktowany plik/folder jako rozwiązany, ale zmiany programisty A trzeba usunąć ręcznie. Ponownie okno dziennika dla źródła scalenia pomaga wyśledzić, co zostało przeniesione.
Programista A pracując na linii głównej przenosi Foo.c
do Bar.c
i zatwierdza go w repozytorium.
Programista J pracując na kopii roboczej przenosi Foo.c
do Bix.c
i zatwierdza to do repozytorium.
Scalenie ze zmianami linii głównej programisty A do kopii roboczej gałęzi dewelopera J powoduje konflikt drzewa:
Bix.c
zostaje oznaczony statusem zwykły (niezmodyfikowany).
Bar.c
jest oznaczony jako dodany z historią.
Foo.c
jest oznaczony jako brakujący i ma konflikt drzewa.
Aby rozwiązać konflikt, programista J musi odnaleźć, na jaką nazwę pliku został przemianowany w katalogu repozytorium plik Foo.c
będący w stanie konfliktu. Można to zrobić przy użyciu okna dialogowego dziennika na źródle scalenia.
Następnie programista J musi wybrać który z dwóch nowych plików Foo.c
pozostawić - ten wykonany przez programistę A, czy wykonany przez siebie poprzez zmianę nazwy.
Po tym jak programista J ręcznie rozwiązał skłócenie, konflikt drzewa musi być oznaczony jako rozwiązany za pomocą przycisku w oknie edytora konfliktu.
Istnieją inne przypadki, które są oznakowane jako konflikty drzewa tylko dlatego, że konflikt dotyczy folderu, a nie pliku. Na przykład, jeśli dodaliście folder o tej samej nazwie zarówno do linii głównej jak i gałęzi, a następnie spróbowaliście je scalić, otrzymacie konfliktu drzewa. Jeśli chcecie zachować folder z celu scalenia, po prostu oznaczcie konflikt jako rozwiązany. Jeśli chcecie zachować źródło scalenia, musicie najpierw SVN usunąć go z celu i dopiero uruchomić ponownie scalenie. Jeśli wymagane jest cokolwiek bardziej skomplikowanego, trzeba to rozwiązać ręcznie.