git-identyfikowanie-rewizji

Git – identyfikowanie rewizji

Identyfikowanie rewizji, czyli jak odnieść się do komita istniejącego w naszej historii. Napiszę jakie są możliwe sposoby wraz z przykładami. Zapraszam 🙂

Pełny SHA-1

Pospolicie commit, profesjonalnie identyfikator rewizji czyli 40-znakowy skrót SHA-1. Polecenie:

git log --pretty=oneline

Spowoduje wyświetlenie wszystkich rewizji, każdy w jednej linii z informacją: sha1 a następnie wiadomość commita. Przykład:

C:\MojeProjekty\git (master -> origin)
λ git log
commit 61893e857c17378b845d66979951ddefa5431b04 (HEAD -> master)
Author: Przemysław Juśkiewicz 
Date:   Sat Apr 8 15:38:04 2018 +0100

    c

commit 30be34132ab4bb7f2c4a69dce94294f21009f752
Author: Przemysław Juśkiewicz 
Date:   Sat Apr 8 15:37:56 2018 +0100

    b

commit 1af12d98d1f6146781e4b8e69743bd5bb9cb08c4
Author: Przemysław Juśkiewicz 
Date:   Sat Apr 8 15:37:41 2018 +0100

    a

C:\MojeProjekty\git (master -> origin)
λ git log --pretty=oneline
61893e857c17378b845d66979951ddefa5431b04 (HEAD -> master) add c
30be34132ab4bb7f2c4a69dce94294f21009f752 add b
1af12d98d1f6146781e4b8e69743bd5bb9cb08c4 add a

Każda rewizja jest identyfikowana unikalnym 40-znakowym skrótem SHA-1. Aby przywrócić obszar roboczy, ze stanu konkretnej rewizji, należy wydać polecenie:

git checkout sha-1 
git checkout 30be34132ab4bb7f2c4a69dce94294f21009f752

W tym przypadku nasz obszar roboczy będzie posiadać stan plików z komitu 'a’ oraz 'b’.

Skrócony SHA-1

Zamiast podawać pełnego skrótu SHA-1 możemy podać jego skróconą wersję, która wynosi 4 znaki. Jest jeden warunek, dana rewizja musi być unikatowa. Jeżeli w historii będą dwie rewizje, które mają taki sam początkowy SHA-1, wtedy komenda nie zadziała. Gdy okaże się, że skrócony zapis nie działa, wtedy należy podać więcej niż 4 znaki. Przykład:

C:\MojeProjekty\git (master -> origin)
λ git log --abbrev-commit --abbrev=4 --pretty=oneline
6189 (HEAD -> master) add c
30be add b
1af1 add a

Ilość znaków, jakie podamy podczas polecenia git checkout jest nie ważna, ważne, aby ilość znaków SHA-1 była unikatowa.

//wyświetli skrócną wersje SHA-1
git log --abbrev-commit --pretty=oneline 
61893e8 (HEAD -> master) add c
30be341 add b
1af12d9 add a

//parametr '--abbrev=' definiuje ile znaków ma być podane.
git log --abbrev-commit --abbrev=4 --pretty=oneline

Znaczniki

Jeżeli rewizje oznaczymy znacznikiem

1af1 add a
git tag -a v0.0.1 -m "Wersja 0.0.1"

wówczas poniższe polecenia działają tak samo:

git checkout -f 1af1
git checkout -f v0.0.1

HEAD

HEAD wskazuje ostatnią rewizję w bieżącej gałęzi.

C:\MojeProjekty\git (master -> origin)
λ git log --pretty=oneline
61893e857c17378b845d66979951ddefa5431b04 (HEAD -> master) add c
30be34132ab4bb7f2c4a69dce94294f21009f752 add b
1af12d98d1f6146781e4b8e69743bd5bb9cb08c4 add a

Poniższe polecenia są równoznaczne

git checkout -f 6189
git checkout -f HEAD

Przywracanie rewizji domyślnej

Inaczej mówiąc, rewizja domyślna działa tak samo, jak rewizja z HEAD, różnica jest w zapisie. Poniższe polecenia działają tak samo:

git checkout -f 6189
git checkout -f HEAD
git checkout -f 

Repozytoria nieliniowe

