Co to jest repozytorium kodu GIT a GitFlow?

07-01-2025 | 08:00
Komentarze (0) 0
Repozytorium
GIT to najpopularniejszy system do zarządzania wersjami kodu źródłowego, czyli repozytorium kodu. GIT umożliwia łatwą współpracę, śledzenie historii zmian, a także sprawia, że praca nad projektem staje się bardziej uporządkowana.

Polecane

Repozytorium kodu GIT a GitFlow Repozytorium kodu GIT a GitFlow

Witajcie! W końcu napisałem na blogu informatycznym o repozytorium kodu GIT. Planowałem i odkładałem napisanie tego materiału od kilku lat. Wielokrotnie myślałem, że wszyscy wiedzą, co to jest GIT, GitFlow, GitHub itd. Wszyscy programiści używają GIT, więc po co o tym pisać? Poza tym w internetach jest milion i mały miliardzik artykułów o GIT. Po co pisać kolejny materiał? A jednak, jakie było moje zdziwienie, kiedy poznałem kilku programistów, posiadających wieloletnie doświadczenie w branży, a... nie posługujących się GIT'em wcale! Czyli jednak muszę napisać obszerny materiał o podstawach GIT.

Co to jest Git?

GIT to narzędzie programistyczne, czyli oprogramowanie, które pozwala na magazynowanie plików z kodem źródłowym, śledzenie historii zmian, zarządzanie wersjami kodu. Kiedy pracujemy nad kodem, często wprowadzamy różne poprawki, zmieniamy funkcje, klasy itd, a GIT pomaga zapisywać te zmiany i magazynować całą historię. Dzięki temu możemy cofnąć zmiany, wrócić do poprzednich wersji kodu, możemy rozdzielać wersje na stabilne i testowe. Za pomocą GIT możemy łączyć zmiany, wnoszone przez wielu programistów jednocześnie. GIT jest systemem rozproszonym, co oznacza, że przy prawidłowym użytkowaniu GIT, jest szansa na odtworzenie całego repozytorium z dowolnego komputera programisty, nawet jeśli serwer GIT padnie. GIT jako narzędzie programistyczne instaluje się na roboczych komputerach programistów oraz na serwerze, ale może być bez serwera (na przykład, jeśli samodzielnie robimy prosty projekt). Git potrafi działać poprawnie zarówno w jednym folderze z projektem (z kodem źródłowym), jak i w infrastrukturze sieciowej.

Oprócz GIT, oczywiście, istnieją inne repozytorium kodu źródłowego (gdyby ktoś nie wiedział...), ale GIT jest zdecydowanie najpopularniejszym. Przynajmniej, stanem na dzień napisania tego materiału.

Oprócz GIT, oczywiście, istnieją inne repozytorium kodu źródłowego (gdyby ktoś nie wiedział...), ale GIT jest zdecydowanie najpopularniejszy. Przynajmniej, stanem na dzień napisania tego materiału. Inne, najbardziej popularne, to chociażby SVN (Subversion), albo w przeszłości Microsoft SourceSafe lub CVS (uff...), lub mniej znane Perforce.

Zazwyczaj w repozytorium (w tym GIT) przechowujemy pliki z kodem źródłowym, pisanym przez programistów, ale możemy też wgrać tam dokumentację, pliki konfiguracyjne i inne pliki związane z projektem. Natomiast nie raz widziałem jak programiści (albo ktoś, kto nazywa siebie programistą) wrzucają do repozytorium obrazki, skompilowane biblioteki, pliki tymczasowe itd - z reguły nie jest to uznawane za dobre podejście.

Jak działa GIT?

GIT działa na zasadzie zapisywania tak zwanych commit'ów. Commit to zapis stanu projektu, tj zapis zawartości wybranych plików (kod źródłowy, dokumentacja itd, czyli wszystko to co wrzuciliśmy do danego repozytorium). Wyobraźmy sobie że programiści pracują nad projektem, wnoszą zmiany do kodu źródłowego i w którymś momencie stwierdzają że obecny stan wybranych (nie koniecznie wszystkich) plików projektu trzeba wrzucić do repozytorium. Właśnie, wtedy robi się tak zwany commit. Commit to jedno z najbardziej podstawowych pojęć repozytorium GIT.

