System kontroli wersji
Systemy kontroli wersji, z którymi miałem okazję się zetknąć, to (chronologicznie):
- RCS, Revision Control System, w 1997 albo 1998 r.
- CVS, Concurrent Versions System, trochę później
- VSS, Visual SourceSafe, w 2000 r.
- SVN, Subversion, w 2005.
- SVK w 2006.
- Mercurial (Hg) w 2011
- git także w 2011
Pierwszym systemem wersjonowania, z jakim miałem do czynienia był RCS (revision control system). Nadawał on się do zarządzania pojedynczymi plikami – dla każdego tworzył "archiwum" w postaci pliku w podkatalogu RCS, przechowującego wszystkie wersje. Plik do edycji należało przy pomocy odpowiednich poleceń "wyczekautować" (co)), a potem "wczekinować" (ci). RCS stosowałem całkiem długo do kontroli zmian w plikach konfiguracyjnych w /etc, w skryptach shellowych i tego typu drobiazgach. Istniały co prawda polecenia próbujące grupowo traktować szereg plików RCS w jednym katalogu (jak chociażby rcs2log), nie dało się jednak nie zauważyć, że zarządzanie poszczególnymi plikami nie było wygodne ani praktyczne w przypadkach innych niż wersjonowanie niezależnych, pojednycznych plików.
Potem poznałem CVS (Concurrent Versions System), który pozwalał operować na jednostkach składających się z wielu plików, katalogów, modułów czy projektów. W środku co prawda posługiwał się jednoplikowymi archiwami RCS, ale użytkownik nie musiał się tym przejmować a zamiast tego korzystać z komend cvs działających na większych jednostkach. Z kolei zaletą wykorzystania RCS-a było to, że można sobie było wejść do wnętrza takiego repozytorium i przy pomocy odpowiednich poleceń przeanalizować poszczególne pliki. Ale były też i wady, jak chociażby duplikownaie informacji typu log message w każdym pliku, brak jakiejkolwiek transakcyjności. Branche, które już w RCS-ie były trochę dziwaczne i polegały na zwiększaniu liczby komponentów numeru wersji pliku (np. r0.1, branch z niego: 0.1.1, pierwsza rewizja na tym branchu: 0.1.1.1), teraz, pod kontrolą CVS uzyskały zupełnie nowy wymiar udziwnienia, a przy tym ich tworzenie wiązało się z fizycznym kopiowaniem danych wewnątrz repozytorium, więc nie było szczególnie efektywne.
Zatem do kontroli większych rzeczy, wieloplikowych, jak programy etc. zacząłem używać CVS-a, ale przy wersjonowanych plikach konfiguracyjnych i przynajmniej niektórych skryptach pozostałem przy RCS-ie, o ile pamiętam. W międzyczasie miałem nieprzyjemność zapoznania się z VSS-em, narzędziem używanym w świecie windowsiarzy, ale o tym naprawdę szkoda gadać.
No i wreszcie, był rok może 2005, nastało Subversion. To znaczy, nastało pewnie trochę wcześniej, ale ja akurat wtedy się z nim zapoznałem. Początkowo twórcy SVN reklamowali go jako "lepszy CVS", "CVS zrobiony jak trzeba" albo podobnie (potem zrezygnowali z tego hasła). I rzeczywiście, SVN przyniósł kilka nowych, pozytywnych koncepcji w porównaniu do CVS, jak wersjonowanie repozytorium zamiast poszczególnych plików, śledzenie przenoszenia i zmian nazw plików i katalogów, błyskawiczne i tanie branche tworzone metodą copy-on-write i pewnie coś jeszcze, o czym akurat zapomniałem. Do tego kod był solidny a oprogramowanie stabilne.
Niestety, twórcy Subversion nie uniknęli pewnych pomysłów kontrowersyjnych, albo przynajmniej nietypowych. Chodzi mi głównie o rezygnację z obiektów typu branch czy tag i sprowadzenie wszystkiego do wersjonowanego drzewa katalogów, którego pewne części umawiamy się traktować w sposób szczególny (zalecana, "kanoniczna" struktura katalogów: trunk, branches, tags). Ten nowatorski pomysł, choć początkowo mógł się wydawać atrakcyjny (po co mnożyć byty przez wprowadzanie tagów i branchy? po prostu kopiujmy katalogi!), z perspektywy czasu oceniam jako poważny błąd projektowy. Jego konsekwencje są takie, że tak naprawdę program nigdy nie wie, co właściwie wersjonuje; to znaczy, gdzie się zaczyna projekt, czy cokolwiek chcemy wersjonować w takim repozytorium. Stąd wynika problem taki, że trudno jest traktować projekt jako całość, zwłaszcza, że w repozytorium mogą się znaleźć jakieś dodatkowo, mniej lub bardziej luźno związane z danym projektem hierarchie katalogów.
Sprawy zupełnie się pogorszyły od wersji 1.5 SVN, kiedy to autorzy postanowili w końcu zaimplementować merge tracking, czyli właściwość polegającą na rejestrowaniu rozgałęzień (branche) i złączeń (merge'owanie) historii projektu i wyciąganiu z tego wniosków mających ułatwiać pracę użytkownikom. Niestety, zupełnie sobie z tym nie poradzili. Po pierwsze ze względu na wspomnianą wyżej luźną strukturę repozytorium, nie narzucającą praktycznie żadnej sementatyki. Jak system ma śledzić branchowanie, skoro branchowanie jest tożsame z kopiowaniem, a przy tym nie musi obejmować dokładnie projektu (o którym oprogramowanie nic przecież nie wie), ale na przykład jakiś jego podzbiór, czy wręcz pojedynczy plik? A z drugiej strony, można sobie skopiować katalog nadrzędny nad tym, w którym sobie założyliśmy, że będziemy trzymać te niby-branche. Tak czy owak, praktyczny efekt na większych repozytoriach jest taki, że merge tracking w ogóle się nie nadaje do użytku i bardziej przeszkadza, niż pomaga, natomiast przykrym efektem ubocznym jest to, że jego ślady z czasem pojawiają sie w properties poszczególnych plików i katalogów w coraz większych ilościach, aż dochodzimy do absurdalnej sytuacji, że zmerge'owanie pojedynczego pliku potrafi wygenerować dziesiątki i setki modyfikacji properties w zupełnie na pozór niezwiązanych miejscach. A to praktycznie uniemożliwia śledzenie zmian w logach.
W 2006 roku zrobiło się głośniej o DVCS-ach czy DSCM-ach, czyli rozproszonych systemach kontroli wersji, ale jakoś się tym bliżej nie zainteresowałem, może dlatego, że wciąż jeszcze byłem zadowolony z efektów, jakie przyniosło porzucenie CVS-a czy VSS-a na rzecz SVN-a. Owszem, pobawiłem się chwilkę SVK, który był reklamowany jako rozproszony, no i może nawet był, ale wcale mnie do koncepcji nie zachęcił. Może dlatego, że w "bebechach" trzymał repozytorium Subversion i jego funkcjonalność była bardzo zbliżona, a w niektórych miejscach gorsza niż właśnie SVN-a. A może jego nieintuicyjna organizacja? Centralny "depot" w katalogu domowym, w nim 1 lub więcej repozytoriów SVN, każde zawierające katalog "mirror", służący do synchronizacji ze zdalnym repozytorium (push i pull) oraz jego kopię "local", służącą do edycji lokalnej (checkout i commit).
Tak czy siak, trwałem przy Subversion, choć od czasu do czasu czytałem coś zachęcającego o systemach rozproszonych. Ale chyba tak naprawdę zaintrygował mnie tym Joel na swoim blogu gdzieś na początku roku 2010. Musiał jednak minąć kolejny rok, bym się tym zajął poważniej i dopiero w 2011 przeczytałem do końca HgInit i zacząłem się bawić Mercurialem. Wkrótce pojawiło się pytanie: a może jednak Git? Który lepszy i dlaczego? Poznałem podstawy obu, raz się skłaniałem ku jednemu, raz ku drugiemu. Postanowiłem się skupić najpierw na Mercurialu, nauczyć się go używać w trochę większym niż podstawowy zakresie a Gita uczyć się przez porównanie, ewentualnie zagłębić się w niego później. Dopiero gdy lepiej poznam oba, będę mógł w miarę obiektywnie odpowiedzieć sobie na pytanie: Git czy Mercurial?
[edytuj] Linki
Interesujące linki związane z tematem.
- http://whygitisbetterthanx.com/ – strona próbująca dowieść wyższości gita nad wszystkim innym
- Understanding Darcs: Patch theory
- Merging vcproj files - SCM's hell
- UCM Central - Configuration Management Branching Strategy
- Advanced SCM Branching Strategies by Stephen Vance, 1988, wraz ze slajdami
- Source Control HOWTO by Eric Sink
- Version Control by Example by Eric Sink