Git jako narzędzie rozproszonego systemu kontroli wersji jest obecnie standardem ułatwiającym zespołom programistycznym rozwój oprogramowania, a jego znajomość jest w zasadzie niezbędna aby być efektywnym developerem. Skuteczne zarządzanie kodem przy użyciu tego narzędzia przyczynia się do zwiększenia jakości, wydajności i stabilności projektów programistycznych z wielu powodów:

  • śledzenie zmian - możemy łatwo przejrzeć historię projektu, zrozumieć kto, kiedy i dlaczego wprowadził określoną zmianę
  • współpraca - wielu programistów może jednocześnie pracować nad projektem niezależnie
  • zarządzanie wersjami - utrzymanie wielu różnych wersji oprogramowania
  • łatwe wycofywanie zmian - łatwe cofanie się do poprzednich stanów projektu
  • bezpieczeństwo przed utratą danych

W tym artykule przybliżę trzy najpopularniejsze strategie zarządzania kodem:
GIT Flow, GitHub Flow i Trunk Based Development.

GIT Flow

Podejście zakłada, że pracujemy na wielu branchach:

  • main (lub master) - powinien być zgodny z kodem, który jest na produkcji
  • develop - kopia brancha main z wszystkimi innymi zmianami, które zostały dodane od ostatniego release
  • feature - developerzy odbijają się od brancha develop tworząc brancha feature np. feature/new-auth-method lub bug/fix-some-bug w zależności od rodzaju zgłoszenia
  • release - jak developerzy wykonali swoją pracę nowy branch jest tworzony od brancha develop aby stworzyć release np. release/1.2.3
  • hotfix - jeżeli jest pilna potrzeba poprawienia buga na produkcji tworzymy brancha hotfix odbijając się od main np. hotfix/INC3458-xyz

Flow programisty:

  1. Dla nowych projektów tworzony jest branch main (lub master)
  2. Następnie branch develop jest odbijany od brancha main. Nie dokonujemy żadnych zmian bezpośrednio na branchu main czy też develop.
  3. Programiści odbijają się od brancha develop tworząc feature branche i pracują nad swoimi zmianami. Czasem zajdzie potrzeba merga develop -> feature jeśli implementacja feature długo trwa i trzeba zintegrować się z innymi zmianami (rekomendowanym podejściem jest użycie rebase).
  4. Gdy feature jest gotowy tworzymy pull requesta do developa. Inni członkowie zespołu robią code review zmian. Jeżeli są konflikty najpierw trzeba je rozwiązać zanim będziemy mogli zmergować zmiany do developa. Warto aby w ramach danego PR uruchamiał się jakiś proces automatyczny, który zweryfikuje czy nic nie popsuliśmy czy testy przechodzą itd.
  5. Jak już wszystkie zmiany pod danego release zostaną wykonane release branch jest tworzony odbijając się od brancha develop. QA Team wykonuje testy tego release przed wdrożeniem na produkcje. W międzyczasie developerzy mogą kontynuować prace na developie jeżeli chodzi o funkcjonalności pod kolejny release.
  6. Gdy jesteśmy pewni, że release został w pełni przetestowany tagujemy wydanie odpowiednią wersją i mergujemy release do main (master).
  7. Po wydaniu wersji mergujemy main do develop aby upewnić się, że wszystkie zmiany wykonywane podczas testów są uwzględnione i spójne z branchem develop.
  8. Jeżeli wystąpi pilny problem na produkcji tworzymy brancha hotfix naprawiamy wystawiamy PR następnie po code review mergujemy do main i develop i tagujemy wersje.

Dlaczego warto odbijać się od mastera?

