Konflikty

Konflikt to sytuacja, gdy dwie osoby (lub więcej) równocześnie zmieniają to samo. Ten sam plik, ten sam moduł, ten sam zasób. Zmiany mogą być jakoś powiązane (ekstremalnie - gdy obaj zajmują się tym samym błędem), ale częściej nie mają związku, ot - Kazio dodaje jedną, a Jasio drugą pomocniczą funkcję czy deklarację.

Blokady

Prymitywne narzędzia zarządzania wersjami próbowały takie przypadki wykluczyć, zwykle stosując technikę nakładania blokad (locking). Kazio przed rozpoczęciem edycji nakładał blokadę, a Jasio ... musiał czekać na jej zwolnienie. Wiadomo kto ma prawo edytować dany plik w danej chwili, konfliktów nie będzie.

W pewnych specyficznych sytuacjach jest to podejście rozsądne, w zdecydowanej większości - koszmarne. Projektanci systemów baz danych wiedzą, że algorytmy sensownego szeregowania blokad są trudne. A ludzie wykonują takie algorytmy bardzo źle. Kazio zapomina zwolnić blokadę, Jasio ją założyć, nieraz dochodzimy do sytuacji gdy pierwszy przychodzący do pracy rezerwuje sobie wszystkie istotne pliki, a reszta może iść na ryby. A nawet przy najlepszej woli i dyscyplinie wszystkich zainteresowanych, realizowanie większych zmian staje się bardzo trudne (chciałbym zreorganizować trochę kod, muszę rozgrzebać piętnaście plików, zajmie mi to około tygodnia, weźcie może urlop...).

Połącz nim oddasz

Następna generacja narzędzi zarządzania wersjami zaczęła tę sytuację oswajać przy pomocy techniki łączenia zmian (merge-and-commit). Nie ma żadnych blokad, edytujesz co chcesz, ale gdy chcesz zatwierdzić (oddać do repozytorium) swoje zmiany, następuje sprawdzenie, czy inni czegoś nie zmieniali w międzyczasie. Jeśli tak - zatwierdzenie jest niemożliwe. Musisz najpierw pobrać zmiany wykonane przez inne osoby. Narzędzie spróbuje automatycznie je połączyć (w szczególności sytuacje typu Kazio dodał coś na początku pliku a Jasio pod koniec nie sprawiają większych problemów), a tam, gdzie będzie to niemożliwe, oznaczy konflikty wymagające rozwiązania. Programista rozwiąże te problemy i wtedy odda połączoną wersję.

Działa to bardzo fajnie przy mniejszych zmianach i ograniczonej grupie zmieniających, znacznie gorzej gdy niektóre zmiany są duże albo programistów wielu. Klasyczny scenariusz - Jasio wprowadza jakąś stosunkowo sporą zmianę i gdy chce ją oddać, nagle napotyka na serię zmian wprowadzonych przez inne osoby. Kod Jasia zostaje wymieszany z serią różnych poprawek, które trudno mu jednoznacznie ocenić. Zamiast myśleć o dokończeniu swojej pracy, musi analizować poprawki innych osób i decydować w jakiej mierze są one zgodne z jego pracą a w jakiej nie, i co począć jeśli np. idą w innym kierunku. I nie ma sposobu, by Jasio przekazał ten problem do rozwiązania komu innemu.

Ponadto, czasami kod może się ładnie połączyć ale ... wymieszać poprawki, które wymieszane być nie powinny (np. pilną poprawkę błędu z zaczątkami prac nad sporą nową funkcją). Taki problem wychodzi na jaw później, przy próbach przygotowania dystrybucji.

Oddaj a potem połącz

Remedium na tego typu kłopoty jest idea oddaj nim połączysz (commit-and-merge). Tutaj - autor zmiany oddaje ją (commituje), nie musząc się na tym etapie kłopotać konfliktami. Jeżeli inni programiści równocześnie także coś zmieniali, powstają równoległe gałęzie rozwoju kodu. Dopiero potem ktoś (niekoniecznie autor poprawek, czasem ktoś, kto pełni rolę opiekuna danego modułu czy programu) łączy zmiany. Nie trzeba robić tego od razu, można wcześniej zamknąć realizowaną pracę i zebrać niezbędne informacje. Można też wybierać, które gałęzie kiedy zostaną połączone.

Technika ta jest modna obecnie, ale tak naprawdę bardzo stara. Odwieczna konwencja wysyłania i integrowania patchy to nic innego, jak właśnie ręczna implementacja idei commit-and-merge. Autor zmiany agreguje swoje zmiany tworząc patch, opiekun programu decyduje kiedy i jak je włączyć i zintegrować z innymi zmianami. Temu samemu służy technologia gałęzi (branch) dostępna w wielu narzędziach zarządzania wersjami różnych generacji (choćby CVS czy Subversion), niestety - zwłaszcza ze względu na prymitywną i trudną w użyciu implementację w CVS - miewająca nienajlepszą sławę.

W przypadku systemów rozproszonych (DVCS, więcej o nich w osobnym artykule) optymalna obsługa zasady commit-and-merge staje się główną zasadą działania.

komentarze obsługiwane przez Disqus