Git
Chapters ▾ 1st Edition

9.3 Mechanizmy wewnętrzne w Git - Referencje w Git

Referencje w Git

Za pomocą komendy git log 1a410e możesz również przejrzeć całą historię swojego projektu, ale musisz wiedzieć, że 1a410e jest ostatnią zmianą (commitem) aby zobaczyć wszystkie modyfikacje. Potrzebujesz pliku w którym będziesz mógł zapisywać wartość SHA-1 pod łatwiejszą nazwą, tak abyś mógł jej używać zamiast sumy SHA-1.

W Gitcie nazywane są one "referencjami" lub krócej "refs"; możesz znaleźć pliki zawierające wartość SHA-1 w katalogu .git/refs. W obecnym projekcie ten katalog nie zawiera żadnych plików, a jego struktura wygląda tak:

$ find .git/refs
.git/refs
.git/refs/heads
.git/refs/tags
$ find .git/refs -type f
$

Aby stworzyć nową referencję, która pomocna będzie przy zapamiętywaniu który commit jest ostatni, możesz wykonać tę prostą komendę:

$ echo "1a410efbd13591db07496601ebc7a059dd55cfe9" > .git/refs/heads/master

Teraz, możesz używać referencji którą właśnie stworzyłeś zamiast sumy SHA-1 w komendach Gita:

$ git log --pretty=oneline  master
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit

Nie musisz bezpośrednio zmieniać plików referencji. Git udostępnia bezpieczniejsze narzędzie do tego, gdy chcesz zaktualizować referencje wywołaj update-ref:

$ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9

Praktycznie tym samym są gałęzie w Git: proste wskazanie lub referencja na najnowszą wprowadzoną zmianę. Aby stworzyć gałąź z poprzedniego commita, wykonaj to:

$ git update-ref refs/heads/test cac0ca

Twoja gałąź będzie zawierała tylko zmiany starsze niż podany commit:

$ git log --pretty=oneline test
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit

W tej chwili, Twoja baza w Git wygląda podobnie do tej z rysunka 9-4.


Rysunek 9-4. Obiekty w katalogach Git z uwzględnieniem referencji do gałęzi.

Gdy uruchamiasz komendę taką jak git branch (nazwagałęzi), Git po prostu uruchamia komendę update-ref, w celu dodania sumy SHA-1 ostatniego commita w gałęzi na której się obecnie znajdujesz, do referencji którą chcesz stworzyć.

Powstaje pytanie, po uruchomieniu git branch (nazwagałęzi), skąd Git wie jaka jest suma SHA-1 ostatniego commita? Odpowiedź to plik HEAD. W tym pliku znajduje się symboliczne dowiązanie do gałęzi w której się obecnie znajdujesz. Poprzez symboliczne dowiązanie, mam na myśli to, że inaczej niż w przypadku normalnego dowiązania, nie zawiera ono sumy SHA-1, ale wskaźnik na inną referencję. Jak zobaczysz na zawartość tego pliku, zazwyczaj zobaczysz coś w stylu:

$ cat .git/HEAD
ref: refs/heads/master

Po uruchomieniu git checkout test, Git zaktualizuje ten plik, aby zawierał:

$ cat .git/HEAD
ref: refs/heads/test

Gdy uruchomisz git commit, zostanie stworzony obiekt commit, określając rodzica tego obiektu na podstawie wartość SHA-1 na którą wskazuje HEAD.

Możesz również ręcznie zmodyfikować ten plik, ale bezpieczniej będzie użyć komendy symbilic-ref. Możesz odczytać wartość która jest w HEAD przy jej pomocy:

$ git symbolic-ref HEAD
refs/heads/master

Możesz również ustawić nową wartość HEAD:

$ git symbolic-ref HEAD refs/heads/test
$ cat .git/HEAD
ref: refs/heads/test

Nie możesz jednak wstawić symbolicznego dowiązania które jest poza katalogiem refs:

$ git symbolic-ref HEAD test
fatal: Refusing to point HEAD outside of refs/

Tagi

Poznałeś już trzy główne obiekty Gita, ale istnieje jeszcze czwarty. Obiekt tag, jest bardzo podobny do obiektu commit - zawiera informacje o osobie, dacie, treści komentarza i wskaźnik. Główną różnicą jest to, że obiekt tag wskazuje na commit, a nie na obiekt tree. Jest podobny do referencji gałęzi, ale nigdy się nie zmienia - zawsze wskazuje na ten sam commit, ale z łatwiejszą nazwą.

Jak opisałem w rozdziale 2, istnieją dwa typy tagów: opisanych i lekkich. Możesz stworzyć lekką etykietę poprzez uruchomienie:

$ git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d

Właśnie tym jest lekka etykieta - gałęzią która nigdy się nie zmienia. Opisana etykieta jest jednak bardziej skomplikowana. Gdy tworzysz opisaną etykietę, Git stworzy obiekt tag, a następnie zapisze referencję wskazująca na niego, zamiast na obiekt commit. Możesz to zauważyć, po stworzeniu opisanej etykiety (-a wskazuje że będzie to opisana etykieta):

$ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 -m 'test tag'

Stworzona została następująca wartość SHA-1:

$ cat .git/refs/tags/v1.1
9585191f37f7b0fb9444f35a9bf50de191beadc2

Teraz, uruchom komendę cat-file na tej wartość SHA-1:

$ git cat-file -p 9585191f37f7b0fb9444f35a9bf50de191beadc2
object 1a410efbd13591db07496601ebc7a059dd55cfe9
type commit
tag v1.1
tagger Scott Chacon <schacon@gmail.com> Sat May 23 16:48:58 2009 -0700

test tag

Zauważ, że wpis rozpoczynający się od "object" wskazuje na sumą SHA-1 commitu który zatagowałeś. Zauważ również, że nie musi on wskazywać na commit; możesz stworzyć etykietę dla każdego obiektu w Git. Na przykład, w kodzie źródłowym Gita, opiekun projektu zamieścił publiczny klucz GPG, jako obiekt blob i następnie go otagował. Możesz zobaczyć zawartość tego klucz, po wykonaniu

$ git cat-file blob junio-gpg-pub

w kodzie źródłowym Gita. Repozytorium ze źródłami projektu Linux ma również taki tag - pierwszy tag stworzony z początkowego stanu kodu źródłowego.

Zdalne repozytoria

Trzecim typem referencji który poznasz, są referencje zdalne. Jeżeli dodasz zdalne repozytorium i wypchniesz do niego kod, Git przechowa wartość którą ostatnio wypchnąłeś do niego, dla każdej gałęzi w katalogu refs/remotes. Na przykład, możesz dodać zdalne repozytorium o nazwie origin i wypchnąć gałąź master do niego:

$ git remote add origin git@github.com:schacon/simplegit-progit.git
$ git push origin master
Counting objects: 11, done.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (7/7), 716 bytes, done.
Total 7 (delta 2), reused 4 (delta 1)
To git@github.com:schacon/simplegit-progit.git
   a11bef0..ca82a6d  master -> master

Następnie możesz zobaczyć w którym miejscu była gałąź master na zdalnym repozytorium origin w czasie gdy wysyłałeś zmiany, przez sprawdzenie pliku refs/remotes/origin/master:

$ cat .git/refs/remotes/origin/master
ca82a6dff817ec66f44342007202690a93763949

Zdalne referencje różnią się od gałęzi (referencji w refs/heads) głównie tym, że nie mogą być pobrane (przez komendę "checkout"). Git zapisuje jest rodzaj zakładek wskazujących na ostatni znany stan w którym te gałęzi były na serwerze.