
Git – podstawowe narzędzie pracy dewelopera i nie tylko. Część III: git-flow, git bisect, git blame

Artykuł zakłada, że czytelnik posiada przynajmniej minimalną wiedzę na temat Gita. Niektóre z zagadnień będą jednak na odrobinę wyższym poziomie. Przydatna może okazać się także wiedza na temat programowania w powłoce BASH i o szeroko pojętym Linuksie.
Artykuł zakłada, że czytelnik posiada przynajmniej minimalną wiedzę na temat Gita. Niektóre z zagadnień będą jednak na odrobinę wyższym poziomie. Przydatna może okazać się także wiedza na temat programowania w powłoce BASH i o szeroko pojętym Linuksie.
Zachęcam Państwa także do przeczytania poprzednich artykułów z tego cyklu.
Git Flow
Flow jest jednym z moich ulubionych zapożyczeń. Po raz pierwszy usłyszałem o nim, gdy w okresie buntu słuchałem przechwałek raperów mających flow na bicie. Na szczęście dzisiaj zwrotu tego używam w zupełnie innym kontekście. Flow oznacza przepływ, nurt, płynięcie. Mówiąc więc o flow pracy, mamy na myśli jej przepływ, kolejność zadań, wpasowanie się w istniejące schematy, reguły, założenia. Git-Flow, GitFlow lub Git Flow (idea tak ważna, że posiada nawet 3 nazwy :) – w celach SEO pozwolę sobie używać ich zamiennie) jest schematem tworzenia i zarządzania gałęziami w Gicie.
By zainicjować repozytorium z git flow, używamy:
[~/P/a]─> git flow init Initialized empty Git repository in /home/Alex/PycharmProjects/a/.git/ No branches exist yet. Base branches must be created now. Branch name for production releases: [master] Branch name for "next release" development: [develop] How to name your supporting branch prefixes? Feature branches? [feature/] Release branches? [release/] Hotfix branches? [hotfix/] Support branches? [support/] Version tag prefix? [] [~/P/a]─[⎇ develop]─>
Jak widać, klikając kilka razy enter, pozwoliłem sobie na domyślny wybór nazw. Są jednak osoby, które zmieniają nazwy np. gałąź develop, można nazwać dev lub next.
Informację à propos naszego flow zapisywane są w .git/config
[~/P/a]─[⎇ develop]─> cat .git/config # wycięty tekst ... [gitflow "branch"] master = master develop = develop [gitflow "prefix"] feature = feature/ release = release/ hotfix = hotfix/ support = support/ versiontag = # wycięty tekst ...
OK? Mamy tutaj kilka komend i konwencji nazewnictwa, lecz czemu jest to takie ważne? Bo pozwala nam na dobry przepływ pracy i komunikacji w zespole. By zrozumieć, skąd wziął się git-flow, proponuję przeczytać świetny artykuł autora rozwiązania: http://nvie.com/posts/a-successful-git-branching-model/.
Pozwolę sobie skrócić jego treść i wytłumaczyć, do czego służą poszczególne gałęzie.
- master – gałąź główna, tutaj znajduje się stabilny kod pochodzący z gałęzi hotfix i release;
- develop – standardowa gałąź, odzwierciedla najnowszy skończony stan developerski;
- hotfix – gałęzie hotfix (w bardzo luźnym tłumaczeniu gorących napraw), pochodzą z gałęzi master. Używamy ich, gdy nasz kod produkcyjny zawiera błąd, który musi zostać szybko naprawiony. Hot fixy powinny zostać scalone (git merge) do gałęzi master i developerskiej;
- release – pochodzi z gałęzi develop. Jest kandydatem do produkcyjnego wydania (release). Po skończeniu pracy nad nią zmiany są scalane do gałęzi developerskiej i produkcyjnej (master);
- feature – pochodzi z gałęzi develop i służy do dodawania funkcjonalności do naszego kodu. Dobrą praktyką jest używanie numerów z systemów zarządzania wytwarzaniem oprogramowania (np. JIRA). Gałąź posiada wtedy intuicyjną nazwę np. feature/45_dodawanie_produktu. Gotowe funkcjonalności scalamy do gałęzi develop;
- support – gałęzie te nie są uwzględnione w Git Flow, a ich przeznaczenie zależy od naszej wizji. Najczęściej stosuje się je, gdy trzeba utrzymywać wiele wersji oprogramowania. Wówczas support trzyma konkretne starsze wersje (np. support/1.{1,2,3}). Gałęzie support przydają się, gdy musimy załatać krytyczny błąd w starszych wersjach.
Konieczność korzystania z konsoli
Naturalnie rodzi się pytanie: czy by zaimplementować Git-Flow musimy używać konsoli? Odpowiedź brzmi: „nie”.
Większość nowoczesnych zintegrowanych środowisk programistycznych (IDE) posiada odpowiednie wtyczki dla GitFlow. Wiodące narzędzia służące do zarządzania gitem z poziomu GUI, takie jak GitKraken lub SmartGit także mają zdolność zarządzania repozytorium z tym sposobem branchowania.
Ściągawka
Świetną ściągawkę dla Git Flow znajdziemy na stronie: https://danielkummer.github.io/git-flow-cheatsheet/.
Ściągawka została przetłumaczona na język polski. Można ją wydrukować i powiesić w biurze. Jest to dobra praktyka, gdy chcemy wprowadzić tę praktykę w naszym zespole.
Git bisect
Jednym z pierwszych poważnych, tj. nietrywialnych algorytmów, jakich uczy się informatyk, jest wyszukiwanie binarne. W bardzo dużym skrócie – jest to algorytm, który służy do wyszukiwania, w jakim miejscu (indeksie) posortowanego zbioru znajduje się zadany element.
Posiada ono złożoność obliczeniową O(log n). Potrzebujemy zatem wykonać bardzo niewielką ilość operacji, by uzyskać żądany efekt. Dla przykładu log2 1267650600228229401496703205376 = 100. By wyszukać indeks zadanej liczby spośród 1267650600228229401496703205376, potrzebujemy 100 operacji.
W bardzo podobny sposób działa git bisect. Wyszukujemy binarnie commity. Jest to wyjątkowo szybki sposób, by znaleźć commit odpowiedzialny np. za wprowadzenie błędu.
Przykład:
Przykład użycia dla repozytorium gitflow :) Oczywiście w żadnym z nich nie testowałem czy zadany commit jest w porządku. Określenie czy commit jest dobry (good) czy zawiera błąd (bad), jest losowe.
[~/tmp]─> git clone [email protected]:nvie/gitflow.git ... [~/tmp]─> cd gitflow/ [~/t/gitflow]─[⎇ develop]─> git checkout master ... [~/t/gitflow]─[⎇ master]─> git bisect start [~/t/gitflow]─[⎇ master]─> git bisect bad # Określenie obecnego stanu (master) jako zły [~/t/gitflow]─[⎇ master]─> git bisect good e8766e0e09a87d178e8fdcc4e6b9f45500d1040a # Określenie dobrego commitu Bisecting: 146 revisions left to test after this (roughly 7 steps) [99c80527d70aa5ba7c2a21135ff100abd17745ad] Merge branch 'feature/quote-all-var-params' into develop [~/t/gitflow]─> git bisect good Bisecting: 73 revisions left to test after this (roughly 6 steps) [d76add9ee2ea68a4649d0df9615f3ef7ec2c6bba] Remove "important" 0.2 message. [~/t/gitflow]─> git bisect bad Bisecting: 35 revisions left to test after this (roughly 5 steps) [b554186c4c171659fd7bc64367a5848dff288c3d] Merge branch 'release/0.2' into develop [~/t/gitflow]─> git bisect good Bisecting: 17 revisions left to test after this (roughly 4 steps) [5b05ad78d10f8cb596fce1eb8ecf76a232962ace] Fix: incorrect order of arguments in determining whether local branch exists. [~/t/gitflow]─> git bisect good Bisecting: 8 revisions left to test after this (roughly 3 steps) [ddb350b3f26192a4adc3487312915803fd19e8ff] Change the URL of the original blog post. [~/t/gitflow]─> git bisect bad Bisecting: 4 revisions left to test after this (roughly 2 steps) [e4badddb56264c1afd45cbbf4bab6eb08f3e6b24] Added Randy Merrill to the AUTHORS. [~/t/gitflow]─> git bisect good Bisecting: 2 revisions left to test after this (roughly 1 step) [e761e355f4c29dbad1ddc8022fa393ebbadcd78c] Force deletion of the feature branch after finish. [~/t/gitflow]─> git bisect bad Bisecting: 0 revisions left to test after this (roughly 0 steps) [06a5de7111e1b6799b40697881ed9a6b038abb3c] Forgot to mention Jason L. Shiffer in AUTHORS file. ...
Jak widać, w kilku krokach można znaleźć interesujący commit wprowadzający błąd do naszego programu.
Krótki komentarz
Git bisect działa poprawnie tylko wtedy, gdy błąd nie był wprowadzany kilka razy tj. jeśli stworzymy prostą funkcję.
f(commit): 1 -> gdy commit ma błąd, 0 -> gdy nie ma.
Chronologiczna lista naszych commitów musi mieć postać:
[0,…,0,1,…,1]
lub
[1,…,1,0,…,0]
W innym wypadku będziemy łatać błąd, który może mieć przyczynę gdzie indziej, dając nam fałszywe poczucie bezpieczeństwa. W takim przypadku możemy jednak stworzyć przypadek/przypadki testowe ujawniające błąd, by potem wykonać je na starszych wersjach. Da nam to lepszy podgląd na rzeczywistą wartość naszej naprawy.
Git blame
Pomimo najszczerszych chęci oprogramowanie, o którym można powiedzieć, że jest w 100% bez błędów (bugów), nie istnieje. W związku z tym faktem powstało wiele sposobów liczenia pokrycia (instrukcji, decyzji, modułów etc.), które w prosty sposób mówią, ile przetestowaliśmy. Jeśli dojdzie jednak do awarii (zewnętrznej manifestacji błędu), musimy umieć ją powtórzyć – by móc w kontrolowanych warunkach zobaczyć które instrukcje i/lub splot zdarzeń odpowiadają za błąd. Gdy dowiemy się już, które linie kodu odpowiadają za defekt, możemy użyć specjalnego narzędzia dostępnego w Gicie – `blame`.
Pokazuje nam ono, który commit (i jego autor) odpowiada za linie kodu w pliku.
Przykład:
Znów wykorzystamy repozytorium z gitflow z platformy github.
[~/tmp]─> git clone [email protected]:nvie/gitflow.git ... [~/tmp]─> cd gitflow/ [~/t/gitflow]─[⎇ develop]─> git checkout master
Główny skrypt git-flow
zawiera opcje DEBUG. Odpowiadają za to linie 40-43.
By zobaczyć, kto ostatnio zmieniał/dodał te linie, używamy git blame.
[~/t/gitflow]─[⎇ master]─> git blame -L 40,43 git-flow e5eaff95 (Benedikt Böhm 2010-01-26 12:44:55 +0100 40) # enable debug mode e5eaff95 (Benedikt Böhm 2010-01-26 12:44:55 +0100 41) if [ "$DEBUG" = "yes" ]; then e5eaff95 (Benedikt Böhm 2010-01-26 12:44:55 +0100 42) set -x e5eaff95 (Benedikt Böhm 2010-01-26 12:44:55 +0100 43) fi
Teraz korzystając z narzędzia git show, możemy zobaczyć, jak wyglądał zadany commit.
[~/t/gitflow]─[⎇ master]─> git show e5eaff95 commit e5eaff9557e935a870bbcc9551a7c38d4c4d54f5 Author: Benedikt Böhm Date: Tue Jan 26 12:44:55 2010 +0100 add bash debug support diff --git a/git-flow b/git-flow index 7f065e1..d7cee2d 100755 --- a/git-flow +++ b/git-flow @@ -13,6 +13,11 @@ # Copyright (c) 2010 by Benedikt Böhm # +# enable debug mode +if [ "$DEBUG" = "yes" ]; then + set -x +fi + warn() { echo "$@" >&2; } die() { warn "$@"; exit 1; } has() { [[ " ${*:2} " == *" $1 "* ]]; }
Podsumowanie i zapowiedzi
Jak zwykle mam nadzieje, że tekst był ciekawy i się Państwu podobał.
Git posiada jeszcze kilka ciekawych modułów i właściwości, o których chcę opowiedzieć. W następnym artykule użyjemy git submodule oraz dowiemy się więcej o bardziej zaawansowanych możliwościach komendy log i git mergetool.