
Organizacja Git flow
Jeśli jesteś na etapie startu projektu i wspólnie z zespołem ustalacie zasady, którymi zamierzacie się kierować przy pracy z systemem kontroli wersji GIT lub czujecie, że wasze obecne flow jest nieefektywne, to ten poradnik jest właśnie dla was.
Opiszę jedną z wielu możliwych ścieżek, którą często wykorzystuję w małych i średniej wielkości projektach (i zespołach). Z tego poradnika dowiesz się jak:
- tworzyć branche
- nazywać poprawnie commity
- tworzyć Merge Requesty (MR)
- organizować środowiska
Dlaczego jasno określonego Git Flow jest bardzo ważne?
- ułatwia współpracę w zespole
- zwiększa jakość kodu
- ułatwia debugowanie
- zwiększa profesjonalizm
- oszczędza czas
Poradnik zachęcam dostosować do swoich potrzeb i specyfiki Waszego projektu, ja skupię się na dość generycznym podejściu, które sprawdza się w wielu projektach. Bez zbędnych ceregieli, zaczynajmy!
Aby mówić tym samym językiem, zacznijmy od zdefiniowania kilku pojęć i konwencji nazewniczych, które będą nam towarzyszyć w dalszej części poradnika.
Terminologia
Środowiska:
DEVELOP- środowisko developerskie, wewnętrzne, tutaj testujemy zmiany przed mergem doSTAGESTAGE- środowisko testerskie (QA), wewnętrzne, tutaj trafiają release'y przed mergem doPRODPREPROD- środowisko przedprodukcyjne, wewnętrzne i zewnętrzne, może służyć do testów akceptacyjnych klienta, może zostać pominięte w zależności od wielkości projektu i oczekiwań klientaPROD- środowisko produkcyjne, finalne, tutaj trafia kod, który jest gotowy do użytku, przetestowany i zatwierdzony
Branche:
main- główny branch produkcyjny, ściśle powiązany ze środowiskiemPROD, zawsze (przynajmniej w teorii :D) stabilnydevelop- branch developerski, bazowy dla wszystkich ficzerów, może być chwilowo niestabilny, służy głównie do testów dla developerów przez oddaniem zadania do QA,release/XXX- branch releasowy, wersja, która trafia na środowiskoSTAGEi ewentualniePREPROD, branch ten jest mergowany domainpo zakończeniu testów na środowiskuSTAGEfeature/XXX- branch dla konkretnego ficzera, bazowy może być branchdeveloplubmainw zależności od potrzebbugfix/XXX- branch dla konkretnego bugfixa, bazowy może być branchdevelop,release/XXXw zależności od bieżących potrzeb, po zmergowaniu bugfixa nie zapomnijmy o zmergowanie do brancha bazowego -develophotfix/XXX- branch dla konkretnego hotfixa, bazowy może byc branchrelease/XXXlubmain, po zmergowaniu hotfixa nie zapomnijmy o zmergowaniu go z powrotem dodevelop, aby kod był spójny
Commity:
Commity powinny być jasne, precyzyjne i zrozumiałe dla innych developerów. Warto dodać identyfikator zadania (np. "#14") na końcu wiadomości commita, co ułatwia powiązanie zmian z konkretnym zadaniem w systemie zarządzania projektami. Później można podlinkować sobie konkretne commity z systemem w których mamy zdefniowane taski, co ułatwia debugowanie i development chociażby z pomocą wtyczki Git Lens w Visual Studio Code. Jednak żeby takie commity miały sens, a nie były tylko jakimś "checkpointem" w historii naszego kodu, warto kierować się następującymi zasadami:
- powinny jasno opisywać, co zostało zrealizowane w danym commicie
- nie powinny być niejasne, nieprecyzyjne lub niedbałe
- nie powinny zawierać zbyt wielu zmian w jednym commicie
- powinny być pisane w języku angielskim, nawet jeśli projekt jest w języku polskim
- warto dodać identyfikator zadania na końcu wiadomości commita, co ułatwia powiązanie zmian z konkretnym zadaniem w systemie zarządzania projektami
- warto stosować określoną konwencję, o której więcej informacji zanjdzięcie w kolejnym paragrafie
Konwencje dla wiadomości commitów:
feat: Added hamburger menu in TopBar #17, gdziefeatoznacza, że dodaliśmy nowy ficzerfix: Fixed issue with login form validation #12, gdziefixoznacza, że naprawiliśmy jakiś bugrefactor: Refactored logic for creating orders #123, gdzierefactoroznacza, że zrefaktoryzowaliśmy jakąś część kodustyle: Improved styles for navbar #456, gdziestyleoznacza, że poprawiliśmy styletest: Added tests for getNavItems function #789, gdzietestoznacza, że dodaliśmy testychore: Updated dependencies #345, gdziechoreoznacza, że zrobiliśmy coś, co nie wpłynęło bezpośrednio na kod, np. aktualizacja zależnościdocs: Updated README.md #123, gdziedocsoznacza, że zrobiliśmy zmiany w dokumentacjici: Updated CI/CD pipeline #123, gdziecioznacza, że zrobiliśmy zmiany w pipeline CI/CDbuild: Updated build process #123, gdziebuildoznacza, że zrobiliśmy zmiany w procesie budowania projektuperf: Improved performance of getNavItems function #123, gdzieperfoznacza, że poprawiliśmy wydajnośćsecurity: Fixed security issue in login form #123, gdziesecurityoznacza, że naprawiliśmy problem z bezpieczeństwem
itd... pewnie można by jeszcze długo wymieniać, ale to już zależy od Was i Waszego projektu, ważne, żeby były spójne i zrozumiałe dla wszystkich w zespole.
Trzymanie się zasad zwiększa profesjonalność i jakość kodu bez dodatkowego nakładu pracy - to tylko kwestia zdefiniowania tych zasad i konsekwentnego ich przestrzegania. Warto takie zasady umieścic w README, aby deweloperzy nie musieli się długo zastanawiać jaką nazwę powinien mieć branch czy jak nazwać commita.
Dla kontrastu podam kilka przykładów jak NIE pisać treści commitów:
fix(nie wiadomo co zostało naprawione)code review fixes(brak konkretów)created component(jaki komponent?)Created Toolbar component, created related ToolbarStore, integrated notifications with API(zbyt wiele zmian w jednym commicie, ale i tak lepiej niż poprzednie przykłady :))Dodałem navbar #12(zachowujmy spójny język - najlepiej angielski)#12 Added navbarto już lepiej, ale jest tutaj mały szkopuł - wiadomość rozpoczyna się od#co może byc problematyczne w niektórych narzędziach, chociażby podczas interaktywnego rebase'u (git rebase -i __COMIT_SHA__)
Polecam już wcześniej wspomnianą wtyczkę GitLens w Visual Studio Code - powyższe reguły nabiorą jeszcze więcej sensu i praca z kodem stanie się dużo przyjemniejsza :)
Jeśli już znamy zasady pisania commitów, wiemy jak tworzyć branche, oraz jakie mamy środowiska, to możemy przejść do opisu jak wyglądać będzie nasz workflow.
Workflow dla tworzenia feature'a
- "Wychodzimy" z brancha
developi na jego podstawie tworzymy branch dla naszego ficzera
git checkout develop;
git pull;
git checkout -b 'feature/XXX';
- Robimy zmiany, commity, itp.
- Po zakończeniu pracy robimy Merge Request (lub jak wolicie - Pull Request) do brancha
develop - Po zmergowaniu kod powinien się zbudować automatycznie za pomocą CI/CD pipeline
- Zmiany trafiają na środowisko
DEVELOPi są testowane przez developerów - Po zakończeniu testów zmiany trafiają na środowisko
STAGEi są testowane przez QA - Po zakończeniu testów na środowisku
STAGEzmiany są mergowane do branchamainczyli na środowisko produkcyjnePROD
Tworzenie bugfixa wygląda podobnie, z tą różnicą, że bazą jest branch develop lub release/XXX w zależności od potrzeb.
Workflow dla tworzenia hotfixa
Hotfix jak sama nazwa wskazuje jest "hot" czyli pilny, więc nie ma czasu na testy na środowisku STAGE, dlatego zazwyczaj hotfixy mergujemy od razu do brancha main i potem z powrotem do develop.
- "Wychodzimy" z brancha
maini na jego podstawie tworzymy branch dla naszego hotfixa
git checkout main;
git pull;
git checkout -b 'hotfix/XXX';
- Robimy zmiany, commity, itp.
- Po zakończeniu pracy robimy Merge Request do brancha
main - Po zmergowaniu kod powinien się zbudować automatycznie za pomocą CI/CD pipeline
- I ostatni, bardzo ważny punkt! - Zmiany trafiają jeszcze na środowisko
DEVELOPnp. tworząc MR do branchadevelopi mergując go tam, aby kod był spójny. Lub robiąc to w sposób bardziej manualny:
git checkout develop;
git pull;
git pull origin main;
Podsumowanie
W powyższym poradniku przedstawiłem jedno z wielu możliwych podejść do organizacji pracy z systemem kontroli wersji GIT. Warto zaznaczyć, że nie ma jednego, uniwersalnego rozwiązania, które sprawdzi się w każdym projekcie. Dlatego zachęcam do eksperymentowania, dostosowywania i testowania różnych rozwiązań, aby znaleźć to, które najlepiej sprawdzi się w Waszym zespole i projekcie.
Objaśnienie skrótów
- GIT - System kontroli wersji służący do zarządzania historią zmian w kodzie źródłowym
- DEVELOP - Środowisko developerskie, wewnętrzne, służące do testowania zmian przed mergem do środowiska STAGE
- STAGE - Środowisko testerskie (QA), wewnętrzne, gdzie trafiają release'y przed mergem do PROD
- PREPROD - Środowisko przedprodukcyjne, wewnętrzne i zewnętrzne, służące m.in. do testów akceptacyjnych klienta
- PROD - Środowisko produkcyjne, finalne, gdzie trafia kod gotowy do użytku, przetestowany i zatwierdzony
- QA - Quality Assurance - Zapewnienie Jakości, proces weryfikacji jakości oprogramowania
- CI/CD - Continuous Integration/Continuous Deployment - Ciągła Integracja/Ciągłe Wdrażanie, praktyki automatyzacji procesu budowania, testowania i wdrażania oprogramowania
- MR - Merge Request - żądanie scalenia zmian z jednego brancha do drugiego (w GitLab)
- PR - Pull Request - żądanie scalenia zmian z jednego brancha do drugiego (w GitHub)
- feat - Feature - nowa funkcjonalność w konwencji commitów
- fix - Naprawa błędu w konwencji commitów
- refactor - Refaktoryzacja kodu bez zmiany jego funkcjonalności w konwencji commitów
- README - Plik dokumentacji projektu zawierający podstawowe informacje o projekcie i instrukcje
Linkografia do dalszej exploracji :)
- Oryginalny artykuł o Git Flow autorstwa Vincenta Driessena
- Gitflow Workflow - przewodnik Atlassian
- Conventional Commits - specyfikacja konwencji commitów
- GitLens - rozszerzenie do VS Code ułatwiające pracę z Git
- Automatyzacja procesów CI/CD w projektach webowych
- Pro Git - darmowa książka o Git
- Code Review - najlepsze praktyki dla zespołów deweloperskich
- Różne podejścia do Git workflow według GitLab
Konrad Bysiek
Frontend Developer / Tech Lead