Blog Cover Image
20 min czytania

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 do STAGE
  • STAGE - środowisko testerskie (QA), wewnętrzne, tutaj trafiają release'y przed mergem do PROD
  • PREPROD - ś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ń klienta
  • PROD - ś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 środowiskiem PROD, zawsze (przynajmniej w teorii :D) stabilny
  • develop - 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 środowisko STAGE i ewentualnie PREPROD, branch ten jest mergowany do main po zakończeniu testów na środowisku STAGE
  • feature/XXX - branch dla konkretnego ficzera, bazowy może być branch develop lub main w zależności od potrzeb
  • bugfix/XXX - branch dla konkretnego bugfixa, bazowy może być branch develop, release/XXX w zależności od bieżących potrzeb, po zmergowaniu bugfixa nie zapomnijmy o zmergowanie do brancha bazowego - develop
  • hotfix/XXX - branch dla konkretnego hotfixa, bazowy może byc branch release/XXX lub main, po zmergowaniu hotfixa nie zapomnijmy o zmergowaniu go z powrotem do develop, 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, gdzie feat oznacza, że dodaliśmy nowy ficzer
  • fix: Fixed issue with login form validation #12, gdzie fix oznacza, że naprawiliśmy jakiś bug
  • refactor: Refactored logic for creating orders #123, gdzie refactor oznacza, że zrefaktoryzowaliśmy jakąś część kodu
  • style: Improved styles for navbar #456, gdzie style oznacza, że poprawiliśmy style
  • test: Added tests for getNavItems function #789, gdzie test oznacza, że dodaliśmy testy
  • chore: Updated dependencies #345, gdzie chore oznacza, że zrobiliśmy coś, co nie wpłynęło bezpośrednio na kod, np. aktualizacja zależności
  • docs: Updated README.md #123, gdzie docs oznacza, że zrobiliśmy zmiany w dokumentacji
  • ci: Updated CI/CD pipeline #123, gdzie ci oznacza, że zrobiliśmy zmiany w pipeline CI/CD
  • build: Updated build process #123, gdzie build oznacza, że zrobiliśmy zmiany w procesie budowania projektu
  • perf: Improved performance of getNavItems function #123, gdzie perf oznacza, że poprawiliśmy wydajność
  • security: Fixed security issue in login form #123, gdzie security oznacza, ż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 navbar to 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

  1. "Wychodzimy" z brancha develop i na jego podstawie tworzymy branch dla naszego ficzera
git checkout develop;
git pull;
git checkout -b 'feature/XXX';
  1. Robimy zmiany, commity, itp.
  2. Po zakończeniu pracy robimy Merge Request (lub jak wolicie - Pull Request) do brancha develop
  3. Po zmergowaniu kod powinien się zbudować automatycznie za pomocą CI/CD pipeline
  4. Zmiany trafiają na środowisko DEVELOP i są testowane przez developerów
  5. Po zakończeniu testów zmiany trafiają na środowisko STAGE i są testowane przez QA
  6. Po zakończeniu testów na środowisku STAGE zmiany są mergowane do brancha main czyli na środowisko produkcyjne PROD

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.

  1. "Wychodzimy" z brancha main i na jego podstawie tworzymy branch dla naszego hotfixa
git checkout main;
git pull;
git checkout -b 'hotfix/XXX';
  1. Robimy zmiany, commity, itp.
  2. Po zakończeniu pracy robimy Merge Request do brancha main
  3. Po zmergowaniu kod powinien się zbudować automatycznie za pomocą CI/CD pipeline
  4. I ostatni, bardzo ważny punkt! - Zmiany trafiają jeszcze na środowisko DEVELOP np. tworząc MR do brancha develop i 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 :)

Konrad Bysiek - avatar

Konrad Bysiek

Frontend Developer / Tech Lead