Odbicie feature brancha od mastera pozwala nam na wdrożenie danego feature w oderwaniu od release'a. W momencie jak biznes się decyduje, że dany feature ma nie wejść unikamy wielu revert'ow. W takim przypadku tworzymy nowego release brancha z mastera i mergujemy wszystkie tylko interesujące nas feature branche. W takim podejściu ważne jest aby nie usuwać feature branchy od razu po mergu do release'a tylko w momencie wdrożenia zmian na produkcję. Wszystkie poprawki dotyczące funkcjonalności powinny trafiać na odpowiedni feature branch (nie powinno być commit'ow bezpośrednio do developa, release czy mastera).

Zalety:

  • pozwala pracować na wielu release'ach jednocześnie
  • łatwo śledzić poszczególne wydania gdyż jest wiele branchy i każdy ma swoje przeznaczenie
  • pozwala na łatwe przełączanie się pomiędzy tym nad czym pracujemy a innymi wydaniami ponieważ "żyją" one w różnych branchach
  • sprawdza się zwykle gdy rzadko wdrażamy zmiany na produkcje np. raz na kilka tygodni lub rzadziej
  • sprawdza się gdy musimy wspierać wiele różnych wersji i robić fixy do tych wersji oraz zachować kompatybilność wsteczną

Wady:

  • słabo się sprawdza w kontekście CI/CD
  • wiele branchy, które trzeba utrzymywać i pamiętać aby zachowywały spójność mergować itd, mija sporo czasu zanim zmiany zostaną zmergowane do mastera i jeszcze więcej czasu zanim inni developerzy lub zespoły zintegrują swoje zmiany z zmianami innych nie wspominając o konfliktach po drodze
  • z uwagi na to, że wydanie jest dość złożone dług technologiczny rośnie

GitHub Flow

Strategia używana przez Githuba. Podejście zakłada, że mamy tylko dwa branche:

  • main (lub master) - podobnie jak w git flow, branch posiada wszystkie stabilne zmiany projektu
  • feature - programiści odbijają się bezpośrednio od main aby pracować nad nowymi funkcjonalnościami

Flow programisty:

  1. W przypadku nowego projektu tworzymy pusty branch master.
  2. Aby wprowadzić zmianę odbijamy się od brancha master i tworzymy feature branch.
  3. Gdy branch feature jest gotowy, przetestowany, a code review zrobione mergujemy do mastera.
  4. Gdy branch feature został zmergowany do mastera powinien być od razu zrobiony release zmian na produkcje.

W przeciwieństwie do Git Flow nie ma tu koncepcji brancha release. Każdy feature tworzy swój własny "release" w związku z tym wszystko zmergowane do mastera powinno tworzyć stan stabilny i deployowalny. Dzięki temu zespoły mogą wdrażać zmiany na produkcje kilka razy dziennie zamiast na koniec sprintu. W celu tak szybkiego wdrażania zmian i robienia wydań należy mieć solidne testy automatyczne.

Zalety:

  • pozwala na wdrożenie CI/CD
  • zachęca zespoły do wdrażania często dzięki czemu szybko mogą uzyskać feedback z pracy, którą wykonali
  • mniejsza szansa na wytworzenie długu technicznego

Wady:

  • wymaga solidnych testów automatycznych i automatycznego procesu release'owego
  • trzeba być ostrożnym ponieważ każdy błąd zmergowany do mastera pójdzie bezpośrednio na produkcje

Trunk Based Development

Trunk-Based Development For Smaller Teams
Scaled Trunk-Based Development

Trunk-Based development to praktyka, w której developerzy mergują często małe zmiany do jednego core'owego brancha trunk lub main (single source-of-truth) zamiast utrzymywać długotrwałe gałęzie. Pomaga to sprawnie wdrażać zmiany i osiągać CI/CD.

W przeciwieństwie do innych strategii, które używają oddzielnych branchy do release'owania zmian w TBD trunk jest tzw. jednym źródłem prawdy wszystkich release'ow na produkcje.

W TBD teoretycznie każdy commit nadaje się do wdrożenia na produkcję. Ta idea pozwala na bardziej elastyczne i częstsze wdrożenia zmian na produkcję i skrócenie time-to-market.

