Git
Chapters ▾ 2nd Edition

10.3 Git Binnenwerk - Git Referenties

Git Referenties

Als je geinteresseerd bent in zien van de geschiedenis van je repository vanaf commit, zeg maar, 1a410e, zou je iets als git log 1a410e kunnen aanroepen om die geschiedenis te bekijken, maar je moet nog steeds onthouden dat 1a410e de commit is die je als beginpunt wilt gebruiken voor die geschiedenis. Het in plaats daarvan handiger zijn als je een bestand zou hebben waarin je die SHA-1 waarde kunt opslaan onder een eenvoudiger naam zoudat je die eenvoudiger naam zou kunnen gebruiken in plaats van die kale SHA-1 waarde.

In Git worden deze simpele namen “referenties” of “refs” genoemd, en je kunt de bestanden die deze SHA-1 waarden bevatten vinden in de .git/refs directory. In het huidige project, bevat deze directory geen bestanden, maar wat er wel in zit is een simpele structuur:

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

Om een nieuwe referentie te maken die je gaat helpen onthouden waar je laatste commit is, kan je technisch gezien iets simpels als dit doen:

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

Nu kan je de head-referentie die je zojuist gemaakt hebt in je Git commando’s gebruiken in plaats van de SHA-1 waarde:

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

Het wordt je niet aangeraden om de referentiebestanden direct te bewerken. Git voorziet in een veiliger commando genaamd update-ref als je een referentie wilt bijwerken:

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

Dit is wat een branch in Git eigenlijk is: een eenvoudige verwijzing of referentie naar de head van een bepaalde werkomgeving. Om achteraf een branch te maken naar de tweede commit, kan je dit doen:

$ git update-ref refs/heads/test cac0ca

Je branch zal alleen werk bevatten van die commit en daarvoor:

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

Nu ziet je Git database er conceptueel zo ongeveer uit:

Git directory objecten inclusief branch head referenties.
Figuur 152. Git directory objecten inclusief branch head referenties.

Als je commando’s aanroept zoals git branch <branchnaam>, roept Git feitelijk die update-ref commando aan om de SHA-1 van de laatste commit op de branch waar je op zit te plaatsten in de referentie die je op dat moment wilt aanmaken.

De HEAD

De vraag is nu, als je git branch <branchnaam> aanroept, hoe weet Git de SHA-1 van de laatste commit? Het antwoord is het HEAD bestand.

Normaalgesproken is het HEAD bestand een symbolische referentie naar de branch waar je op dit moment op zit. Met symbolische referentie bedoelen we dat, in tegenstelling tot een normale referentie, het een verwijzing naar een andere referentie.

Echter, in enkele uitzonderlijke gevallen kan het HEAD bestand de SHA-1 waarde bevatten van een git-object. Dit gebeurt als een tag, commit of remote branch uitcheckt, wat je repository in een "detached HEAD" staat brengt.

Als je naar het bestand kijkt, zie je normaalgesproken zoiets als dit:

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

Als je git checkout test aanroept, werkt Git het bestand bij om er zo uit te zien:

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

Als je git commit aanroept, wordt het commit object aangemaakt, waarbij de ouder van dat commit object wordt gespecificeerd door de SHA-1 waarde die staat in de referentie waar HEAD op dat moment naar verwijst.

Je kunt dit bestand ook handmatig bijwerken, maar alweer is er een veiliger comando om dit te doen: symbolic-ref. Je kunt de waarde van je HEAD met dit commando lezen:

$ git symbolic-ref HEAD
refs/heads/master

Je kunt ook de waarde van HEAD bepalen met het zelfde commando:

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

Je kunt geen symbolische referentie waarde invullen die niet voldoet aan de de refs-stijl:

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

Tags

We zijn zojuist geëindigt met het bespreken van de drie hoofd objecttypen van Git (blobs, trees en commits), maar er is nog een vierde. Het tag object lijkt erg op een commit object — het bevat een tagger, een datum, een bericht en een verwijzing. Het belangrijkste verschil is dat een tag object over het algemeen verwijst naar een commit in plaats van een boom. Het lijkt op een branch referentie, maar het zal nooit bewegen — het verwijst altijd naar dezelfde commit, maar geeft het een vriendelijkere naam.

Zoals besproken in Git Basics, zijn er twee soorten tags: geannoteerd en lichtgewicht. Je kunt een lichtgewicht tag aanmaken door iets als het volgende aan te roepen:

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

Dat is alles wat een lichtgewicht tag is — een referentie dat nooit zal bewegen. Een geannoteerde tag is echter veel complexer. Als je een geannoteerde tag aanmaakt, maakt Git een tag object en schrijft daarna een referentie die daarnaar verwijst, in plaats van direct te verwijzen naar de commit. Je kunt dit zien door een geannoteerde tag aan te maken (met de -a optie):

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

Hier is de SHA-1 waarde van het object die is aangemaakt:

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

En roep nu het git cat-file -p commando aan op die SHA-1 waarde;

$ 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

Merk op dat vermelding van het object wijst naar de SHA-1 waarde van de commit die je hebt getagged. Merk ook op dat het niet perse hoeft te verwijzen naar een commit; je kunt elke Git object taggen. In de broncode van Git, bijvoorbeeld, heeft de onderhouder hun GPG publieke sleutel als een blob object toegevoegd en deze toen getagged. Je kunt de publieke sleutel bekijken door het volgende aan te roepen in een cloon van de Git repository:

$ git cat-file blob junio-gpg-pub

De Linux kernel repository heeft ook een tag die niet naar een commit wijst — de eerste tag die gemaakt is verwijst naar de initiële tree van de import van de broncode.

Remotes

Het derde type referentie die je zult zien is een remote referentie. Als je een remote toevoegt en ernaar pusht, slaat Git voor elke de waarde die je het laatst naar die remote hebt gepusht in de refs/remotes directory. Bijvoorbeeld, je kunt een remote genaamd origin toevoegen en daar je master-branch naar pushen:

$ 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

Je kunt zien wat de master-branch op de origin remote was op met moment dat je voor het laatst met de server hebt gecommuniceerd, door het refs/remotes/origin/master bestand te bekijken:

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

Referenties van remotes verschillen van branches (refs/heads referenties) voornamelijk door het feit dat ze als alleen-lezen worden beschouwd. Je kunt naar een git checkout doen, maar Git zal HEAD nooit naar een laten verwijzen, dus je zult er nooit een kunnen bijwerken met een commit commando. Git gebruikt ze als boekleggers naar de laatst bekende staat van waar deze branches op stonden op die servers.

scroll-to-top