Każdy commit ma unikatowy identyfikator (tzw. hash), dzięki czemu można łatwo odwołać się do niego w przyszłości. Kiedy wprowadzamy zmiany w kodzie, GIT porównuje je z poprzednimi commit'ami i zapisuje różnice (tzw. diff), a nie nadpisuje tego co jest obecnie.

Drugim absolutnie kluczowym pojęciem w GIT jest branch, czyli gałąź. GIT pozwala na tworzenie gałęzi (branch'y), które umożliwiają równoległą pracę nad różnymi obszarami projektu. Dzięki gałęziom, możemy zmieniać kod, nie bojąc się popsuć głównej wersji projektu. Ogólnie rzecz biorąc, gdyby ktoś nie wiedział, programiści to ludzie od psucia wszystkiego. Najpierw psujemy, potem dumnie naprawiamy. Po zakończeniu psucia pracy nad nową funkcjonalnością, w repozytorium GIT możemy "scalić" gałąź nad którą długo i ciężko pracowaliśmy, z główną wersją projektu, czyli zrobić merge. Właśnie, merge jest kolejnym bardzo ważnym pojęciem w GIT.

Tak pracę GIT można zobrazować graficznie:

Praca z GIT Praca z GIT

Otóż, co jest na tym dziwnym obrazku? Linie poziome to są branch'e. Ogólnoprzyjętą praktyką jest tworzenie głównej gałęzi (branch'a) o nazwie master lub master. Absolutnie nie musimy tego robić, to jest tylko dobra praktyka, obyczajem. Z reguły, przynajmniej w większych projektach, nad którymi pracują więcej niż jedna osoba, tworzymy branch o nazwie dev (od słowa development) i umieszczamy w nim wersję roboczą, która nie powinna trafić do produktu końcowego. Też nie musimy robić dokładnie tak, GIT wiele przetrawi, ale szanujmy innych programistów. Lepiej używać dobrych praktyk, chyba że to nie jest uzasadnione w naszym projekcie. Kropeczki na liniach poziomych na rysunku to są commit'y. Przypomnę, że commit to zrzucenie zestawu plików z kodem źródłowym do repozytorium. Jeśli działamy na repozytorium sieciowym, po commit'ie robimy push, żeby wysłać zmiany do sieci, ale o tym za chwilę. Otóż, z reguły, "wszechświat" zaczyna się od pierwszego commit'u do branch'a master, dodajemy np. plik readme i w komentarzu do commitu tradycyjne piszemy "Init commit", czyli commit inicjujący. Od branch'a master odpączkowujemy branch dev, od dev odpączkowujemy branch np. task_1. Nazwa może być dowolna, ale warto w zespole ustalić jak nazywamy branch'e, np. mogą to być numery zgłoszeń z systemu do zarządzania projektami, albo jakieś inne zrozumiale dla zespołu punkty odniesienia. Po zakończeniu programowania jakiejś malej lub większej funkcjonalności, robimy commit do przykładowego task_1, testujemy, opisujemy co żeśmy wgrali do tego repozytorium i robimy merge (czyli łączenie) z powrotem do dev, testujemy wersje programu w branch'u dev, a kiedy stwierdzimy że ta wersja już nadaje się do wypuszczenia nowej wersji produktu - robimy merge dev do master, po drodze rozwiązujemy konflikty (jeśli dwóch lub więcej programistów wprowadzili zmiany w tym samym miejscu). Dobrą tradycją jest robienie branch'a na każdą konkretną zmianę, merge'owanie tego branch'a do dev, a dev po pozytywnym wszechstronnym przetestowaniu merge'ujemy do master. Jak potwierdziliśmy (lub testerzy potwierdzili, o ile są w zespole) że naprawiliśmy więcej niż popsuliśmy, to branch z nazwą konkretnej zmiany możemy usunąć (żeby nie zaśmiecać repozytorium, bo w ten sposób bardzo szybko straci czytelność).

