Inżynieria Oprogramowania
Transkrypt
Inżynieria Oprogramowania
Inżynieria Oprogramowania Subversion – system zarządzania wersjami (konfiguracjami) Narzędzie nr 1: TortoiseSVN Narzędzie TortoiseSVN jest rozszerzeniem do Windowsa, które umożliwia pracę z repozytorium bardzo „przezroczyście”. Użytkownik traktuje zarządzanie wersjami jako element naturalny systemu, co ma tą zaletę, że uczy dobrych praktyk – nie tylko w programowaniu, ale również w wersjonowaniu np. dokumentów. Znakomita większość operacji jest dostępna z menu kontekstowego, tj. menu dostępnego po naciśnięciu prawego przycisku myszy – najczęściej na pliku lub folderze. Ćwiczenie 1.1. Checkout z repozytorium 1. Utworzyć katalog repo, np. w c:\temp\infXXXXX zamieniając XXXXX swoim numerem indeksu. Po zajęciach oczywiście po sobie sprzątamy i usuwamy taki katalog. 2. Na katalogu repo wybrać z menu kontekstowego SVN Checkout… 3. Wypełnić okienko wstawiając URL: https://ophelia.cs.put.poznan.pl/svn/io2009/infXXXXX/lab03 i wybrać przycisk OK. 4. Gdy pojawi się pytanie o użytkownika i hasło, wpisać otrzymane od prowadzącego dane. 5. Komunikat typu Completed oraz odpowiednia ikonka na folderze repo (po odświeżeniu) informują nas, że operacja zakończyła się powodzeniem. 6. Sprawdzić, czy w repo pojawiły się katalogi branches, tags oraz trunk. Jest to skutek używania zalecanej struktury repozytorium i ma znaczenie przy tworzeniu gałęzi (o tym w części 3). Ćwiczenie 1.2. Tworzenie folderów i zapis plików 1. W katalogu repo/trunk utworzyć katalog test. Nowopowstały folder nie będzie wyróżniony żadnym symbolem, gdyż folder ten nie znajduje się jeszcze na serwerze, w repozytorium. 2. Na nowym folderze wybieramy TortoiseSVN/Add… i OK. Wskazany folder został oznaczony do dodania (ale tylko lokalnie, ciągle nie ma go w repozytorium!). 3. Do założonego katalogu należy zapisać plik Fibonacci.java. 4. Z menu kontekstowego Fibonacci.java wybieramy TortoiseSVN/Add… i OK. 5. Zapis nowej wersji pliku na serwer można wykonać wybierając na katalogu test (lub repo albo trunk) SVN Commit… W okienku należy wpisać komentarz do dodawanej wersji pliku, np. „pierwsza wersja klasy”. I wybrać OK. Ćwiczenie 1.3. Modyfikacja plików 1. Zasymulujemy modyfikację pliku nadpisując go zmienioną wersją (z pliku Fibonacci2.java, zmieniając nazwę na Fibonacci.java). 2. Zmiana powinna zostać wykryta: 3. Wprowadzoną zmianę (wypisywanie 20 a nie 10 liczb) można zapisać na serwerze przy pomocy operacji SVN Commit. W komentarzu wersji należy wpisać: „wypisywanie 20 liczb”. Ćwiczenie 1.4. Wypisywanie logu zmian pliku 1. Na Fibonacci.java wybieramy TortoiseSVN/Show log 2. System wyświetli listę zmian, które są powiązane z danym plikiem. Ćwiczenie 1.5. Różnice 1. Zmodyfikuj plik Fibonacci.java zmieniając Created on 2004-10-04 na Created on 04-10-2004 2. Na „naszym” Fibonaccim wybieramy TortoiseSVN/Diff. Pokaże się wówczas okienko, które obrazuje, jakie są różnice wersji lokalnej w stosunku do wersji ostatnio pobranej z repozytorium. Ćwiczenie 1.6. Cofnięcie do wersji z repozytorium 1. Powiedzmy, że wprowadzone zmiany były niepoprawne i chcielibyśmy pobrać poprzednią wersję. 2. Klikamy prawym na naszym pliczku i wybieramy TortoiseSVN/Revert… 3. Wyświetlając zawartość pliku zobaczymy poprzednią wersję: Created on 2004-10-04. Pamiętajmy, że powrót do poprzedniej wersji nie oznacza uaktualnienia do najnowszej wersji! Operacja cofnięcia jest operacją lokalną, nie nawiązuje kontaktu z repozytorium. Ćwiczenie 1.7. Symulowanie konfliktów Konflikt w Subversion może się pojawić, jeżeli dwóch użytkowników pobrało w pewnym czasie określoną wersję danego pliku, po czym obaj dokonali w nim zmian i dokonują operacji Commit w tej samej linii w pliku. Pierwszy programista dokona operacji bez problemu, jednak w przypadku drugiego zostanie wykryta sytuacja niezgodności wersji na podstawie której dokonywał on zmian z wersją aktualnie znajdującą się w Subversion (dopiero co zapisaną przez pierwszego programistę). Sytuacja konfliktowa wymaga automatycznego lub ręcznego połączenia zmian wprowadzonych przez obu programistów. Do zasymulowania konfliktu potrzebny będzie drugi katalog roboczy. 1. Utwórzmy c:\temp\infXXXXX\repo2. 2. Pobierzmy repozytorium tak jak opisano w Ćwiczeniu 1.1. 3. Zmieńmy zawartość c:\temp\infXXXXX\repo2\trunk\temp\Fibonacci.java zastępując go treścią pliku Fibonacci3a.java. Po tej zmianie można wykonać TortoiseSVN/Diff, żeby zobaczyć, jakie zmiany wprowadzono w pliku. 4. Zapiszmy nową wersję do repozytorium SVN nadając następujący opis: „poprawka do liczby liczb w dokumentacji”. 5. Wracamy do pracy w katalogu c:\temp\infXXXXX\repo. 6. Znajduje się tam już teraz nieaktualna wersja, o czym jednak nie wie programista nad nią pracujący. 7. Zmieńmy zawartość c:\temp\infXXXXX\repo\trunk\temp\Fibonacci.java zastępując ją treścią z pliku Fibonacci3b.java. Po tej zmianie można wykonać TortoiseSVN/Diff, żeby zobaczyć, jakie zmiany wprowadzono w pliku. 8. Przy próbie Commita zmienionego pliku wyświetlony zostanie komunikat o błędzie: nie można utworzyć nowej wersji na serwerze, ponieważ mogłoby to usunąć zmiany, które już tam są, a nie są uwzględnione w naszej kopii lokalnej. Ćwiczenie 1.8. Rozwiązywanie konfliktów 1. W celu rozwiązania konfliktu i połączenia zmian wprowadzonych w lokalnej wersji pliku i nowej wersji z repozytorium (tj. wprowadzonej w repo2) należy wywołać operację SVN Update… z menu kontekstowego pliku Fibonacci.java. 2. W wyniku operacji zostanie dokonana operacja połączenia dwóch wersji plików – lokalnej i najnowszej w repozytorium – tam, gdzie się da automatycznie. Tam gdzie to będzie niemożliwe zostanie to pozostawione do rozstrzygnięcia użytkownikowi. 3. W katalogu pojawią się pliki (z innymi rozszerzeniami wskazującymi na faktyczne numery wersji): Fibonacci.java.mine – kopia lokalna w momencie łączenia, Fibonacci.java.213 – wersja z repozytorium, w stosunku do której były dokonywane zmiany lokalne (213), Fibonacci.java.214 – najnowsza wersja z repozytorium (214). Sam plik Fibonacci.java zawierać będzie zawartość uzyskaną przez automatyczne połączenie wersji (tam gdzie zmienione sekcje się nie nakładały) oraz fragmenty pozostawione do ręcznego zsynchronizowania. 4. Należy otworzyć plik Fibonacci.java do edycji. Jak widać z jego zawartości dokonane zostało automatyczne połączenie części zmian. Najważniejszy jest fragment dotyczący konfliktowej zmodyfikowanej w obu wersjach linii: <<<<<<< .mine * Created on 2004-11-24 ======= * Created on 2004-11-23 >>>>>>> .r214 Zawiera on zawartość zmodyfikowanej linii z lokalnej kopii pliku (powyżej ======) oraz konfliktującej wersji 214 z repozytorium (poniżej ======). 5. Rozwiązanie konfliktu sprowadza się do wyboru wersji linii, która ma zostać użyta. Zastępujemy zatem powyższy fragment, pojedynczą linią: * Created on listopad 2004 oraz wybierając operację TortoiseSVN/Resolved. Plik uzyskuje status zmienionego lokalnie, bez konfliktów. 6. Możemy sprawdzić, że wszystko jest OK wybierając TortoiseSVN/Diff. 7. Dokonujemy operacji Commit wpisując odpowiedni komentarz. Narzędzie nr 2: Eclipse Eclipse sam w sobie nie jest oczywiście narzędziem do zarządzania wersjami, jednak od początku w jego projekcie przewidziana jest możliwość „wpięcia” plug-inów do komunikowania się z systemami zarządzania wersjami. Standardowo w Eclipse 3.3 dostarczane są wtyczki do obsługi repozytoriów CVS (od wersji 3.4 również SVN). Aby korzystać z Subversion należy doinstalować wtyczki Subversive albo Subclipse. Na zajęciach korzystamy z tego pierwszego. Poniższe ćwiczenia polegają z grubsza na tym samym co już przeprowadzone z narzędziem TortoiseSVN, więc ich opis jest bardziej uproszczony. Tam gdzie to istotne zaznaczono specyfikę Eclipse'a. Warto pamiętać, że większość operacji będzie wyglądała podobnie podczas pracy z innymi wtyczkami (Subclipse, praca z CVS), dzięki temu, że mechanizm zarządzania wersjami jest elementem platformy Eclipse. Ćwiczenie 2.1. Utworzenie projektu w repozytorium 1. W Eclipse utworzyć nowy projekt Java: File/New/Project... i Java/Java Project. 2. Podać nazwę, np. test-svn; upewnić się, że ustawienia rozdziału plików .java i .class są takie jak poniżej: 3. Kliknąć Finish. 4. Z menu kontekstowego projektu wybrać Team/Share project... 5. Wybieramy typ repozytorium SVN 6. Dalej podajemy URL i dane użytkownika (patrz ćwiczenie 1.1.). Uwaga: Proszę podać dokładnie taki URL jak w ćwiczeniu 1.1. 7. Po poprzednim kroku mamy utworzoną informację o repozytorium. Może w nim być wiele projektów. Dlatego na następnym ekranie podajemy katalog, w którym ma być umieszczony nasz projekt, w ramach zdefiniowanego repozytorium. Możliwych jest wiele schematów układu katalogów projektów w repozytorium. Proszę użyć ustawień jak na rysunku poniżej; skutkują one strukturą uwzględniającą gałęzie i tagi na poziomie repozytorium (czyli w lab03, a poniżej projektu test-svn). 8. Po wciśnięciu Finish, Eclipse poprosi o podanie komentarza do Commita. Podajemy np. „import projektu Eclipse”. Ciekawostką jest fakt, że jest to drugi commit, zawartości projektu. Pierwszy został wykonany automatycznie i polegał na utworzeniu tylko folderu projektu w SVN – najprostszy sposób, aby wykluczyć istnienie w repozytorium projektu o podanej nazwie. 9. Obecnie projekt jest obecny w repozytorium, oraz lokalnie. Kopia lokalna jest „standardową” kopią SVN, o czym można się przekonać wykonując dowolne operacje z poziomu TortoiseSVN na folderze projektu Eclipse. Oznacza to np. że dodając do projektu pliki z poziomu TortoiseSVN nie ryzykujemy niespójności repozytorium – Eclipse działa tutaj jak „nakładka” na projekt, podobnie jak TortoiseSVN jako „nakładka” na system plików. Ćwiczenie 2.2. Dodawanie plików 1. Z poziomu Windowsa dodajemy do folderu src plik Fibonacci.java. 2. W Eclipse odświeżamy projekt (Refresh w menu kontekstowym projektu). 3. Rozwijając drzewko do poziomu dodanego pliku widzimy obok ikonkę ze znakiem zapytania. Oznacza ona, że plik jest nieznany z punktu widzenia repozytorium, tzn. został dodany lokalnie, ale w repozytorium go nie ma. Zwróćmy też uwagę na symbol > obok projektu. Oznacza on, że w tym projekcie są jakieś rozbieżności pomiędzy repozytorium a wersją lokalną (najczęściej zmodyfikowane lokalnie pliki). 4. Na projekcie wybieramy Team/Synchronize with Repository. Perspektywa, która się pokazała jest podstawową z punktu widzenia operacji na kopii lokalnej i repozytorium. 5. Widzimy, że Eclipse wykonuje automatycznie niektóre operacje, np. oznaczył do dodania plik Fibonacci.java. 6. Na projekcie wybieramy z menu kontekstowego Commit... i wpisujemy komentarz, np. „dodano plik Fibonacci.java”. 7. Eclipse informuje nas, że nie ma więcej zmian w stosunku do repozytorium; podobnie w perspektywie Java, nie widać oznaczań zmian lokalnych na ikonach w drzewku. Ćwiczenie 2.3. Pobieranie projektu z repozytorium Teraz spróbujemy pobrać projekt z repozytorium. Żeby było to skuteczne na projekcie wybieramy z menu kontekstowego Delete i zaznaczamy opcję Also delete contents under '...'. 1. Wybieramy z File/Import... i SVN/Projects from SVN. 2. Wybieramy nasz profil repozytorium z listy. 3. Zaznaczamy na liście folder trunk/test-svn i klikamy Finish. 4. Potwierdzamy checkout zasobu jako osobny projekt. 5. Sprawdzamy, czy „w środku” jest wszystko tak, jak przed rozpoczęciem ćwiczenia. Ćwiczenie 2.4. Modyfikacja i różnice w plikach 1. Z poziomu Windows podmieniamy zawartość Fibonacci.java (patrz ćwiczenie 1.3., krok 1.). 2. Odświeżamy w Eclipse projekt i przechodzimy do perspektywy Team Synchronizing. 3. Widzimy, że Eclipse wykrył zmianę w pliku: strzałka „w prawo” oznacza chęć Eclipse'a do wysłania zmian do repozytorium. 4. Aby przekonać się, co się zmieniło, dwukrotnie klikamy na zmieniony plik. W obszarze edytora otworzy się nowe okno, gdzie zaprezentowane są zmiany pomiędzy wersją lokalną a oryginalną z repozytorium. 5. Aby wysłać zmiany do repozytorium na projekcie wybieramy Commit. Ćwiczenie 2.5. Symulowanie konfliktów Podobnie jak w ćwiczeniu 1.7., do symulacji konfliktu potrzebujemy drugiej, równoległej kopii lokalnej. 1. Utwórzmy c:\temp\infXXXXX\repo3. 2. Pobierzmy repozytorium tak jak opisano w Ćwiczeniu 1.1. 3. Zmieńmy zawartość c:\temp\infXXXXX\repo3\trunk\testsvn\src\Fibonacci.java zastępując go treścią pliku Fibonacci3a.java. Po tej zmianie można wykonać TortoiseSVN/Diff, żeby zobaczyć, jakie zmiany wprowadzono w pliku. 4. Zapiszmy nową wersję do repozytorium SVN nadając następujący opis: „poprawka do liczby liczb w dokumentacji”. 5. Wracamy do pracy w katalogu projektu Eclipse. 6. Znajduje się tam już teraz nieaktualna wersja, o czym jednak nie wie programista nad nią pracujący. 7. Zmieńmy zawartość pliku Fibonacci.java zastępując ją treścią z pliku Fibonacci3b.java. Odświeżamy projekt w Eclipse. Po tej zmianie można podejrzeć (jak w ćwiczeniu 2.4.), jakich dokonano zmian lokalnych na tym pliku. 8. Przy próbie synchronizacji (przycisk Synchronize SVN w perspektywie Team Synchronizing) status pliku zmieni się na „konfliktowy” (czerwony kolor strzałek na ikonie). Ćwiczenie 2.6. Rozwiązywanie konfliktów. 1. Aby zobaczyć konflikty i je rozwiązać, dwukrotnie klikamy na plik Fibonacci.java (ciągle w perspektywie synchronizacji). Widzimy, że plik lokalnie zmieniony i najnowsza wersja z repozytorium zostały połączone. Wszystkie lokalne zmiany są prezentowane tak, jak widzieliśmy to podczas oglądania różnic w ćwiczeniu 2.4. Konfliktowe linie zostały zaznaczone na czerwono. Wymagają one podjęcia decyzji, jak ma wyglądać w tych miejscach nowa wersja pliku lokalnego, którą będzie można „wrzucić” do repozytorium. 2. Proszę zapoznać się z przyciskami nad panelem różnic, bez obaw klikając: Show/Hide Ancestor pane – oprócz dwóch plików pokazany zostanie trzeci, który jest wspólnym „przodkiem” obu zmian, Select Next/Previous Change – pozwala na nawigowanie pomiędzy zmianami. Podświetlane są zmiany na poziomie poszczególnych znaków, co jest często dużą pomocą: czasem trudno stwierdzić „na oko” czym różnią się dwie linie. 3. Ponieważ chcemy wprowadzić w wierszu konfliktowym inny tekst, niż dostępny w obu wersjach, ustawiamy tam kursor po stronie Local File (lewy panel) i wpisujemy * Created on listopad 2004 po czym zapisujemy plik (Ctrl+S). 4. Dajemy znać Eclipse'owi, żeby się już nie martwił i że rozwiązaliśmy wszystkie konflikty: wybieramy Marked as Merged z menu kontekstowego na kłopotliwym pliku. 5. Status pliku zmieni się z „konfliktowego” na zmodyfikowany lokalnie. Możemy więc zapisać zmiany w repozytorium (ćwiczenie 2.4., kroki od 3.). Narzędzie 3: Linia poleceń Historycznie patrząc, jest to pierwszy i referencyjny klient do SVN, rozwijany razem z serwerem. Większość operacji, które można wykonać z poziomu GUI (Eclipse, TortoiseSVN) można też wykonać z poziomu linii poleceń, jednak wymaga to większej liczby operacji i „stuknięć klawisze”. Aby wywołać klienta należy wpisać w konsoli svn <komenda> gdzie <komenda> jest operacją, jaką chcemy wykonać. Zależnie od operacji może być wymagane podanie dodatkowych argumentów. Można się o tym dowiedzieć – co będzie użyteczne w dalszych ćwiczeniach – z pomocy uzyskanej poleceniem svn help <komenda>. Ćwiczenie 3.1: Checkout z repozytorium Polecenie (jedna linia!) svn checkout https://ophelia.cs.put.poznan.pl/svn/io2009/infXXXXX/lab03 repo4 pobierze zawartość repozytorium do katalogu repo4. Ćwiczenie 3.2: Dodawanie plików Należy przejść do katalogu repo4/trunk. 1. Wykonać komendę SVN status. Nie powinno być żadnego komunikatu, co oznacza, że kopia lokalna jest „czysta”, bez zmian lokalnych. 2. Należy utworzyć nowy katalog i plik. Ponowna komenda status pokaże obok nowych elementów znak '?', co oznacza, że nie jest on znany dla SVN. 3. Wykonujemy komendę add. Ponowne sprawdzenie statusu pokazuje obok nowych elementów znak 'A', co wskazuje na oznaczenie elementów do dodania. 4. Należy zatwierdzić zmiany w repozytorium komendą commit. 5. Status katalogu powinien być „czysty”, jak w punkcie 1. Ćwiczenie 3.3: Tworzenie gałęzi W dowolnym miejscu rozwoju kodu możemy podjąć decyzję o utworzeniu gałęzi: alternatywnej linii rozwoju projektu. W SVN nie istnieje pojęcie gałęzi jako element architektury. Zamiast tego używa się mechanizmu „taniej kopii” i umownej struktury repozytorium. Taką umową są trzy katalogi o specjalnych nazwach, położone obok siebie: trunk – tutaj umieszczane są „zwykłe” zmiany. Zawartość tego katalogu to najczęściej główna linia rozwoju projektu; branches – kiedy uznamy, że potrzebna jest dodatkowa gałąź (np. celem stabilizacji wersji do wydania na rynek, bez konieczności zwalniania tempa rozwoju trunka), tutaj wykonujemy kopię trunka; tags – kiedy uznamy, że jakiś moment (tj. wersja repozytorium) jest godna uwagi (np. stabilizowana gałąź jest wydawana na rynek), tutaj wykonujemy kopię z gałęzi (najczęściej). Powyżej sporo pisano o kopiach. Tak jest, ponieważ kopiowanie jest „tanie” w Subversion i jest często używane. Kopia zasobu w SVN podobna jest do linka w systemie Linux; stanowi ona tylko oznaczenie, z którego miejsca w której wersji repozytorium pochodzi kopia. 1. Posłuchać co prowadzący może mieć do powiedzenia na temat kopii, gałęzi i tagów. 2. Wykonać kopię najnowszej wersji repozytorium do nowej gałęzi (proszę zauważyć, że kopiowanie jest tylko w repozytorium, bez udziału kopii lokalnej – jest to dużo wydajniejsze niż kopiowanie do kopii lokalnej i z powrotem): svn copy https://ophelia/svn/io2009/infXXXXX/lab03/trunk https://ophelia/svn/io2009/infXXXXX/lab03/branches/stable-01 3. Pobrać wersję gałęzi do osobnego katalogu, np. repo5 (jedna linia!): svn checkout https://ophelia/svn/io2009/infXXXXX/lab03/branches/stable-01 C:\temp\infXXXXX\repo5 4. Wprowadzić zmiany w gałęzi (tj. w repo5) i wrzucić je do repozytorium. 5. Zauważmy, że po aktualizacji kopii roboczej z trunka (tj. w repo4) komendą update nic się nie zmieniło (bo jest to zupełnie inny podkatalog w repozytorium: kopia wykonana przez copy zaczyna „żyć własnym życiem”). 6. Czasami jednak chcemy przenieść część zmian z gałęzi do trunka (np. dokonane poprawki błędów). Służy do tego komenda merge, na której przećwiczenie nie mamy niestety czasu... Odpowiednia komenda, wykonana w repo4, która przeniesie naszą ostatnią zmianę z brancha do trunka miałaby postać: svn merge -r X:Y https://ophelia/svn/io2009/infXXXXX/lab03/branches/stable-01 gdzie X = Y-1, a Y jest wersją, którą uzyskaliśmy po poprzednim commicie.