Git
Chapters ▾ 2nd Edition

10.3 Git зсередини - Посилання Git

Посилання Git

Якщо вам цікаво подивитися на історію сховища, що досяжна з певного коміту, скажімо, 1a410e, ви можете виконати щось на кшталт git log 1a410e, щоб переглянути цю історію, проте вам усе одно доведеться памʼятати, що 1a410e — це коміт, що є початковою точкою для цієї історії. Натомість легше було б, якби у вас був файл, що зберігає це значення SHA-1 під простою назвою, щоб ви могли використовувати просту назву замість значення SHA-1.

У Git ці прості назви відомі як “посилання” (reference або ref). Ви можете знайти файли, які містять ці значення SHA-1 у директорії .git/refs. У поточному проекті, ця директорія не містить файлів, проте вона містить просту структуру:

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

Щоб створити нове посилання, яке допоможе вам пам’ятати, де знаходиться ваш останній коміт, ви технічно можете зробити щось настільки просте:

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

Тепер, ви можете використати щойно створене посилання замість значення SHA-1 у командах Git:

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

Ми не заохочуємо вас редагувати файли посилань напряму. Натомість, Git надає для цього безпечнішу команду git update-ref, якщо ви бажаєте оновити посилання:

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

В основі, це і є гілкою в Git: простий вказівник чи посилання на верхівку лінії роботи. Щоб створити гілку з другого коміту, ви можете зробити наступне:

$ git update-ref refs/heads/test cac0ca

Ваша гілка буде містити лише роботу з цього коміту й попередню:

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

Тепер, ваша база даних Git концептуально виглядає так:

Об’єкти директорії Git
Figure 151. Об’єкти директорії Git, включно з посиланнями гілок.

Коли ви виконуєте такі команди як git branch <назва гілки>, Git по суті виконує команду update-ref, щоб додати SHA-1 останнього коміту поточної гілки до якого забажаєте нового посилання.

HEAD

Тепер питання в тому, як Git дізнається SHA-1 останнього коміту, коли ви виконуєте git branch <назва гілки>? Відповідь у файлі HEAD.

Файл HEAD — це символічне посилання на поточну гілку. Під символічним посиланням, ми маємо на увазі, що, на відміну від звичайного посилання, воно зазвичай не містить значення SHA-1, а натомість вказівник на інше посилання. Якщо ви подивитесь на цей файл, то зазвичай побачите щось таке:

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

Якщо виконати git checkout test, Git оновлює цей файл наступним чином:

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

Коли ви виконуєте git commit, він створює об’єкт коміту, якому встановлює батьківській коміт у те значення SHA-1, на яке вказує посилання, на яке вказує HEAD.

Ви також можете вручну редагувати цей файл, проте знову таки, існує безпечніша команда: git symbolic-ref. Ви можете зчитати значення HEAD за допомогою цієї команди:

$ git symbolic-ref HEAD
refs/heads/master

Ви також можете встановити значення HEAD за допомогою тієї ж команди:

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

Ви не можете встановлювати символічні посилання поза стилем refs:

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

Теґи

Ми щойно завершили обговорення трьох основних типів об’єктів Git (блоби, дерева та коміти), проте існує четвертий. Об’єкт теґ дуже схожий на об’єкт коміт — він містить автора теґу, дату, повідомлення та вказівник. Головна різниця в тому, що об’єкт теґ вказує на коміт, а не на дерево. Це схоже на посилання гілки, проте воно ніколи не переміщується — завжди вказує на один коміт, проте надає йому зрозуміліше ім’я.

Як вже обговорено в Основи Git, існують два головних типи теґів: анотовані та легкі. Ви можете створити легкий теґ, якщо виконаєте щось таке:

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

Це і є легкий теґ — посилання, яке ніколи не змінюється. Анотований тег, втім, складніший. Якщо ви створите анотований теґ, Git створить об’єкт теґ, а потім запише посилання, яке вказує на нього, а не на сам коміт. Ви можете побачити це, якщо створите анотований теґ (за допомогою опції -a):

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

Ось значення SHA-1 створеного об’єкта:

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

Тепер, виконайте git cat-file -p для цього значення 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

Завважте, що елемент object вказує на значення SHA-1 коміту, який ви позначили теґом. Також зверніть увагу, що це не обов’язково має бути коміт; ви можете створити теґ для будь-якого об’єкта Git. Наприклад, у вихідному коді Git, супроводжувач додав свій публічний ключ GPG як блоб та створив для нього теґ. Ви можете відобразити публічний ключ, якщо виконаєте наступне після клонування Git репозиторія:

$ git cat-file blob junio-gpg-pub

Репозиторій ядра Linux також має об’єкт теґ, який вказує не на коміт — перший створений теґ вказує на початкове дерево імпорту вихідного коду.

Віддалені посилання

Третій тип посилань, які вам зустрінуться — це віддалені посилання. Якщо ви додасте віддалене сховище та надішлете до нього зміни, Git збереже значення, яке ви востаннє надсилали, для кожної гілки в директорії refs/remotes. Наприклад, ви можете додати віддалене сховище під назвою origin та надіслати до нього свій 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

Потім, ви можете бачити, якою була гілка master віддаленого сховища origin, коли ви востаннє взаємодіяли зі сервером, перевіривши файл refs/remotes/origin/master:

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

Віддалені посилання відрізняються від гілок (посилань refs/heads) головним чином тим, що вважаються доступними лише для читання. Ви можете переключитись на нього, проте Git не переключить туди HEAD, отже ви ніколи його не обновите за допомогою команди commit. Git вважає їх закладками на останній відомий стан того, де були ці гілки на цих серверах.