Narzędzia

Automatyzacja merga w git.

Automatyzacja merga w git

Całkiem niedawno (bo blog jest od początku roku) popełniłem wpis traktujący o skrypcie, którego używam jak robię merge. Skrypt miał sporo plusów (głównie dzięki git oraz niesamowitej prostocie ocierającej się o prostactwo) i jeszcze więcej minusów. Trzeba było pamiętać (co to za automatyzacja) i przy zakładaniu nowych branchy dopisywać je do skryptów ręcznie. Do tego jak wystąpiły konflikty cały skrypt “jechał” dalej i tylko dzięki temu, że git wie co robi nic się nie działo. Ponieważ niedługo zmieniam pracę naciskałem by to poprawić. Niedawno udało mi się usiąść z moim guru i wykoncypować coś takiego:

Skrypt ten służy do robienia mergy, ale elementy tego skryptu mogą przydać się do wielu rzeczy. I wiele problemów takie narzędzia mogą rozwiązać. Dobierzemy się do tego skryptu linijka po linijce, ale najpierw wytłumaczę po co nam skrypt do mergowania.

O branchowaniu słów kilka

Posiadamy kilka gałęzi które zawarte są w odgałęzieniach nazwanych masters i releases. Kolejna wersja programu ma odzwierciedlenie tak w releases jak i masters. W podgałęzi releases posiadamy tylko wersje do wydania na zewnątrz. W podgałęzi masters wersje główne. Gałęzie zawarte w masters na razie trzymamy (może później będą usuwane), gałęzie w releases są mergowane do odpowiedniej gałęzi w masters, tagowane i usuwane. W takim przypadku możemy mieć np. takie gałęzie:

masters/ver1

masters/ver2

releases/ver2release1

masters/ver3

releases/ver3release2

master

Gałęzie releases wychodzą z gałęzi masters, po wydaniu wszystkie zmiany wracają do odpowiednich gałęzi masters. W gałęzi master dzieje się kodowanie kolejnych wersji i z niej wychodza kolejne gałęzie z podgałęzi masters. Trochę to skomplikowane i podobne do gitflow. Generalnie jest to wariacja pozwalająca wydawać kilka wersji na raz, bo to była zastana sytuacja w trakcie przejścia na git. Teraz sytuacja się normuje i możliwe, że uda się przejść na normalny git flow.

Ale przy tylu gałęziach nasze mergowanie wygląda tak.

masters/ver1 ->  masters/ver2 -> releases/ver2release1 -> masters/ver3 -> releases/ver3release2 -> master

Pierwsze koty za płoty, czyli jak pobrać branche z gita

Mam nadzieję, że już uzbrojeni w wiedzę o specyficznym branchowaniu możemy zająć się skryptem. Oto jego pierwsza ważna albo może nawet najważniejsza linijka:

W niej do zmiennej mergeBranches przypisuję branche remote wybrane z podgałęzi masters i releases za pomocą programu grep. Potem za pomocą awk dzielę każdą z nazw na człony rozdzielone znakiem / i wypisuję je w odpowiedniej kolejności. Awk można użyć mniej więcej jak split w .Net. Za chwilę to rozrysuję tylko dokończmy tą linijkę. Potem program sort sortuje je, a na koniec za pomocą programu cut wypisuję tylko 2 część tego co rozbiłem za pomocą awk. “branch_koncowy” jest dopisanym elementem tablicy.

Jak powiedziałem wyżej awk działa podobnie jak split. W powyższej funkcji awk zostało użyte w ten sposób:

origin/masters/ver1 zostało rozbite na origin, masters, ver1, a potem zapisane jako ver1 <tabulator> masters/ver1. Dlaczego tak? Ponieważ potrzebuję posortować gałęzie po numerze wersji, a nie po słowie masters czy releases tak, aby mergowanie przebiegało po wersjach z mastersów do releasów i w górę. Cut podzielił posortowany wynik działania programu awk na elementy ver1, masters/ver1 i wypisał tylko ten drugi człon. Tu zamiast cut można by użyć awk, ale cut jest prostsze, przy czym nie ma zaawansowanych możliwości takich jak awk.

Wszystkie programy zostały połączone za pomocą pionowej linii | tzw. “pipe”. Oznacza on “użyj wyjścia programu po lewej stronie znaku | jako wejścia do programu po jego prawej”.

Nowa zmienna

Tu tworzę nową zmienną i nadaję jej wartość false. Będzie mi ona potrzebna jeśli bym chciał uruchamiać nasz skrypt zupełnie automatycznie, bez interakcji z użytkownikiem.

Argumenty działania skryptu

Skrypt bashowy jak każdy program, który w windowsie nazywa się konsolowy może przyjmować argumenty swego wywołania. Powyżej funkcja while getopts ma podane możliwe opcje “fhn”i rzutuje je na zmienną opt. W case sprawdzam która z nich jest aktywna i wykonuję poszczególne działania. Jeśli -f to ustawiam force na true i kontynuuję program. Jeśli -h wyświetlam help, a jeśli -n to pokazuję ścieżkę mergowania, która zostanie użyta.

Prawdziwa akcja toczy się tu

Powyżej iteruję się po iteratorze tablicy. Jednym słowem w zmiennej “i” będę miał kolejny index tablicy, który jest aktualnie procesowany. Sam merge jest prostym zestawem działań. Przełącz się na aktualny branch, ściągnij zmiany, jeśli nie jest to pierwszy branch w tablicy, to merguj do niego poprzedni branch. Wszystko jest poprzetykane 2 rodzajami działań. $? przechowuje rezultat ostatnio wykonanej operacji. Jeśli zakończy się ona powodzeniem $? == 0. Jeśli nie $? != 0. W bashu == 0 to -eq 0 (equal), a != 0 to -ne (not equal). Można też zauważyć, że w przypadku automatu wykonywanego na maszynie nie związanej z człowiekiem (Jenkins na ten przykład), merge jest abortowany. Jeśli jest wykonywane na maszynie programisty, bez force, skrypt jest zakańczany, a w gicie ma prawdopodobnie konflikty do rozwiązania. Jako tip dopisałem, że na maszynie gdzie jest pełny automat, by to działało, należy jeszcze przeiterować się do tyłu po branchach i wycofać je ( git reset –hard HEAD) do poziomu brancha remote.

Wszystko co ma początek koniec musi mieć

Na sam koniec chcę wypchnąć zmergowane gałęzie na serwer. Oczywiście jeśli robi to automat i dobrnął aż tutaj, po prostu robi push i już. Natomiast jeśli uruchamia to developer lub inny członek drużyny (nie pierścienia 🙂 ) zobaczy najpierw loga z wszystkich gałęzi. Po sprawdzeniu czy wszystko się zgadza, wyświetlony zostanie komunikat, czy użyszkodnik chce wysłać zmiany na serwer, a po podaniu y lub Y zmiany zostaną wysłane.

Jak Wam się podoba taki update skryptu? Widzie jakieś ciekawe miejsca gdzie moglibyście zastosować fragmenty tego skryptu, np. inne niż mergowanie?

1 thought on “Automatyzacja merga w git.

  1. Pingback: dotnetomaniak.pl

Leave a Reply

Your email address will not be published. Required fields are marked *