Stosując TBD zmiany są wdrażane na bieżąco, co minimalizuje czas w jakim kod różnych programistów jest oddzielony. Wdrożenia są częstsze,  co ułatwia śledzenie błędów i umożliwia dostarczanie funkcji szybciej.

W celu zastosowania TBD, zespoły programistyczne powinny często łączyć swoje zmiany z gałęzią główną. Wprowadza to zasady takie jak Feature Flags, które pozwalają na tymczasowe wyłączanie kodu, co umożliwia łączenie różnych funkcji niezależnie od ich gotowości do wdrożenia. Niezbędne jest również stosowanie praktyk takich jak automatyczne testy aby zapewnić, że łączone zmiany nie wprowadzają nowych błędów.

Podstawowe założenia TBD:

  • ciągła integracja z głównym branchem trunk
  • używanie short-term feature branchy
  • bezpieczne techniki deploymentowe, częste release'owanie zmian na produkcję z trunk'a
  • utrzymanie bardzo wysokiego pokrycia kodu aby zminimalizować ryzyko wdrożenia bugow na produkcję
  • użycie feature flags jest niezbędne (commitujemy zmiany dot. feature, które jeszcze jest inprogress)
  • silne nastawienie na automatyzacje, automatyczny deployment testy itd.
  • częste merge do trunk'a zmuszają do wytwarzania małych zmian, kod powinien być zawsze gotowy do wdrożenia na produkcję
  • częste wdrożenia

W przeciwieństwie do innych strategii gdzie branche mogą istnieć tygodnie lub nawet miesiące w TBD branche są tymczasowe co oznacza, że programiści tworzą branche typu feature lub fix i mergują je zwykle do trunk'a w ciągu jednego dnia i usuwają tego brancha. Ta metoda minimalizuje ryzyko napotkania na konflikty a codebase jest bardziej uporządkowany i zorganizowany.

CI & Testy

Continuous Integration jest bardzo istotne w TBD. Z uwagi na to, że programiści bardzo często commitują do trunk'a (mastera) zachodzi potrzeba ciągłej integracji tj. budowania i testowania zmian automatycznie i ogólnie sprawdzania jakości kodu aby upewnić się, że zmiana nie psuje mastera czy też nie ma konfliktu z innymi zmianami. Proces CI powinien automatycznie sprawdzać zmiany dokonane na masterze utrzymując głównego brancha w dobrej kondycji, zawsze gotowego do wdrożenia na produkcję. Każdy commit należy interpretować jako potencjalnie kolejny release. Dzięki temu mamy szybsze cykle wdrożeniowe i niski time-to-market.

Jaką strategię wybrać?

Wybów odpowiedniej strategii branchowania jest istotny, ponieważ wpływa na sposób, w jaki zespoły współpracują nad projektem, zarządzają kodem, wdrażają zmiany i zależy od charakterystyki projektu, wymagań biznesowych i preferencji zespołu. Git Flow jest bardziej skomplikowany ale zapewnia kontrolę nad procesem, nadaje się do projektów wymagających jasno określonych wydań, szczegółowego planowania i testowania. GitHub Flow jest prosty i dynamiczny, efektywny w projektach wymagających ciągłego wdrażania i szybkiego dostarczania nowych funkcji. TBD sprawdza się w projektach wymagających szybkiego wdrażania, minimalizuje konflikty i utrzymuje prostotę, jednak należy pamiętać, że wymaga całej otoczki automatyzacji, która pozwoli bezpiecznie wdrażać zmiany na produkcję.

Podsumowanie

Mam nadzieję, że w klarowny i zrozumiały sposób wyjaśniłem Tobie czym charakteryzują się rożne strategie branchowania i zarządzania kodem. Jeżeli ten artykuł był dla Ciebie wartościowy podziel się nim z innymi. Tymczasem zostawiam Cię w klimacie progresywnego house mojego autorstwa, do usłyszenia!