W poprzednim wpisie wspomniałem o gałęziach, historii liniowej oraz nieliniowej. Teraz nadszedł czas, aby omówić, czym owe gałęzie są. Ten wpis opowie, czym są branch’e, oraz jak ów utworzyć i przełączać się między nimi.
Nim zaczniemy słowo wstępu (legenda)
- Na rysunkach (rys 1, rys 2, rys n… gdzie n to liczba naturalna), zamiast wypisywać wszystkie SHA-1 będę podawać duże litery alfabetu od A do Z
- git commit––allow-empty pozwala utworzyć pustą rewizję
- git commit––allow-empty -m ” Tutaj wiadomosc ” pozwala utworzyć pustą rewizję wraz z wiadomością
- Gałąź, Branch to, to samo. Gałąź == Branch
Co to jest gałąź
Gałąź to nic innego jak wskaźnik na konkretny komit. Utworzenie gałęzi to utworzenie pliku tekstowego ze skrótem SHA-1. Taki plik znajduję się w naszym katalogu
.git->refs->heads/master.
Zawartość pliku master: 2186eb685ead6a4a2273e031750a60dc4ce7657d
Gałąź master
Skąd bierze się gałąź master? Przecież nie tworzymy jej poleceniem git branch
Domyślnie w nowym repozytorium utworzonym poleceniem git init oraz po wykonaniu pierwszej rewizji poleceniem git commit––allow-empty -m ” Wiadomosc komita ” tworzona jest jedna gałąź o nazwie master. Żeby to sprawdzić, wykonaj te trzy kroki, czyli zainicjuj repozytorium, dodaj komit, sprawdź dostępne gałęzie.
git init git commit --allow-empty -m "A" $ git branch * master
Po wykonaniu polecenia git branch dostajemy odpowiedź:
* master
Gwiazdka * informuje, na jakiej gałęzi obecnie jesteśmy. Gdy wykonamy pierwszą rewizję naszą sytuację możemy zobrazować następująco:
Gdy dodamy kolejny commit
$ git commit --allow-empty -m "B"
Wskaźnik master przesunie się na drugą rewizję. Repozytorium będzie wtedy wyglądać następująco:
Za każdym razem, gdy tworzymy rewizję, wskaźnik bieżącej gałęzi przesuwa się do ostatniego komita. Po dodaniu kolejnej rewizji w repozytorium, historia będzie wyglądała jak na rys 3:
Gdy użyjemy polecenia git log––oneline konsola wyświetli historię naszego repozytrium, ktore odzwierciedla rys 3.
$ git log --oneline f83fc25 (HEAD -> master) C 6a913f8 B edda2c9 A
Wskaźnik gałęzi master to skrót SHA-1 ostatnej rewizji. Jest on zapisywany w pliku .git/refs/heads/master.
Tworzenie gałęzi
Do tworzenia gałęzi służy polecenie
git branch nazwa-galezi
Jeżeli chcemy utworzyć nową gałąź i znajdujemy się na ostatnim komicie w naszej historii to nowa gałąź zostanie utworzona na tym samym wskaźniku co master. Tak to wygląda na rysunku 4:
$ git log --oneline f83fc25 (HEAD -> master) C 6a913f8 B edda2c9 A $ git branch FirstBranch $ git log --oneline f83fc25 (HEAD -> master, FirstBranch) C 6a913f8 B edda2c9 A
W folderze .git pojawi się plik .git/refs/heads/FirstBranch zawierający SHA-1 C czyli w moim wypadku f83fc256d7770a054263ad165af3d641c737c314
Poleceniem git branch sprawdzimy, jakie mamy branche w repozytorium oraz na jakiej gałęzi się znajdujemy
$ git branch FirstBranch * master
W moim przypadku znajdują się dwie gałęzie. Bieżącą gałęzią jest gałąź master. Informacje o bieżącej gałęzi znajdziemy w pliku .git/HEAD. Jeżeli bieżącą gałęzią jest master, to w pliku HEAD znajdziemy wpis: ref: refs/heads/master
Reasumując:
git branch – wyświetla wszystkie gałęzie wraz z informacją, na której gałęzi się znajdujemy obecnie.
git branch nazwa-gałęzi – utworzy nową gałąź o podanej nazwie.
Dodanie commit’a do bieżącej gałęzi (master)
Mamy dwa branche, znajdujemy się na gałęzi master, dodajmy nowy komit i sprawdźy jak wygląda nasza historia
$ git commit --allow-empty -m "D" [master 8eeb69f] D $ git log --oneline 8eeb69f (HEAD -> master) D f83fc25 (FirstBranch) C 6a913f8 B edda2c9 A
Jak widać na powyższym przykładzie, master został przesunięty na nową rewizję D, a branch FirstBranch pozostał na poprzednim, czyli na miejscu, gdzie został utworzony.
Dodajmy jeszcze dwa komity. Wystarczy wydać dwa polecenia i nie przejmować się niczym ponieważ nowe rewizję są dodawane automatycznie do bieżącej gałęzi
$ git commit --allow-empty -m "E" [master 584e5cc] E $ git commit --allow-empty -m "F" [master a4fe622] F
Tak teraz wygląda nasza historia
Tworzenie gałęzi na dowolnej rewizji
Utworzyliśmy poprzednio gałąź FirstBranch, gdybyśmy chcieli teraz utworzyć kolejną gałąź to powstała by ona na ostatniej rewizji gałęzi master.
My jednak chcemy utworzyć nową gałąź w innym miejscu, dowolnym, wybranym przez nas. Aby Utworzyć nową gałąź na komicie D należy wydać polecenie
git branch nazwa-galezi SHA-1
Czyli, po wydaniu poniższej komendy
git branch SecondBranch D // pseudo kod git branch SecondBranch 8eeb69f // tak powinno to wyglądać, podajemy SHA-1
Historia będzie wyglądać następująco
W folderze .git/refs/heads/ pojawi się nowy plik o nazwie naszej gałęzi. Zawartość tego pliku będzie posiadać SHA-1, w moim przypadku będzie to 8eeb69f…
Obecnie nasz wskaźnik dalej wskazuje na ostatni komit gałęzi master, wydajmy polecenie i sprawdźmy, że tak jest
$ git branch FirstBranch SecondBranch * master
Przełączanie gałęzi
Potrafimy tworzyć nowe gałęzie, teraz wypadałoby nauczyć się z nich korzystać a jeszcze lepiej nauczyć się przełączać po nich.
$ git checkout nazwa-galezi
Po wydaniu powyższego polecenia przeniesiemy się na wybraną gałąź, pliki w obszarze roboczym przyjmą wartość z ostatniej rewizji w tej gałęzi.
W naszym przypadku wyglądałoby to następująco.
$ git checkout FirstBranch
Po wykonaniu powyższego polecenia nasz obszar roboczy przyjmie dane z komitu C
$ git branch * FirstBranch SecondBranch master
Powyższe polecenie pokaże nam, że obecnie znajdujemy się na gałęzi FirstBranch. Nasza historia komitów będzie wyglądać następująco
Tak jak wspomniałem wcześniej, gwiazdka przy nazwie gałęzi FirstBranch mówi nam o tym, że znajdujemy się na bieżącej gałęzi. W pliku .git/HEAD znajdziemy wpis:
ref :refs/heads/FirstBranch
Dodajmy teraz trzy rewizje na obecnej gałęzi, czyli gałęzi FirstBranch
$ git commit --allow-empty -m "G" [FirstBranch 17a15ab] G $ git commit --allow-empty -m "H" [FirstBranch e2d4c0b] H $ git commit --allow-empty -m "I" [FirstBranch ba4397a] I
Tak teraz wygląda nasza historia
Możemy również zobaczyć naszą historię, która będzie wyglądać podobnie jak rys 9 za pomocą konsoli, wystarczy wydać poniższe polecenie
$ git log --oneline --graph --all
A tutaj wynik powyższego polecenia:
SecondBranch i dodajmy w niej dwie rewizje:$ git checkout SecondBranch $ git commit --allow-empty -m "J" [SecondBranch 0427396] J $ git commit --allow-empty -m "K" [SecondBranch 4ec6098] KRepozytorium teraz wygląda następująco
Tworzenie i przełączanie gałęzi jednym poleceniem
Poprzednio, aby utworzyć gałąź musieliśmy wydać polecenie git branch nazwa-galezi a potem przenieść się na nową gałąź za pomocą polecenia git checkout -b nazwa-galezi. Teraz pokaże inne polecenie, które utworzy gałąź i na nie przejdzie za jednym zamachem
git checkout -b nazwa-galeziStwórzmy nową gałąź ThirdBranch na ostatnie rewizji w gałęzi SecondBranch
git checkout -b ThirdBranch
A co powie konsola?$ git log --oneline --graph --all * 4ec6098 (ThirdBranch, SecondBranch) K * 0427396 J | * ba4397a (FirstBranch) I | * e2d4c0b H | * 17a15ab G | | * 9b9b3d2 (HEAD -> master) F | | * e1a4370 E | |/ |/| * | 8eeb69f D |/ * f83fc25 C * 6a913f8 B * edda2c9 AWydajmy polecenie, które powie nam, na jakiej gałęzi obecnie się znajdujemy
$ git branch FirstBranch SecondBranch * ThirdBranch masterPoleceniem git checkout -b nazwa-galezi SHA-1 możemy utworzyć nową gałąź gdziekolwiek chcemy i od razu zostaniemy na nową gałąź przeniesieni
git checkout -b nazwa-galezi SHA-1Przykładowo utwórzmy FourthBranch na komicie B
git checkout -b FourthBranch B //pseudo kod git checkout -b FourthBranch 6a913f8gitk
Cały czas pokazuję narysowane obrazki albo wynik z polecenia
git log––oneline ––graph––all ale to nie wszystko. Git daje nam również graficzne narzędzie, w którym możemy oglądać wyniki naszej pracy. Aby uruchomić ten graficzny interfejs należy w konsoli wydać polecenie:gitkPo takim zabiegu pojawi nam się kolorowe okienkowe narzędzie 🙂 Ale „hola wędrowcze, zatrzymaj się gdy Cie prosi starzec…” (Baldur’s gate)
Otworzył nam się interfejs ale widzimy tylko dwie rewizje i gałąź o nazwie FourthBranch
Stało się tak ponieważ polecenie gitk wyświetla zawartość aktualnej gałęzi. Aby uzyskać widok wszystkich gałęzi należy wydać polecenie gitk––allDetached HEAD – co to jest
Detached HEAD jest to stan, w którym obecnie nie znajdujemy się na żadnej gałęzi.
Wydajmy polecnie
$ git log --oneline --all 4ec6098 (ThirdBranch, SecondBranch) K 0427396 J ba4397a (FirstBranch) I e2d4c0b H 17a15ab G 9b9b3d2 (HEAD -> master) F 6a913f8 (FourthBranch) B 8eeb69f D f83fc25 C e1a4370 E edda2c9 AA teraz przejdźmy na commit D czyli 8eeb69f, poleceniem
$ git checkout 8eeb69f Note: checking out '8eeb69f'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example: git checkout -bHEAD is now at 8eeb69f D ... MINGW64 /c/gitProj ((8eeb69f...)) Tak wygląda teraz sytuacja na rysunku 13. Znajdujemy się w miejscu: .git/HEAD (czyli na komicie D)
Dostajemy informację od Git’a, że zostaliśmy przekierowani na commit D w moim przypadku SHA-1: 8eeb69f po czym zostajemy w stanie detached HEAD. Git informuje nas, aby utworzyć nową gałąź w tym miejscu, żeby nie stracić nowych elementów znajdujacych się w obszarze roboczym. Zróbmy to o co nas prosi git
$ git checkout -b CreatedBranchFromDetachedHeadW takim przypadku utworzymy nową gałąź i wszystkie komit jakie zostały na niej utowrzone, będą zachowane na nowej gałęzi. (Polecam potestować sobie samemu i zobaczyć jakie będą wyniki)
Będąc wstanie detached HEAD, dodamy jakiś komit z poprawkami, nowymi plikami itp i wrócimy do gałęzi master, to wszystkie zmiany ze stanu detached HEAD zostaną usunięte. Chyba, że zrobimy to, o co nas prosi git. Po kolei:
- Upewnijmy się, że znajdujemy się na gałęzi master
- Przejdźmy na komit C czyli w moim wypadku f83fc25
- Dodajmy pusty komit z wiadomością
- Sprawdźmy historię commitów poleceniem git log––oneline
- Przejdźy na gałąź master
- Przeczytajmy komunikat jaki dostaniemy
$ git branch FirstBranch SecondBranch ThirdBranch FourthBranch * master $ git checkout f83fc25 ... $ git commit --allow-empty -m "L" [detached HEAD 48b9e81] L $ git log --oneline 48b9e81 (HEAD) L f83fc25 C 6a913f8 (FourthBranch) B edda2c9 A $ git checkout master Warning: you are leaving 1 commit behind, not connected to any of your branches: 48b9e81 L If you want to keep it by creating a new branch, this may be a good time to do so with: git branch48b9e81 Switched to branch 'master'
Jak widzimy, Git informuje nas, że jeżeli nie utworzymy nowej gałęzi na poprzednim komicie, to wszelkie nasze zmiany zostaną utracone. Teraz będąc na gałęzi master, wydając polecenie git log––oneline, nie zobaczymy komita z wiadomością L o numerze SHA-1: 48b9e81. Żeby nie utracić zmian na tym komicie, wykonajmy polecenie, o które prosi nas git:
$ git branch CreatedBranchSavingPreviousCommit 48b9e81
W ten o to sposób zostanie utworzona nowa gałąź z wcześniej zapisanymi komitami.
Będąc w stanie detached HEAD, Git poinformuje nas w jakiej jesteśmy sytuacji i co powinniśmy zrobić aby nie narobić sobie kłopotów 🙂
Podsumowanie
Wpis trochę długi, ale myślę, że bardzo ważny. Pokazuje moc Git’a, dający nam do dyspozycji gałęzie. To jest początek tematu zwiazanego z gałęziami. Kolejny wpis powie, jak usuwać gałęzie, zmieniać nazwy gałęzi.
Warto pamiętać o jednej rzeczy pracując z Git’em i gałęziami: jeżeli pracujesz nad jakąś nową funkcjonalnością w swojej aplikacji, to twórz branch per feature. Tworzysz nowy kolor background na stronie – tworzysz nowy branch, zmieniasz logo – tworzysz branch, dodaje button generujący hello world – tworzysz branch…
Na przyszłość, skoro możemy tworzyć wiele branch’y w Git i mieć różne stany plików na różnych gałęziach, to Git daje nam możliwość łączenia gałęzi między sobą, kluczowe słowo to merge, ale o tym później.
Teraz znając pojęcia branch oraz detached HEAD, możemy przypomnieć sobie wpis o rewizjach dzięki którym, będziemy wiedzieć jak tworzyć nowe gałęzie z konkretnymi komitami i ich zawartością.
To tyle na dziś, jeżeli masz jakieś pytania, uwagi, sugestie albo uważasz, że ten wpis jest do bani, to napisz mi to, uwzględniając DLACZEGO jest niedobry, bądź jest dobry 🙂
Pozdro 🙂
cyt.: „Prawda, że ładnie 🙂 nie lekceważ konsoli, źródłem mocy jest ona 🙂”
Pomijając oczywisty fakt, że kurs jest świetny (lepszego nie znalazłem), to bardzo cenię sobie ludzi z niebanalnym poczuciem humoru, co jest to nie tylko miłe ale również świadczy o inteligencji.
Niby banał, ale od czasu do czasu brawa się należą, nawet jeżeli „aktor” tego nie oczekuje.
Marek, bardzo dziękuję za Twój komentarz, to bardzo miłe 🙂
Świetnie wytłumaczone Brawo za zdolności dydaktyczne.
Bardzo dziękuję 🙂