Przepływ pracy Git | Porównanie przepływów pracy

Porównanie przepływów pracy Git: co należy wiedzieć

Git jest obecnie najczęściej używanym systemem kontroli wersji. Przepływ pracy Git to przepis lub zalecenie, jak korzystać z Git, aby wykonać pracę w spójny i produktywny sposób. Przepływy pracy Git zachęcają programistów i zespoły DevOps do konsekwentnego i skutecznego wykorzystywania możliwości systemu. Git oferuje dużą elastyczność w sposobie zarządzania zmianami. Z racji priorytetowego charakteru nadawanego przez Git kwestii elastyczności, nie istnieje jeden standardowy sposób interakcji z tym systemem. Pracując z zespołem nad projektem zarządzanym za pomocą Git, trzeba się upewnić, że wszyscy zgadzają się co do danego sposobu wprowadzania zmian. Aby mieć pewność, że zespół jest pod tym względem jednomyślny, należy opracować lub wybrać wspólnie uzgodniony przepływ pracy.Istnieje kilka powszechnie znanych przepływów pracy Git, które mogą być dobrym rozwiązaniem dla Twojego zespołu. Tutaj omówimy niektóre z nich.

Szeroki wachlarz możliwości w zakresie przepływów pracy może początkowo sprawić trudności przy wdrażaniu Git. Dlatego w tym artykule omówimy te najpopularniejsze wśród zespołów programistycznych.

W trakcie lektury pamiętaj, że podane przykłady mają pełnić rolę wskazówek, nie gotowych rozwiązań. Prezentujemy tu pewien zakres możliwości, które można dowolnie łączyć i dopasowywać do własnych potrzeb.

Czym charakteryzuje się skuteczny przepływ pracy w Git?

Przy ocenie przydatności przepływu pracy dla danego zespołu należy przede wszystkim wziąć pod uwagę jego kulturę. Celem przepływu pracy jest zwiększenie efektywności zespołu, a nie bycie ciężarem ograniczającym produktywność. Przykłady kwestii, które należy wziąć pod uwagę podczas oceny przepływu pracy:

  • Czy można go skalować w zależności od wielkości zespołu?
  • Czy umożliwia łatwe cofanie błędów?
  • Czy ten przepływ pracy wymaga sporo nauki?

Scentralizowany przepływ pracy

Przepływ pracy Git | Centralne i lokalne repozytoria

Scentralizowany przepływ pracy to świetne rozwiązanie dla zespołów migrujących z SVN. Podobnie jak Subversion, scentralizowany przepływ pracy wykorzystuje centralne repozytorium, które służy jako pojedynczy punkt wprowadzania wszystkich zmian w projekcie. W tym przypadku domyślna gałąź programistyczna nosi nazwę main, a nie trunk, a wszystkie zmiany są dodawane do niej w postaci commitów. Ten przepływ pracy nie wymaga żadnych innych gałęzi poza main.

Przejście na rozproszony system kontroli wersji może wydawać się trudnym zadaniem, ale nie trzeba zmieniać dotychczasowego sposobu pracy, aby móc skorzystać z zalet systemu Git. Twój zespół może rozwijać projekty w dokładnie taki sam sposób, jak w przypadku Subversion.

Jednakże używanie Git do zarządzania przepływem prac programistycznych oferuje kilka zalet w porównaniu z SVN. Po pierwsze: każdy programista otrzymuje własną, lokalną kopię całego projektu. To odizolowane środowisko pozwala każdemu programiście pracować niezależnie od wszelkich pozostałych zmian w projekcie — może on dodawać commity do swojego lokalnego repozytorium i całkowicie zapomnieć o rozwoju sytuacji w repozytorium nadrzędnym, dopóki będzie to dla niego wygodne.

Po drugie: zapewnia dostęp do solidnego modelu tworzenia i scalania gałęzi Git. W odróżnieniu od SVN tworzenie gałęzi w Git zostało zaprojektowane jako bezpieczny mechanizm scalania kodu i dzielenia się zmianami między repozytoriami. Scentralizowany przepływ pracy jest podobne do innych rodzajów przepływów, ponieważ wykorzystuje zdalne repozytorium znajdujące się po stronie serwera, służące do wypychania i ściągania plików. W porównaniu z innymi rozwiązaniami scentralizowany przepływ pracy nie ma zdefiniowanych wzorców pull requestu czy podziału. Najlepiej się sprawdza w przypadku zespołów migrujących do Git z SVN oraz dla zespołów o mniejszych rozmiarach.

Jak to działa