Słowo wstępu, jeżeli nie wiesz, czym jest gałąź (ang. branch), nie przejmuj się :), te elementy zostaną omówione w kolejnych wpisach. Przykłady z nieliniową historią rewizji ma pokazać, że git nie ogranicza się tylko do historii liniowej.

Powyższe przykłady pokazują historie rewizji w jednej linii tzn z jednym rodzicem.

...
O   Third commit ...
^
|
|
O   Second commit
^
|
|
O   First commit

W git istnieją gałęzie (ang. branch), pozwalają one na utworzenie historii nieliniowych, będę pisać o tym w dalszej części serii.

Przykład historii wieloliniowej:

               ...
                   O   Merged commit
                   ^ 
               ----|----
               ^       ^
               |       |                      
               |       |
               |       O Five commit 
three commit   O       ^   
               ^       |
               |       O Four commit
               |       |
Two commit     ----O----  
                   ^
                   |
                   |
One commit         O

Oba przykłady mają wspólny element, mowa o rodzicach (ang. parent revision, parent node).
Używając Gita możemy, identyfikować rodziców za pomocą specjalnych znaków:

X~n
X^n

//LEGEND
X - commit
n - natural numbers
~ - shows n ancestor generation
^ - shows n parent generation

Komity opisujemy tutaj znakiem X. Liczbą naturalną jest n, która wskazuję na konkretnego rodzica. Znak ~ wskazuję na przodka n-tej generacji, zaś ^ mówi o n-tym rodzicu.

Kolejność rodziców

Mając w historii wielu rodziców, warto wiedzieć jaka jest kolejność, który jest pierwszy, drugi i ostatni…
Zaprezentuję to na przykładzie:

                   O   Merged commit
                   ^ 
               ----|----
               ^       ^
               |       |                      
               |       |                 
one commit     O       O two commit                         

Polecenie git log pokaże następujące wiadomości:

Merged commit powstał przez połączenie one commit i two commit
two commnt jest drugim rodzicem rewizji Merged commit
one commit jest pierwszym rodzicem rewizji Merged Commit                       

Czyli pierwszym rodzicem rewizji Merged commit jest one commit, a drugim rodzicem jest two commit.
Mówiąc inaczej, pierwszym rodzicem w historii rewizji, zawsze jest ten najniżej. Gdy spojrzymy na wynik w konsoli, najniższym będzie pierwszy z lewej strony na samym dole. Przykład konsoli:

C:\MojeProjekty\git (master -> origin)
λ git log --all --decorate --oneline --graph
*   69c417e (HEAD -> master) Merge branch 'twoBranch'
|\
| * 857ba5d (twoBranch) Add f      (second branch names twoBranch)
| * 4f927bf Add e
* | a9f7e86 Add d
|/
* 61893e8 (tag: v0.0.1) add c
* 30be341 Add b
* 1af12d9 Add a                    (first branch names master)

Przodek n-tej generacji

Teraz zidentyfikujemy rewizję za pomocą wcześniej wspomnianym przykładzie X~n. Odwołamy się do n-tego przodka w historii liniowej, czyli takim z jednym rodzicem.

...
O   X
^
|
|
O   X~1
^
|
|
O   X~2

W miejsce znaku n podajemy liczbę kroków, o jaką należy cofnąć się w historii. Powyższy przykład mówi nam: X jest dzieckiem, X~1 ojcem, X~2 dziadkiem itp

W miejce X wstawiamy przykładowo znak SHA-1, pełny albo skrócony, można podać HEAD(czyli zaczynamy od dziecka) oraz znaczniki (ang.tags):

git log
61893e857c17378b845d66979951ddefa5431b04 (HEAD -> master) add d
30be34132ab4bb7f2c4a69dce94294f21009f752 add c
1af12d98d1f6146781e4b8e69743bd5bb9cb08c4 add b   (tag: v0.0.1)
1aza7898d1f6146781e4b8e789654jkhb9cb08c4 add a
////////////////////////////////////////////

61893~2  - shows 'add b'
61893~3  - shows 'add a'
HEAD~1   - shows 'add c'
v0.0.1~2 - shows 'add b'

Jeżeli historia rewizji mam kilku rodziców, zapis X~n dotyczny zawsze pierwszego rodzica.

n-ty rodzic

