GitBranch

Git – Branch

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 commitallow-empty pozwala utworzyć pustą rewizję
  • git commitallow-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 commitallow-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 logoneline 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] K

Repozytorium 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-galezi

Stwó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 A

Wydajmy polecenie, które powie nam, na jakiej gałęzi obecnie się znajdujemy

$ git branch
  FirstBranch
  SecondBranch
* ThirdBranch
  master

Poleceniem 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-1

Przykładowo utwórzmy FourthBranch na komicie B

git checkout -b FourthBranch B //pseudo kod
git checkout -b FourthBranch 6a913f8 

gitk

Cały czas pokazuję narysowane obrazki albo wynik z polecenia
git logoneline graphall 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:

gitk

Po 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 gitkall

Detached 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 A

A 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 -b 

HEAD 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 CreatedBranchFromDetachedHead

W 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 logoneline
  • 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 branch  48b9e81

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 logoneline, 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 🙂
 

4 komentarze

  1. 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.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *

*