To nie jest jedyny możliwy schemat pracy z GIT, wręcz nie zawsze jest to optymalny schemat. Niektórzy, szczególnie młodzi, programiści i administratorzy DevOps, bez zrozumienia sedna sprawy, ślepo twierdzą że "oficjalne" gitflow (o tym za chwilę) jest jedyną słuszną koncepcją pracy z GIT. Właśnie, nie jest.

Podstawowe polecenia (komendy) GIT

Najlepiej z GIT'em pracuje się w terminalu (tj. wiersz poleceń). Oczywiście, są narzędzia graficzne do pracy z GIT, ale lepiej od razu się nauczyć posługiwania się wierszem poleceń. Polecenia GIT wykonujemy w folderze z repozytorium w wierszy poleceń systemu operacyjnego. GIT oferuje sporo poleceń do pracy z kodem i samym repozytorium, przeróżnych kluczy, rozszerzających lub doprecyzowujących wybrane polecenia. Komendy GIT zaczynają się od, właśnie, komendy git, za którą idzie wybrane polecenie. Oto niektóre najważniejsze komendy GIT:

  • git init – tworzy nowe repozytorium GIT w bieżącym folderze, wykonuje się jednorazowo przed rozpoczęciem pracy (właśnie, jest tym rozpoczęciem, ale nie jedynym możliwym) z repozytorium.
  • git clone – klonuje (kopiuje, pobiera) istniejące repozytorium (na przykład, ze zdalnego serwera) do lokalnego foldera.
  • git status – pokazuje, jakie zmiany zostały wprowadzone w plikach od ostatniego commit'a. To polecenie ładnie podświetla które pliki zostały zmienione (na czerwono) a które dodane do commit'a (na zielono) kiedy samego commita jeszcze nie zrobiono.
  • git checkout
  • - przełącza na wybranego branch'a lub tworzy go i przełącza (jeśli żyjemy klucza -b).
  • git add – dodaje plik do śledzenia przez GIT, aby ten plik mógł zostać zapisany w kolejnym commit'ie. Warto pamiętać że domyślnie GIT nie śledzi nowych plików, więc trzeba je dodać za pomocą komendy add.
  • git commit - zapisuje (ale nie wysyła do zdalnego repozytorium, tylko do lokalnego) zmiany w repozytorium (z opisem, jeśli użyjemy klucza -m "jakiś komentarz..."). Cały czas warto pamiętać o tym, że GIT nie nadpisuje danych, tylko dopisuje zmiany do historii zmian.
  • git push – wysyła zmiany do zdalnego repozytorium, z reguły na zdalny serwer GIT.
  • git pull – pobiera najnowsze zmiany ze zdalnego repozytorium do lokalnego.
  • git branch – wyświetla listę gałęzi w projekcie.
  • git merge – łączy zawartość bieżącego branch'a z innym. Często przy próbie merge powstają błędy (w sytuacji kiedy wiele osób pracowało jednocześnie nad tym samym plikiem), to są tak zwane konflikty merge'owania, ale to temat na osobny duży artykuł.

Ww. lista nie jest wyczerpującą, lecz małym ułamkiem komend GIT, ale są to komendy których, najprawdopodobniej, będziemy używać na codzień podczas pracy z GIT. Oto przykład seansu pracy z GIT (opis tego co tutaj zrobiłem, dalej pod obrazkiem):

Praca z GIT Praca z GIT

