Якщо вам цікаво подивитися на історію сховища, що досяжна з певного коміту, скажімо, 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 branch <назва гілки>
, Git по суті виконує команду update-ref
, щоб додати SHA-1 останнього коміту поточної гілки до якого забажаєте нового посилання.
Тепер питання в тому, як 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 (блоби, дерева та коміти), проте існує четвертий. Об’єкт теґ дуже схожий на об’єкт коміт — він містить автора теґу, дату, повідомлення та вказівник. Головна різниця в тому, що об’єкт теґ вказує на коміт, а не на дерево. Це схоже на посилання гілки, проте воно ніколи не переміщується — завжди вказує на один коміт, проте надає йому зрозуміліше ім’я.
Як вже обговорено в ch02-git-basics-chapter.asc, існують два головних типи теґів: анотовані та легкі. Ви можете створити легкий теґ, якщо виконаєте щось таке:
$ 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 <[email protected]> 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 [email protected]: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 [email protected]: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 вважає їх закладками на останній відомий стан того, де були ці гілки на цих серверах.