Programiści zaczynają od sklonowania centralnego repozytorium. W swoich lokalnych kopiach projektu edytują pliki i zatwierdzają zmiany, tak jak w SVN, ale nowe commity są przechowywane lokalnie; są całkowicie odizolowane od centralnego repozytorium. Dzięki temu programiści mogą odłożyć synchronizację z repozytorium nadrzędnym do najbardziej dogodnego dla nich momentu.

Aby opublikować zmiany w oficjalnym projekcie, programiści „wypychają” swoją lokalną gałąź main do centralnego repozytorium. Jest to odpowiednik polecenia svn commit, z tą różnicą, że dodaje wszystkie lokalne commity, które nie znajdują się jeszcze w centralnej gałęzi main.

Inicjowanie centralnego repozytorium

Przepływ pracy Git: inicjalizacja centralnego repozytorium początkowego

Najpierw ktoś musi utworzyć centralne repozytorium na serwerze. Jeśli jest to nowy projekt, możesz zainicjować puste repozytorium. W przeciwnym razie musisz zaimportować istniejące repozytorium Git lub SVN.

Centralne repozytoria powinny zawsze mieć postać czystych repozytoriów początkowych (bez katalogu roboczego). Tworzy się je w następujący sposób:

ssh user@host git init --bare /path/to/repo.git

Pamiętaj, aby użyć poprawnej nazwy użytkownika SSH jako user, domeny lub adresu IP swojego serwera jako host oraz lokalizacji do przechowywania repozytorium jako /path/to/repo.git. Zwróć uwagę, że do nazwy repozytorium umownie dodaje się rozszerzenie .git wskazujące, że jest to repozytorium czyste.

Hostowane repozytoria centralne

Centralne repozytoria są często tworzone za pośrednictwem zewnętrznych usług hostingowych Git, takich jak Bitbucket Cloud czy Bitbucket Server. Omówiony powyżej proces inicjowania pustego repozytorium jest wykonywany za Ciebie przez usługę hostingową. Serwis udostępnia następnie adres centralnego repozytorium, który umożliwia dostęp z Twojego repozytorium lokalnego.

Klonowanie centralnego repozytorium

Następnie każdy programista tworzy lokalną kopię całego projektu. Wykonuje się to za pomocą polecenia git clone:

git clone ssh://user@host/path/to/repo.git

Gdy klonujesz repozytorium, Git automatycznie dodaje skrót o nazwie origin wskazujący na repozytorium nadrzędne dla potrzeb dalszej interakcji.

Wprowadzanie i zatwierdzanie zmian

Gdy repozytorium zostanie sklonowane lokalnie, programista może wprowadzać zmiany za pomocą standardowego procesu zatwierdzania w systemie Git: edycja, zapis w przechowalni i commit. Dla tych, którzy nie są zaznajomieni z funkcją przechowalni — jest to sposób na przygotowanie commitów bez konieczności uwzględniania każdej zmiany w katalogu roboczym. To umożliwia tworzenie wysoce wyspecjalizowanych commitów, nawet gdy dokonuje się wielu lokalnych zmian.

git status # View the state of the repo
git add <some-file> # Stage a file
git commit # Commit a file</some-file>

Jako że polecenia te generują commity lokalne, John może powtarzać ten proces tyle razy, ile potrzebuje, nie martwiąc się o zawartość repozytorium centralnego. Może to być bardzo przydatne w przypadku rozbudowanych funkcji, które muszą zostać podzielone na prostsze, bardziej elementarne fragmenty.

Wypychanie nowych commitów do centralnego repozytorium

Po zatwierdzeniu nowych zmian w lokalnym repozytorium zostają one wypchnięte do repozytorium centralnego celem podzielenia się z innymi programistami w projekcie.

 git push origin main

To polecenie spowoduje wypchnięcie nowo wprowadzonych zmian do centralnego repozytorium. Może się zdarzyć, że wypchnięte wcześniej przez innego użytkownika aktualizacje będą zawierały kod, który będzie sprzeczny z aktualizacjami obecnie wypychanymi. Git wyświetli komunikat informujący o zaistniałym konflikcie. W takiej sytuacji należy najpierw zastosować polecenie git pull. Ten scenariusz konfliktu zostanie omówiony w następnej części.

Zarządzanie konfliktami

Centralne repozytorium reprezentuje oficjalny projekt, więc jego historia commitów powinna być traktowana jako niezmienna i nienaruszalna. Gdyby lokalne commity programisty różniły się od centralnego repozytorium, Git odmówi wypchnięcia zmian, jako że nadpisałyby one oficjalne commity.

Przepływ pracy Git: zarządzanie konfliktami