Aby, odwołać się do konkretnego rodzica należy użyć schematu X^n. Tak X^1 wskazuje na pierwszego rodzica, X^2 drugiego itp

Używać komendy X^n możemy tak samo pracować, jak z X~n. Utworzyłem jeden plik a.txt w gałęzi master. Stworzyłem Gałąź A, B i C w każdej z gałęzi robiłem edycje na pliku a.txt. Gałąź główną master scaliłem z gałęziami A, B i C. Obecnie nasz ostatni commit ma plik a.txt, który był edytowany przez 3 różne źródła, teraz doskonale zobaczymy jaki rodzic, jakie zmiany wprowadził za pomocą komendy X^n.
Przykład: (ten przykład wykonuj na konsoli git bash)

touch a.txt
vim a  //(dokonuje edycji pliku, wpisując przykładowy tekst "Test 1")
git add a.txt
git commit -m "Add a.txt with text"

git log
commit be42d1e587684a983e1ebdc2e75122c751292d61
Author: Przemysław Juśkiewicz 
Date:   Sat Apr 10 18:25:41 2018 +0100

//Tworze nowe gałęzie od commit: be42d1e587684a983e1ebdc2e75122c751292d61
git branch A
git branch B
git branch C
//Przechodze do branch A
git checkout A
//Edytuje plik a.txt
vim a.txt (wpisuje "Test 2"
git add a.txt
git commit -m "Add a.txt with text from branch A"
//Te same kroki wykonuje dla branch B i C
git checkout B
vim a.txt (wpisuje "Test 3"
git add a.txt
git commit -m "Add a.txt with text from branch B"
git checkout C
vim a.txt (wpisuje "Test 4"
git add a.txt
git commit -m "Add a.txt with text from branch C"

//Przechodze do gałęzi głównej master
git checkout master
//Dokonuje scalania branchy A,B i C do master
git merge A
git merge B
git merge C
//Podczas merge mogą wystąpić konflikty, nalezy je rozwiązać.
//Czyli wchodzimy do pliku a.txt i usuwamy zbędne znaki po za namszymi "test1, test2 itp" 

//Wydaje polecenie jak poniżej

$ git log --all --decorate --oneline --graph
*   647636f (HEAD -> master) Merge from C
|\
| * fb6960b (C) Change a from C
* | 5edb409 Change a from master
* |   5b62f45 Merge from B
|\ \
| * | b81a745 (B) Add a with text from branch B
| |/
* | dcc4281 (A) Add a with text from branch A
|/
* 6a6ae4d Add a with text

//Teraz będąc w commit:647636f sprawdźmy, ilu rodziców
//miał plik a.txt oraz jakie były robione zmiany.
//Rodzic pierwszy
git show 647636f^1

commit 5edb40975e06c3eb205b22c5366f8cf99dd1c186
Author: Przemysław Juśkiewicz 
Date:   Sat Apr 10 18:27:41 2018 +0100

    Change a from master

diff --git a/a b/a
index 31326ac..a7d686e 100644
--- a/a
+++ b/a
@@ -1,3 +1,5 @@
 Test 1
 Test 2
 Test 3
+Test 4
  
//Rodzic drugi
git show 647636f^2

commit fb6960b19642853ac635efd4a2b37d0ce8de9990 (C)
Author: Przemysław Juśkiewicz 
Date:   Sat Apr 10 18:28:41 2018 +0100

    Change a from C

diff --git a/a b/a
index ac5ab8f..60e9843 100644
--- a/a
+++ b/a
@@ -1 +1,6 @@
 Test 1
+
+
+
+
+Test5        

Sprawdzanie n-tego rodzica dla danego pliku. Powtarzam po raz kolejny :), Jeżeli nie rozumiesz powyższego przykładu, nie przejmuj się, w kolejnej serii będą wpisy dotyczące gałęzi oraz operacji na nich, wtedy ta podkategoria będzie czytelniejsza. Jedyne co z tego podtytułu należy wiedzieć to, że identyfikacje rewizji możemy robić na wiele sposobów. 🙂

Dziennik reflog

W git posiadamy dziennik reflog, w tym dzienniku zapisywane są identyfikatory bieżących rewizji. Gdy wykonujemy operacje na rewizji i 'zapisujemy’ nasze zmiany, wtedy do dziennika reflog trafiają kolejne wpisy.

Do sprawdzenia zawartości dziennika używamy polecenia: git reflog
Przykład:

touch a.txt
git add a.txt
git commit -m a

touch b.txt
git add b.txt
git commit -m b

touch c.txt
git add c.txt
git commit -m c

git reflog
addc5d0 (HEAD -> master) HEAD@{0}: commit: c
05b8f5e HEAD@{1}: commit: b
51d8a85 HEAD@{2}: commit: a

Dziennik reflog jest przydany, gdy chcemy wrócić do stanu kodu przed mergem gałęzi, albo gdy popełnimy jakiś faux-pas i będziemy chcieli wrócić do poprzedniego stanu. Przechodzenie do stanu z danego wpisu z reflog należy użyć polecenia git checkout HEAD@{n}, gdzie n jest liczbą naturalną i oznacza n-ty od góry wpis.

Aby sprawdzić dziennik dla innej gałęzi, należy wydać polecenie git reflog NazwaGalezi.
Przykład:

git branch
* master
 pierwszyBranch
 drugiBranch

git reflog pierwszyBranch
//Tutaj pokażą się wpisy prowadzone dla tej gałęzi.

W dzienniku reflog możemy poruszać się nie tylko za pomocą konkretnej liczby, mam tutaj na myśli n z HEAD@{n}. Oprócz tego można użyć jednostki w czasie np: godziny, bądź daty.

Poniższy przykład pokaże nam dziennik reflog z gałęzi master pokazując rewizje ze stanu godzinę temu, czyli wszystkie operacje na rewizjach wykonane jedną godzine wstecz od aktualnej:

git reflog @{1.hour.ago}
647636f (HEAD -> master) refs/heads/master@{Tue Apr 11 16:28:17 2018 +0100}: commit (merge): Merge from C 
5edb409 refs/heads/master@{Tue Apr 11 16:26:52 2018 +0100}: commit: Change a
5b62f45 refs/heads/master@{Tue Apr 11 16:26:26 2018 +0100}: commit (merge): Merge from B
dcc4281 (A) refs/heads/master@{Tue Apr 11 16:25:53 2018 +0100}: merge A: Fast-forward
6a6ae4d refs/heads/master@{Tue Apr 11 16:24:48 2018 +0100}: commit (initial): Add a with text

Tutaj podobnie ale dostaniemy informację stanu gałęzi master z dnia 11 kwietnia roku 2018 o godzinie 16:30:00

git reflog @{2018-04-11.16:30:00}
647636f (HEAD -> master) refs/heads/master@{Tue Apr 11 16:28:17 2018 +0100}: commit (merge): Merge from C 
5edb409 refs/heads/master@{Tue Apr 11 16:26:52 2018 +0100}: commit: Change a
5b62f45 refs/heads/master@{Tue Apr 11 16:26:26 2018 +0100}: commit (merge): Merge from B
dcc4281 (A) refs/heads/master@{Tue Apr 11 16:25:53 2018 +0100}: merge A: Fast-forward
6a6ae4d refs/heads/master@{Tue Apr 11 16:24:48 2018 +0100}: commit (initial): Add a with text

Poprawne formaty:
@{yyyy-mm-dd.hh:mm:ss}
@{n.minute.ago}
@{n.hour.ago}
@{n.day.ago}

Aby wyczyścić dziennik reflog, użyjemy komendy:
git reflog expire –all –expire=now

Podsumowanie

Dotarliśmy do końca 🙂 w tym wpisie było dużo informacji na temat rewizji oraz informacji o tematyce, która zostanie poruszona w dalszych wpisach mam tu na myśli temat gałęzi i poruszania się po nich. Informację na temat dziennika reflog są bardzo pomocne, mi w pracy z Git’em ten dzienniczek bardzo pomógł, gdy jeszcze byłem początkującym 'git-owcem’ :D.

Jeżeli coś jest nie jasne, czegoś nie rozumiesz, albo zauważyłeś błąd, bądź po prostu chcesz wyrazić swoją opinię, zapraszam Cię do skomentowania, bądź bezpośredniego kontaktu e-mailowego do mnie 🙂

 

 

 

Pozdro 🙂
 

 

Dodaj komentarz

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

*