Git
Chapters ▾ 2nd Edition

10.3 Git Internals - Git References

Git References

Chcete-li si prohlédnout celou svou historii, můžete zadat příkaz git log 1a410e. Problém je v tom, že si k prohlížení historie a nalezení objektů stále ještě musíte pamatovat, že poslední revizí byla 1a410e. Hodil by se soubor, do nějž budete pod jednoduchým názvem ukládat hodnotu SHA-1. Tento ukazatel pro vás bude srozumitelnější než nevlídná hodnota SHA-1.

In Git, these are called “references” or “refs”; you can find the files that contain the SHA-1 values in the .git/refs directory. V aktuálním projektu nejsou v tomto adresáři žádné soubory, zatím tu najdete jen jednoduchou strukturu:

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

Chcete-li vytvořit novou referenci, díky níž si budete pamatovat, kde se nachází vaše poslední revize, lze to technicky provést velmi jednoduše:

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

Nyní můžete v příkazech Git používat „head“ referenci, kterou jste právě vytvořili, místo hodnoty SHA-1:

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

You aren’t encouraged to directly edit the reference files. Git zná bezpečnější metodu, jak referenci aktualizovat: příkaz update-ref:

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

That’s basically what a branch in Git is: a simple pointer or reference to the head of a line of work. Chcete-li vytvořit větev zpětně na druhé revizi, můžete zadat:

$ git update-ref refs/heads/test cac0ca

Vaše větev bude obsahovat pouze práci od této revize níže:

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

Now, your Git database conceptually looks something like this:

Git directory objects with branch head references included.
Figure 152. Git directory objects with branch head references included.

When you run commands like git branch (branchname), Git basically runs that update-ref command to add the SHA-1 of the last commit of the branch you’re on into whatever new reference you want to create.

The HEAD

Nyní se však nabízí otázka, jak může Git při spuštění příkazu git branch (název větve) znát hodnotu SHA-1 poslední revize. Odpověď zní: soubor HEAD.

The HEAD file is a symbolic reference to the branch you’re currently on. By symbolic reference, we mean that unlike a normal reference, it doesn’t generally contain a SHA-1 value but rather a pointer to another reference. If you look at the file, you’ll normally see something like this:

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

Spustíte-li příkaz git checkout test, Git aktualizuje soubor do následující podoby:

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

Spustíte-li příkaz git commit, systém vytvoří objekt revize, jehož rodičem bude hodnota SHA-1, na niž ukazuje reference v souboru HEAD.

Soubor můžete editovat také ručně, ale opět existuje i bezpečnější příkaz: symbolic-ref. Hodnotu souboru HEAD můžete načíst tímto příkazem:

$ git symbolic-ref HEAD
refs/heads/master

Hodnotu pro soubor HEAD můžete také nastavit:

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

You can’t set a symbolic reference outside of the refs style:

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

Značky

We just finished discussing Git’s three main object types, but there is a fourth. The tag object is very much like a commit object – it contains a tagger, a date, a message, and a pointer. The main difference is that a tag object generally points to a commit rather than a tree. It’s like a branch reference, but it never moves – it always points to the same commit but gives it a friendlier name.

As discussed in Základy práce se systémem Git, there are two types of tags: annotated and lightweight. Prostou značku lze vytvořit spuštěním například tohoto příkazu:

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

That is all a lightweight tag is – a reference that never moves. Anotovaná značka je už složitější. Vytvoříte-li anotovanou značku, Git vytvoří objekt značky a zapíše referenci, která na objekt ukazuje (neukazuje tedy na samotnou revizi). You can see this by creating an annotated tag (-a specifies that it’s an annotated tag):

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

Here’s the object SHA-1 value it created:

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

Nyní pro tuto hodnotu SHA-1 spusťte příkaz cat-file:

$ 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

Všimněte si, že záznam objektu ukazuje na hodnotu revize SHA-1, k níž jste značku přidali. Also notice that it doesn’t need to point to a commit; you can tag any Git object. Ve zdrojovém kódu systému Git správce například vložil svůj veřejný klíč GPG jako objekt blobu a ten označil značkou. You can view the public key by running this in a clone of the Git repository:

$ git cat-file blob junio-gpg-pub

The Linux kernel repository also has a non-commit-pointing tag object – the first tag created points to the initial tree of the import of the source code.

Reference na vzdálené repozitáře

The third type of reference that you’ll see is a remote reference. Přidáte-li vzdálený repozitář a odešlete do něj revize, Git v adresáři refs/remotes uloží pro každou větev hodnotu, kterou jste do tohoto repozitáře naposled odesílali. Můžete například přidat vzdálený repozitář origin a odeslat do něj větev master:

$ 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

Poté se můžete podívat, jakou podobu měla větev master na vzdáleném serveru origin, když jste s ním naposledy komunikovali. Pomůže vám s tím soubor refs/remotes/origin/master:

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

Remote references differ from branches (refs/heads references) mainly in that they’re considered read-only. You can git checkout to one, but Git won’t point HEAD at one, so you’ll never update it with a commit command. Git manages them as bookmarks to the last known state of where those branches were on those servers.