Zanim programista będzie mógł opublikować swoją funkcję, musi pobrać aktualne centralne commity celem zmiany bazy własnych. To oznacza tyle co: „Chcę dodać moje zmiany do tego wszystkiego, co już zrobili inni”. W rezultacie otrzymamy idealnie liniową historię, tak jak w tradycyjnych przepływach pracy SVN.

Jeśli lokalne zmiany bezpośrednio kolidują z commitami nadrzędnymi, Git wstrzyma proces zmiany bazy i umożliwi ręczne rozwiązanie konfliktów. Zaletą systemu Git jest to, że do generowania commitów, jak i rozwiązywania konfliktów scalenia, służą te same polecenia git status i git add. To ułatwia nowym programistom zarządzanie własnymi scaleniami. Ponadto, na wypadek komplikacji, Git ułatwia przerwanie całej zmiany bazy i podjęcie próby od nowa (lub znalezienie pomocy).

Przykład

Prześledźmy za pomocą przykładu w jaki sposób mały zespół może wykorzystać ten przepływ pracy. Załóżmy, że dwoje programistów, John i Mary, pracuje nad oddzielnymi funkcjami i dzieli się efektami swoich działań za sprawą scentralizowanego repozytorium.

John pracuje nad swoją funkcją

Przepływy pracy Git: proces edycji / zapisu w przechowalni / commitu funkcji

W swoim lokalnym repozytorium John może rozwijać funkcje za pomocą standardowego procesu zatwierdzania w Git: edycja, zapisanie w przechowalni i commit.

Jako że polecenia te generują commity lokalne, John może powtarzać ten proces tyle razy, ile potrzebuje, nie martwiąc się o zawartość repozytorium centralnego.

Mary pracuje nad swoją funkcją

Przepływy pracy Git: edycja / zapis w przechowalni / commit funkcji

W tym samym czasie Mary pracuje nad swoim własnym elementem w swoim własnym repozytorium lokalnym, stosując ten sam proces edycji, zapisu i commitu. Tak samo, jak w przypadku Johna, nie obchodzi ją stan repozytorium centralnego, jak i naprawdę nie obchodzi ją, co John robi w swoim własnym lokalnym repozytorium, jako że wszystkie lokalne repozytoria są prywatne.

John publikuje swoją funkcję

Przepływy pracy Git: publikowanie funkcji

Kiedy John ukończy swoją funkcję, powinien opublikować swoje lokalne commity w centralnym repozytorium, aby inni członkowie zespołu mieli do nich dostęp. Może to zrobić za pomocą polecenia git push w następujący sposób:

 git push origin main

Pamiętaj, że origin to zdalne połączenie z centralnym repozytorium utworzone przez Git wskutek klonowania przez Johna. Argument main nakazuje systemowi Git upodobnienie gałęzi main repozytorium origin do jego lokalnej gałęzi main. Ponieważ centralne repozytorium nie było aktualizowane od czasu sklonowania przez Johna, nie spowoduje to żadnych konfliktów i wypychanie przebiega zgodnie z oczekiwaniami.

Mary próbuje opublikować swoją funkcję

Przepływy pracy Git: błąd polecenia push

Zobaczmy, co się stanie, jeśli Mary spróbuje wypchnąć swoją funkcję już po tym, jak John pomyślnie opublikuje swoje zmiany w centralnym repozytorium. Może użyć dokładnie tego samego polecenia:

 git push origin main

Jednakże, z racji różnic między jej lokalną historią a tą centralnego repozytorium, Git odrzuci żądanie z dość szczegółowym komunikatem o błędzie:

error: failed to push some refs to '/path/to/repo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

To zapobiega nadpisywaniu oficjalnych commitów przez Mary. Dlatego musi ona ściągnąć aktualizacje Johna do swojego repozytorium, zintegrować je ze swoimi lokalnymi zmianami, a następnie spróbować ponownie.

Mary dokonuje zmiany bazy na podstawie commitów Johna

Przepływy pracy Git: git pull rebase

Mary może użyć polecenia git pull, aby włączyć do swojego repozytorium zmiany wprowadzone w repozytorium nadrzędnym. To polecenie jest podobne do svn update — ściąga całą historię commitów z repozytorium nadrzędnego do lokalnego repozytorium Mary celem zintegrowania z jej lokalnymi commitami:

 git pull --rebase origin main

Opcja --rebase każe systemowi przenieść wszystkie commity Mary do końcówki gałęzi main po zsynchronizowaniu ich ze zmianami z centralnego repozytorium, tak jak to widać poniżej:

