Mercurial TFS2010 Poprzednio pisałem o tym dlaczego postanowiliśmy przejść na Mercuriala, a dziś kilka konkretów na temat przeprowadzenia migracji, instalacji centralnego repozytorium w sposób, powiedzmy bezbolesny, dla programistów .NET oraz o innych sprawach, które mogą być przydatne dla każdego kto chce wykonać podobny krok :)

Konfiguracja Mercuriala na serwerze Windows Server

Docelowa konfiguracja zakładać będzie wykorzystanie Mercuriala 1.9.1, Pythona 2.6, IIS 7.5, Windows Server 2008 R2. Dobry przewodnik wyjaśniający krok po kroku wszystkie niezbędne akcje do wykonania znaleźć można pod adresem: Installing Mercurial 1.8.4 on IIS 7.5 as a Repository website. Osobiście muszę przyznać, że poradnik jest w pełni wyczerpujący i zgodny także z najnowszą wersją Mercuriala. Wykonując wszystkie kroki i zalecenia otrzymujemy działające rozwiązanie, które pozwala korzystać z Hg z centralnego repozytorium.  Przy okazji muszę wspomnieć o pewnym problemie, który napotkaliśmy – a jakże – zaraz po przejściu w stan produkcyjny, a którego nie byliśmy tak naprawdę w stanie rozwiązać normalnymi sposobami.

O co chodzi? W środowisku testowym (tzn. wtedy gdy tylko kilka osób – 2 – korzystało z repozytorium Mercuriala) nie było żadnych problemów, o tyle w momencie gdy do centralnego repozytorium podpięły się nowe osoby i zaczęły z nim pracę, to serwer odmawiał posłuszeństwa i najzwyczajniej w świecie się zawieszał. Tak, nowoczesny Windows Server 2008 R2 przestawał odpowiadać w momencie, gdy nowi użytkownicy wykonywali jakiekolwiek zapytanie do centralnego repo. Okazało się, że działo się tak tylko w przypadku, gdy komputer kliencki wykonujący zapytanie był połączony do lokalnej sieci przez kabel RJ-45. W przypadku WiFi – wszystko działało bez najmniejszych problemów (choć też zdarzyły się 2 incydenty przy wykonywaniu Clone, ale brak mi pewności, czy nie jest to związane z przypadkową akcją innego użytkownika połączonego kablem). Co ciekawe system zawieszał się bez żadnego wpisu do EventLoga, co skutecznie utrudniło zlokalizowanie problemu. Takie bardzo doraźne próby poradzenia sobie z problemem, jak np. zwiększenie puli obsługiwanych równocześnie połączeń ze standardowych 10 do 10000 w najmniejszym stopniu nie pomagało. Istniała szansa, że problem leży w konfiguracji serwera, jednak ze względu na brak czasu na przeinstalowanie maszyny trzeba było znaleźć inne rozwiązanie i to szybko.

Bardzo dobrym rozwiązaniem okazało się użycie zamiast IIS bezpłatnego serwera Abyss Web Server, którego konfiguracja jest o wiele prostsza i szybsza niż Microsoftowego pupilka. Poza tym instalacja serwera Abyssa nie wyklucza używania IIS (oba rozwiązania bardzo dobrze znoszą siebie nawzajem).

A teraz kilka słów jak skonfigurować Abyss Web Server aby dobrze nam służył.

Konfiguracja Abyss Web Server

  1. Instalacja aplikacji. Po zakończeniu automatycznie uruchomi się nam w przeglądarce strona administracyjna serwera. Pierwsze uruchomienie to m.in. nadanie hasła dla administratora, itd.
    Konfiguracja CGI na serwerze Abyss

  2. Po zakończeniu wchodzimy pod adres: http://localhost:9999 i klikamy Configure na dostępnym domyślnym hoście

  3. Klikamy Scripting Parameters, gdzie ustawimy obsługę CGI i Pythona dla naszego hgweb
  4. W sekcji Interpreters klikamy Add i uzupełniamy podobnie jak na zdjęciu po prawej
  5. Następnie wracamy do strony głównej hosta i wybieramy Aliases
  6. Dodajemy nowy alias, który odpowiada wirtualnemu katalogowi z IIS. W moim przypadku VirtualPath to /hg, a PhysicalPath wskazuje rzeczywisty katalog z danymi. Wskazałem ten sam katalog, który był używany przez IIS, bez żadnych zmian i działa bez zarzutu :)
  7. Opcjonalnie można skonfigurować jeszcze URL Rewrite do usunięcia hgweb.cgi z adresu, jednak u nas w teamie nie było to w sumie bardzo kluczowe, więc ten krok pominąłem :)
  8. Cieszymy się działającym centralnym repozytorium Mercuriala na Windows Server! ;]

Przy okazji okazało się, że możliwości serwera Abyss są całkiem pokaźne, w szczególności biorąc pod uwagę wielkość paczki instalatora (~1,8 MB). Ponadto nie testowałem możliwości hostowania stron w ASP.NET w Abyss zamiast na IIS (jest taka możliwość i jest obsługa .NET Frameworka do najnowszej wersji – 4.0), a na pewno warto byłoby tę funkcjonalność wypróbować :)