Uruchomiłem terminal (systemowy wiersz poleceń, ja akurat, używam Linux'a, ale terminal jest w każdym systemie operacyjnym dla zwykłych komputerów). W pierwszej linii za pomocą systemowego polecenia cd przekierowałem wiersz poleceń do foldera /data/temp/012, to był pusty folder, stworzony na cele niniejszego ćwiczenia. Dalej wykonałem polecenie git init (linia 2), które utworzyło mi w bieżącym folderze (czyli /data/temp/012) puste repozytorium GIT. W linii 14 wykonałem polecenie git status, które wyświetliło mi obecny status świeżo upieczonego repozytorium. Jak widać na poziomie linii 15, poprzednie polecenie nie tylko założyło puste repozytorium, ale też stworzyło w nim branch o nazwie master. Nawiasem mówiąc, również to polecenie w bieżącym folderze stworzyło folder o nazwie .git, w którym GIT będzie przechowywać wszystkie zmiany. W linii 20 wykonałem polecenie nano readme, które nie dotyczy GIT'a, natomiast tworzy (akurat w Linux'ie) plik tekstowy, więc stworzyłem plik o nazwie readme i wpisałem do niego jakiś przykładowy tekst. Po zapisaniu pliku tekstowego, ponownie wykonałem polecenie git status (linia 21). Jak widać, tym razem GIT podpowiada (linia 28, czerwony wyraz readme) że istnieje nieśledzony plik. W linii 31 wykonałem polecenie git add readme, czym właśnie dodałem plik readme do śledzenia przez GIT. Następnie, ponownie wykonałem git status, i jak widzimy, kolor wyrazu readme zmienił się na zielony, co oznacza że teraz GIT śledzi ten plik. W linii 41 wykonałem polecenie git commit -m "Init commit", co oznacza że poprosiłem GIT o dodanie pierwszego commit'u z komentarzem "Init commit". I tutaj wystąpił pierwszy błąd: w linii 42 GIT poinformował mnie że nie mam ustawionych nazwy użytkownika i adresu email do pracy z tym repozytorium oraz, w liniach 48 i 49, pokazał jak mogę podać mu te dane. Przed pierwszym commit'em te dane muszą być podane. Można podać dane dla tego dokładnie repozytorium albo globalnie dla całego komputera, czyli dla wszystkich repozytoriów z którymi będziemy pracować, logując się na konto wybranego użytkownika na danym komputerze.

Co to jest Gitflow?

Jeśli mówimy o profesjonalnej pracy z GIT'em w dużej firmie, Gitflow często jest optymalnym podejściem do korzystania z repozytorium GIT. Natomiast, wyraźnie podkreślam, nie jest to jedyne słuszne podejście. W inżynierii (i to w każdej) nie ma nic gorszego od robienia czegoś bez zrozumienia tego co robimy. W niektórych branżach to może doprowadzić do katastrofy (wyobraź sobie że ktoś pisze kod do sterowania reaktorem jądrowym, albo węzłem kolejowym, i przypadkiem wybrał zły branch w GIT do wydania wersji produkcyjnej oprogramowania...). Owszem, żadna poważna rozmowa rekrutacyjna na stanowisko programisty raczej nie obejdzie się bez pytania o Gitflow (chyba że rekrutujący sam nie ma pojęcia co to jest). Otóż, Gitflow to zbiór ustaleń, albo model pracy z GIT. Gitflow wprowadza zorganizowany i ustrukturyzowany sposób zarządzania branch'ami, commit'ami, komentarzami, robienia merge'ów, psucia i naprawy głównego branch'a (który, jak juz wiemy, najczęściej nazywa się master albo main). Gitflow jest dość dobrze opisanym zestawieniem dobrych praktyk i czesto znakomicie się sprawdza. Czasem opłaca się zmodyfikować standardowe Gitflow na potrzeby projektu lub zespołu. Gitflow jest tylko polecanym zestawem dobrych praktyk, a nie obowiązkowym do stosowania. Znam przykłady kiedy inżynierowie DevOps (czyli administratorzy systemowi) w dużej firmie wymuszali stosowanie Gitflow bez zrozumienia o co z tym wszystkim chodzi. Wyglądało to, przynajmniej, zabawnie.

Standardowe podejście Gitflow zakłada tworzenie kilku branch'ów:

  • master (lub main) - to główny branch w projekcie, który zawiera gotowy do produkcji kod. Wszystkie stabilne wersje aplikacji są wypuszczane z tego branch'a.
  • dev (albo develop) - branch develop jest gałęzią, w której odbywa się aktywny rozwój projektu. Programiści na tej gałęzi dodają nowe funkcje, poprawki, a także testują kod przed ostatecznym wydaniem. To jest miejsce, gdzie wszystkie funkcje łączą się w jeden, wspólny kod do testów. Branch dev jest gałęzią, która przygotowuje projekt do przyszłej wersji produkcyjnej (czyli do zrobienia raz na jakiś czas merge do master'a).
  • release - kiedy dev osiąga pewien poziom stabilności i jest gotowe na nową wersję produkcyjną, tworzymy branch release naśladując dev. Na gałęzi release dokonuje się drobnych poprawek (np. poprawki błędów, drobne usprawnienia, aktualizacja dokumentacji) przed wydaniem nowej wersji oprogramowania. Po zakończeniu prac nad gałęzią release, jest ona scalana (merge) zarówno do gałęzi master, jak i develop, aby zaktualizować te dwie gałęzie. W małych projektach jest to zbędne. Nie warto tworzyć branch'a release tylko dla sztuki.
  • hotfix - branch'e o nazwie hotfix są tworzone bezpośrednio z master w celu szybkiej naprawy popsutej funkcjonalności (przecież mówiłem, że programiści są od psucia), rozwiązania krytycznych problemów w produkcji (np. błędów, które mogą powodować awarie systemu). Po zakończeniu pracy nad poprawką, branch hotfix jest scalany zarówno z master'em, jak i z dev'em, aby zaktualizować obie gałęzie. Przykładowa nazwa gałęzi raczej brzmi: hotfix/nazwa_poprawki, a nie samo hotfix.
  • task - tutaj też, raczej task/numer_lub_nazwa_funkcjonalności, a nie samo task. Chodzi o funkcjonalność którą dodajemy lub poprawiamy. Branch'e task tworzymy dla każdej jednej funkcjonalności, nad którą pracujemy. Branch'e task są tworzone z dev'a. Kiedy funkcja lub zmiana jest gotowa, gałąź task jest scalana z dev'em. Z reguły, jeśli mamy jakiś system do zarządzania projektem (chociażby JIRA), jako nazwy branch'a z funkcjonalnością używamy identyfikatora zgłoszenia, w którym jest opisana funkcjonalność lub poprawka, którą mamy do zrobienia.

Z reguły, zaczynamy pracę od stworzenia gałęzi task prosto z gałęzi dev. Pracujemy nad daną funkcjonalnością, testujemy ją, psujemy i dumnie poprawiamy po drodzę inne rzeczy, a gdy funkcja jest gotowa, scalamy ją z dev. Kiedy dev osiągnie punkt, w którym projekt jest gotowy do wydania (np. po dodaniu kilku nowych funkcji, albo gdy marketingowcy z księgowym krzyczą że zaraz nam kasa się skończy na koncie firmowym), tworzymy gałąź release z dev. W tej gałęzi dokonujemy drobnych poprawek, np. aktualizacji dokumentacji, drobnych zmian w interfejsie użytkownika czy naprawy małych błędów, o ile są. Po zakończeniu pracy nad release, gałąź ta jest scalana z master i oznaczana jako wersja produkcyjna do wydania produktu.

Jeśli na produkcji pojawi się krytyczny błąd, tworzymy gałąź hotfix z master'a. Po naprawie błędu gałąź hotfix jest scalana zarówno z master, jak i z dev, aby poprawka była dostępna w obu gałęziach. Gitflow daje nam (czyli programistom) jednolitą metodologię tworzenia gałęzi i ich zarządzania, co czyni cały proces bardziej przejrzystym, szczególnie w dużych zespołach. Ale jeszcze raz chcę to wyraźnie podkreślić, standardowe Gitflow nie jest jedynym słusznym podejściem do porządkowania repozytorium. Gitflow może być nadmiarowe i zbyt skomplikowane dla małych projektów lub zespołów, które nie potrzebują tak rozbudowanego systemu zarządzania gałęziami. Aby Gitflow działało sprawnie, cały zespół musi ściśle przestrzegać ustalonych reguł dotyczących pracy z gałęziami. Niewłaściwe zarządzanie gałęziami może prowadzić do chaosu i problemów z synchronizacją.

Co to jest GitHub i GitLab?

GIT to narzędzie, które działa na roboczym komputerze programisty (chociaż, nie koniecznie akurat programisty). Git może zostać zainstalowany na serwerze, do przechowywania kodu źródłowego projektów firmy w sieci. Ale są też duże ogólnodostępne repozytoria GIT. Najbardziej znane to, chyba, GitHub.

GitHub to serwis internetowy, który przechowuje ogromne ilości kodu źródłowego, tj takie globalne repozytorium GIT. A raczej sieciowy zasób, obsługujący mnóstwo osobnych repozytoriów GIT. GitHub pozwala na łatwe współdzielenie kodu z innymi osobami, współpracę nad projektami, a także na publiczne udostępnianie swoich repozytoriów (jak na cały swiat tak i wybranym osobom lub zespołom). Możemy, na przykład, utworzyć swoje repozytorium na GitHub, a potem klonować (git clone) go na swoim komputerze, aby pracować nad projektem. Kiedy wprowadzimy zmiany, możemy wysłać je (git push) z powrotem do GitHub, aby inni mogli je zobaczyć i z nich skorzystać. GitHub to także bardzo popularne miejsce, gdzie można znaleźć projekty open-source, ogromną ilość komentarzy, dokumentacje do projektów itd. Dzięki GitHub, projekt staje się bardziej dostępny dla innych programistów, którzy mogą wnieść własny wkład w rozwój oprogramowania, o ile autor projektu pozwala na wniesienie zmian. Obecnie GitHub należy do Microsoft.

GitLab to platforma GIT, która oferuje szereg podobnych funkcji jak GitHub, ale z pewnymi różnicami. W odróżnieniu od GitHub, GitLab oferuje darmowe repozytoria prywatne, co czyni go atrakcyjnym rozwiązaniem dla osób i zespołów, które potrzebują ochrony kodu bez konieczności płacenia za subskrypcję. GitLab oferuje wbudowane narzędzia do zarządzania projektami, takie jak tablice kanban, zarządzanie zadaniami, śledzenie błędów (issues), co sprawia, że platforma staje się kompletnym narzędziem do zarządzania całym cyklem życia oprogramowania. GitLab umożliwia automatyzację wielu procesów związanych z zarządzaniem cyklem życia aplikacji dzięki funkcji Auto DevOps, która automatycznie ustawia pipelines, testy i wdrożenia na podstawie najlepiej praktykowanych wzorców.

Pomocne odnośniki

Więcej materiałów o repozytoriach kodu źródłowego znajdziesz w kategorii Repozytorium (kliknij tu) oraz w Bazie Wiedzy (kliknij tu).

Dokumentacja GIT: https://git-scm.com/doc

GitHub: https://github.com

GitLab: https://about.gitlab.com

Jeśli masz pytania dotyczące GIT - daj znać w komentarzu pod tym artykułem.

Jeśli znalazłe[-a]ś w tekście, literówkę, błąd stylistyczny albo inny błąd językowy - bardzo proszę o napisanie poprawki w komentarzu pod artykułem albo przez formularz kontaktowy. Dziękuję!

Autor artykułu: Sergiusz Diundyk.

Komentarze

Na razie brak komentarzy. Dodaj pierwszy komentarz do artykułu!
Dodaj nowy komentarz:

 Oświadczam że przeczytałe[-a]m Regulamin i akceptuję go w całości i bezwarunkowo.
 
Imię lub pseudonim
 
Twój komentarz
Wyślij komentarz
Baza wiedzy
Zoom
Ok