Przepływy pracy Git: zmiana bazy na podstawie master

Ściąganie zadziała również przy pominięciu tej opcji, ale kończy się to wygenerowaniem niepotrzebnego „commitu scalenia” przy każdej próbie synchronizacji z centralnym repozytorium. W przypadku tego przepływu pracy zawsze lepiej jest dokonać zmiany bazy zamiast generować commit scalenia.

Mary rozwiązuje konflikt scalania

Przepływy pracy Git: zmiana bazy na podstawie commitów

Zmiana bazy polega na przeniesieniu każdego lokalnego commitu jeden po drugim do zaktualizowanej gałęzi main. Oznacza to, że konflikty scalania są wyłapywane w każdym commicie osobno, a nie rozwiązywane hurtem w ramach jednego dużego commitu scalenia Dzięki temu Twoje commity są maksymalnie wyspecjalizowane i wspólnie składają się na uporządkowany obraz historii projektu. To z kolei ułatwia zorientowanie się, gdzie zostały wprowadzone ewentualne błędy oraz, jeśli to konieczne, wycofanie zmian przy minimalnym wpływie na projekt.

Jeśli Mary i John pracują nad niepowiązanymi funkcjami, jest mało prawdopodobne, że proces zmiany bazy wywoła jakieś konflikty. Gdyby jednak to nastąpiło, Git wstrzyma zmianę bazy na bieżącym commicie i wyświetli następujący komunikat wraz z odpowiednimi instrukcjami:

CONFLICT (content): Merge conflict in <some-file>
Przepływy pracy Git: rozwiązywanie konfliktów

Wspaniałą zaletą systemu Git jest to, że każdy może rozwiązywać swoje własne konflikty scalania. W naszym przykładzie Mary po prostu uruchamia polecenie git status, aby zobaczyć, w czym tkwi problem. Sprzeczne ze sobą pliki są widoczne w sekcji Unmerged paths:

# Unmerged paths:
# (use "git reset HEAD <some-file>..." to unstage)
# (use "git add/rm <some-file>..." as appropriate to mark resolution)
#
# both modified: <some-file>

Następnie Mary dokonuje edycji plików według własnego uznania. Kiedy już jest zadowolona z rezultatu, zapisuje pliki w przechowalni w standardowy sposób i pozwala, aby polecenie git rebase zajęło się resztą:

git add <some-file>
git rebase --continue

I to już wszystko. Git przejdzie do następnego commitu i powtórzy proces dla wszystkich innych commitów generujących konflikty.

Jeśli na tym etapie nie masz pojęcia, co się dzieje — nie panikuj. Po prostu wykonaj poniższe polecenie, a wrócisz do punktu wyjścia:

git rebase --abort

Mary pomyślnie publikuje swoją funkcję

Przepływy pracy Git: synchronizacja centralnego repozytorium

Po zakończeniu synchronizacji z centralnym repozytorium Mary może pomyślnie opublikować swoje zmiany:

 git push origin main

Co dalej

Jak widać, odtworzenie tradycyjnego środowiska programistycznego Subversion jest możliwe za pomocą zaledwie kilku poleceń Git. Jest to świetne rozwiązanie przy migrowaniu zespołów z SVN, ale nie wykorzystuje ono rozproszonej natury systemu Git.

Scentralizowany przepływ pracy jest dobry dla małych zespołów. Jednakże proces rozwiązywania konfliktów opisany powyżej może stać się wąskim gardłem w miarę powiększania zespołu. Jeśli Twój zespół dobrze czuje się w scentralizowanym przepływie pracy, ale chce usprawnić swoją współpracę, to zdecydowanie warto się zapoznać z przepływem pracy gałęzi funkcji. Dzięki wydzieleniu osobnej gałęzi na każdą funkcję można zainicjować dogłębną dyskusję nad nowymi dodatkami przed ich włączeniem do oficjalnego projektu.

Inne popularne przepływy pracy

Scentralizowany przepływ pracy stanowi zasadniczo fundament dla innych przepływów pracy Git. Większość popularnych rozwiązań opiera się na jakimś scentralizowanym repozytorium, z którego poszczególni programiści ściągają i do którego wypychają swoje zmiany. Poniżej omówimy krótko kilka innych popularnych przepływów pracy Git. Te rozszerzone przepływy pracy oferują bardziej wyspecjalizowane wzorce zarządzania gałęziami do opracowywania funkcji, poprawkami i ewentualnymi wydaniami.

Tworzenie gałęzi funkcji