Migracja repozytorium

Mając postawione centralne repozytorium należałoby wgrać do niego wszystkie dane z nieszczęsnego TFS, aby nowe repozytorium było w pełni funkcjonalne. Do migracji użyłem maleńkiego programiku tfs2hg odpalanego z linii konsoli. Programik dla repozytorium o ilości 4000 changesetów działa jakieś 2 – 3h, więc należy uzbroić się w cierpliwość :) Nie polecam uruchamiać programu na swojej maszynie deweloperskiej, ponieważ w TFS jest pewien problem z tym, żeby mieć solucję “zamontowaną” w więcej niż 1 miejscu. Programik do migracji do wybranego folderu robi po kolei Get Specific Version od wersji 1 do ostatniej i po każdej akcji robi hg commit. Żeby nie męczyć się z jakimś bezsensowym konfigurowaniem workspace’ów w TFS na moim komputerze do odpalenia programu użyłem mojego podręcznego serwera, gdzie nigdy nie była pobierana solucja z TFS ;]

Przy okazji ciekawostka:

Pobierając po kolei wszystkie wersje repozytorium z TFS, w rezultacie możemy nie uzyskać zakładanego efektu. W moim przypadku zauważyłem pewną ciekawą rzecz. Mianowicie w rezultacie działania programiku brakowało około 800 plików z kodem. Trudno mi powiedzieć, czemu, w szczególności, że log migratora wskazywał na poprawnie wykonaną migrację wszystkich zmian, a mimo to czegoś brakowało :)

Różnice w stosunku do TFS

Rozpoczynając pracę w środowisku Mercuriala i przy repozytorium projektowym aplikacji .NET, należy w pierwszej kolejności dodać (lub edytować, jeśli został już utworzony) plik .hgignore, który zawiera rozszerzenia, nazwy plików i katalogów, które mają być ignorowane przy commitach. W przypadku TFS nie było potrzeby się tym zajmować, bo pakiet zawierał już taki predefiniowany plik zawierający informacje o tym jakie pliki powinny się znaleźć w repozytorium, a jakie nie. My musimy to ręcznie wprowadzić i plik ten później dodać do repozytorium. Na stronie stackoverflow question całkiem dobra zawartość przykładowego pliku .hgignore dla projektów w Visual Studio 2008. Nasz plik .hgignore dla Visual Studio 2010 jest dostępny tutaj.

Jeśli zaś chodzi o konfigurację klienta, to najpierw podejdę do tematu od drugiej strony. Należy bowiem wiedzieć czym się różnią “zwykłe” systemy kontroli wersji takie jak Subversion lub TFS od systemów rozproszonych z Mercurialem i Gitem na czele.

Centralized System Distributed System
System scentralizowany System rozproszony

Źródło obrazków: Dokumentacja Joomla

Widać tutaj podstawową różnicę w systemie rozproszonym – każdy deweloper uczestniczący w projekcie ma własną wersję repozytorium, do której wykonuje wszystkie operacje związane z kontrolą wersji. Dopiero operacje pull i push synchronizują repozytoria pomiędzy sobą. Jest to najważniejszy punkt dla deweloperów zniszczonych korzystaniem z TFS, gdzie symbol zielonej ikonki na pliku w solucji oznaczał, że plik jest w repozytorium widocznym już dla wszystkich. W przypadku Mercuriala – symbol zielonej ikonki nic takiego nie oznacza :)

Kolejna różnica jaką można byłoby zauważyć to sam mechanizm działania repozytorium i sposób rozwiązywania konfliktów. Skoro nie ma blokowania plików to oczywistym jest, że pojawią się konflikty. Teraz kilka słów o gałęziach, konfliktach i scalaniu gałęzi. Każdy commit do repozytorium Hg to nowa gałąź, która potencjalnie może być niezależna od innych. Jeśli w danym momencie solucja jest edytowana przez minimum 2 użytkowników, to użytkownik dokonujący pusha jako drugi będzie poinformowany o tym, że to co do tej pory robił to osobna gałąź projektu i, żeby ją dodać do centralnego repozytorium, należy dokonać scalenia swojej gałęzi z główną gałęzią w repo. Scalenia – takie straszne w SVN i TFS – w Mercurialu są automatyczne lub prawie automatyczne (do tej pory ręcznie musiałem sprawdzić słownie 1 plik, z którym Hg nie mógł sobie poradzić. Już częściej musiałem scalać ręcznie pliki w TFS ;]). Trzeba też pamiętać o tym, że wykonując synchronizacje (obustronne) oraz scalania i inne operacje między repozytoriami, nie wpływamy bezpośrednio na nasz Working Directory (folder, w którym są pliki z naszą solucją, itd). To co po takich operacjach się stało, to zmiana stanu repozytorium – nic innego. Żeby uwzględnić zmiany z innego repozytorium w naszym katalogu z projektem należy zrobić operację Update (a dokładniej – w ogóle nie powinniśmy jej robić, ale o tym zaraz). Tyle tylko, żeby wykonać Update, nie należy mieć jakichkolwiek wyedytowanych i nie zacommitowanych plików. Update nie będzie mógł się wykonać dopóki nie odrzucimy zmian, jeśli takowe są. W takich momentach przydaje się operacja fetch, która robi lokalnego commita, automatycznie scala i wykonuje update, alternatywnie możemy ręcznie zrobić to samo :)

Brzmi może nieco nietrywialnie i niezbyt zachęcająco dla programistów, którzy “jak chcieli coś wcommitować, to klikali commit i już”, ale teraz pokażę jak skonfigurować klienta Mercuriala aby korzystanie z niego było maksymalnie uproszczone i względnie zbieżne z tym jak wyglądało to w SVN lub TFS.

Konfiguracja klienta

Jest kilka rzeczy, które trzeba zrobić bez względu na sposób zastosowania Hg. Wszystkie da się ustawić w Ustawieniach aplikacji.

  • Wprowadzenie swojej nazwy użytkownika (Commit –> Username). Ze względu na to, że pracując w niewielkiej sieci intranetowej, która sama w sobie jest zamknięta na zewnątrz nie ma potrzeby dokładniejszej autoryzacji użytkowników; działa tu mechanizm zaufania do każdej osoby, która będzie korzystała i wnosiła coś do centralnego repozytorium. Osoba może się nazwać dowolnie i pod nadanym sobie loginem czynić zmiany w repo. W przypadku, gdy chcielibyśmy wdrożyć system poza intranetem lub bardzo dokładnie dbać o to co i kto robi z repozytorium, to po stronie serwera centralnego należałoby skonfigurować jakąś metodę autoryzacji.
  • Włączyć wtyczkę fetch (Extensions –> Fetch), o której mowa była wcześniej, a która dość mocno ułatwi nam życie

Rzeczy, które warto skonfigurować dla osób migrujących się z TFS:

  • Domyślna akcja po każdym pull (czyli synchronizacji z serwera do naszego repozytorium) (Workbench –> After Pull Operation). Powinniśmy wybrać z listy fetch. Dzięki temu, ilekroć pobierzemy dane z centralnego repo, nasza lokalna solucja zostanie automatycznie i bezboleśnie zaktualizowana, czyli w domyśle wykonane będzie to, czego się domyślaliśmy, że chcieliśmy zrobić ;])
  • Automatyczny push po każdym commicie (Commit –> Push After Commit). Z listy wybieramy sobie ‘default-push’. Wybór ten oznacza, że do tego repozytorium będzie wykonany push (czyli synchronizacja do serwera)
  • Skonfigurowanie listy serwerów z repozytoriami. W naszym przypadku chcemy tylko jedno centralne, dlatego zmieniamy sobie zakładkę na Repository Settings, następnie klikamy na Edit file i dodajemy taki wpis na samym dole pliku
[paths]
default-push =  

Można oczywiście inaczej, ale tak mamy to w jednym miejscu wykonane i już dla docelowego repozytorium.

To tak tyle z grubsza z ułatwień jakie można włączyć bezstresowo w Mercurialu ku naszej wygodzie :) Teraz kilka słów o tym jak się korzysta z TortoiseHg.

Korzystanie z klienta

image

Generalnie najłatwiej i najprzyjemniej jest używać TortoiseHg Workbench do obsługi naszego projektu. Na obrazku zamieszczam wygląd Workbencha. W czerwonej, odręcznej ramce są 4 przyciski, które dość często będą wykorzystywane. Służą do synchronizowania naszego repozytorium z innymi. Od lewej: Sprawdź czy są przychodzące zmiany, Pobierz przychodzące zmiany, Sprawdź czy są wychodzące zmiany, Wyślij zmiany. W niebieskiej odręcznej ramce są zakładki, które zmieniają wygląd Workbencha. W moim przypadku był wybrany widok odpowiedni dla operacji Commit.

Przy okazji warto zauważyć widoczne po lewej stronie drzewko gałęzi, które jest dość ważne w całej pracy z Mercurialem. Za każdym razem, gdy wystąpi informacja, o tym, że nie można zsynchronizować do serwera własnych zmian, to należy rzucić okiem na ten graf. W takich sytuacjach na ogół winnym jest jeden branch, który nie łączy się z domyślną ścieżką. Na takim rekordzie należy kliknąć PPM i wybrać Merge with Local, które spowoduje zasadnicze scalenie zmian.

Całkiem długi wpis wyszedł w rezultacie :) Może poniewczasie, ale nie czujcie się zniechęceni taką ilością tekstu - migracja do Mercuriala jest naprawdę osiągalna dla większości zespołów i naprawdę taki krok pomoże w zwiększeniu produktywności oraz przyjemności z pracy wśród programistów. Poza tym – dlaczego by nie poznać nowej i innowacyjnej technologii? Czego by Microsoft nie publikował i jakby się nie chwalił, to należy pamiętać, że nie tworzy on innowacyjnych rozwiązań :]

Referencje

Abyss Underground

Abyss - URL Rewriting Tutorial

Abyss Web Server Download

Migrator repozytorium TFS –> Mercurial

HgInit - bardzo zaawansowany poradnik do Mercuriala