Tworzenie gałęzi funkcji to logiczne rozszerzenie scentralizowanego przepływu pracy. Podstawowym założeniem przepływu pracy gałęzi funkcji jest to, że cały proces opracowywania funkcji powinien się odbywać w obrębie gałęzi dedykowanej, a nie gałęzi main. Ta forma izolacji ułatwia wielu programistom pracę nad określoną funkcją bez zakłócania głównej bazy kodu. Oznacza to również, że gałąź main nigdy nie będzie zawierała wadliwego kodu, co jest ogromną zaletą w środowiskach ciągłej integracji.

Przepływ pracy Gitflow

Przepływ pracy Gitflow został po raz pierwszy zaprezentowany w 2010 roku na blogu Vincenta Driessena w serwisie nvie.com. Przepływ pracy Gitflow definiuje sztywny model pracy z gałęziami skonstruowany wokół wydania projektu. Ten przepływ pracy nie wnosi żadnych nowych koncepcji ani poleceń oprócz tych, które są wymagane w przepływie pracy gałęzi funkcji. Zamiast tego przypisuje on bardzo konkretne role różnym gałęziom oraz definiuje sposób i czas ich interakcji.

Przepływ pracy z podziałem

Przepływ pracy z podziałem różni się zasadniczo od innych przepływów pracy omówionych w tym samouczku. W miejsce korzystania z jednego repozytorium po stronie serwera, które pełniłoby funkcję „centralnej” bazy kodu, wykonanie podziału sprawia, że każdy programista ma do dyspozycji repozytorium po stronie serwera. Oznacza to, że każdy autor kodu dysponuje nie jednym, a dwoma repozytoriami Git: prywatnym repozytorium lokalnym i publicznym repozytorium po stronie serwera.

Wytyczne

Nie ma jednego uniwersalnego sposobu pracy w Git. Jak już wspomnieliśmy, kluczowe jest opracowanie takiego sposobu pracy, który zwiększy produktywność zespołu. Oprócz wpisywania się w kulturę zespołu przepływ pracy powinien również dobrze pasować do sposobu prowadzenia działalności. Funkcje Git, takie jak gałęzie czy tagi, powinny współgrać z harmonogramem wydań w Twojej firmie. Jeśli Twój zespół korzysta z oprogramowania do zarządzania projektami z funkcją śledzenia zadań, warto używać gałęzi odpowiadających zadaniom w toku. Ponadto przy wyborze przepływu pracy należy rozważyć jeszcze kilka aspektów:

Gałęzie krótkoterminowe

Im dłużej dana gałąź funkcjonuje w oderwaniu od gałęzi produkcyjnej, tym większe istnieje ryzyko wystąpienia konfliktów przy scalaniu oraz problemów przy wdrażaniu. Gałęzie krótkotrwałe sprzyjają czystemu scalaniu i skutecznemu wdrażaniu.

Ograniczenie i uproszczenie wycofywania zmian

Przepływ pracy powinien proaktywnie zapobiegać scaleniom wymagającym później wycofania. Do tego celu może służyć funkcja testowania gałęzi przed zezwoleniem na jej scalenie z gałęzią main. Jednakże wypadki mogą zawsze się zdarzyć. Dlatego warto korzystać z przepływu pracy, który pozwala na łatwe wycofanie zmian, które nie zakłóca procesów roboczych innych członków zespołu.

Dopasowanie do harmonogramu wydań

Przepływ pracy powinien pasować do cyklu wydawania oprogramowania w Twojej firmie. Jeśli planowanie jest wydawanie kilka razy dziennie, konieczne będzie utrzymanie stabilności gałęzi main. Jeśli harmonogram wydawania jest mniej napięty, można rozważyć użycie tagów Git w celu przypisania gałęzi do wersji.

Podsumowanie

W tym artykule omówiliśmy kwestię przepływów pracy Git. Dokładnie przyjrzeliśmy się scentralizowanemu przepływowi pracy na podstawie praktycznych przykładów. W ramach rozwinięcia tematu przedstawiliśmy też inne, bardziej wyspecjalizowane rodzaje przepływów. Kluczowe wnioski są następujące:

  • Nie ma jednego uniwersalnego sposobu pracy w Git.
  • Przepływ pracy powinien być prosty i sprzyjać zwiększeniu produktywności zespołu.
  • Powinien też odzwierciedlać potrzeby wynikające z prowadzonej działalności biznesowej.

Więcej o kolejnym rodzaju przepływu pracy dowiesz się z naszego kompleksowego omówienia przepływu pracy gałęzi funkcji.

Chcesz nauczyć się obsługi systemu Git?

Wypróbuj ten interaktywny samouczek.

Zacznij już teraz