-
1. Введение
- 1.1 О системе контроля версий
- 1.2 Краткая история Git
- 1.3 Что такое Git?
- 1.4 Командная строка
- 1.5 Установка Git
- 1.6 Первоначальная настройка Git
- 1.7 Как получить помощь?
- 1.8 Заключение
-
2. Основы Git
-
3. Ветвление в Git
- 3.1 О ветвлении в двух словах
- 3.2 Основы ветвления и слияния
- 3.3 Управление ветками
- 3.4 Работа с ветками
- 3.5 Удалённые ветки
- 3.6 Перебазирование
- 3.7 Заключение
-
4. Git на сервере
- 4.1 Протоколы
- 4.2 Установка Git на сервер
- 4.3 Генерация открытого SSH ключа
- 4.4 Настраиваем сервер
- 4.5 Git-демон
- 4.6 Умный HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Git-хостинг
- 4.10 Заключение
-
5. Распределённый Git
-
6. GitHub
-
7. Инструменты Git
- 7.1 Выбор ревизии
- 7.2 Интерактивное индексирование
- 7.3 Припрятывание и очистка
- 7.4 Подпись
- 7.5 Поиск
- 7.6 Перезапись истории
- 7.7 Раскрытие тайн reset
- 7.8 Продвинутое слияние
- 7.9 Rerere
- 7.10 Обнаружение ошибок с помощью Git
- 7.11 Подмодули
- 7.12 Создание пакетов
- 7.13 Замена
- 7.14 Хранилище учётных данных
- 7.15 Заключение
-
8. Настройка Git
- 8.1 Конфигурация Git
- 8.2 Атрибуты Git
- 8.3 Хуки в Git
- 8.4 Пример принудительной политики Git
- 8.5 Заключение
-
9. Git и другие системы контроля версий
- 9.1 Git как клиент
- 9.2 Переход на Git
- 9.3 Заключение
-
10. Git изнутри
- 10.1 Сантехника и Фарфор
- 10.2 Объекты Git
- 10.3 Ссылки в Git
- 10.4 Pack-файлы
- 10.5 Спецификации ссылок
- 10.6 Протоколы передачи данных
- 10.7 Обслуживание репозитория и восстановление данных
- 10.8 Переменные окружения
- 10.9 Заключение
-
A1. Приложение A: Git в других окружениях
- A1.1 Графические интерфейсы
- A1.2 Git в Visual Studio
- A1.3 Git в Visual Studio Code
- A1.4 Git в Eclipse
- A1.5 Git в IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine
- A1.6 Git в Sublime Text
- A1.7 Git в Bash
- A1.8 Git в Zsh
- A1.9 Git в PowerShell
- A1.10 Заключение
-
A2. Приложение B: Встраивание Git в ваши приложения
- A2.1 Git из командной строки
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
A3. Приложение C: Команды Git
- A3.1 Настройка и конфигурация
- A3.2 Клонирование и создание репозиториев
- A3.3 Основные команды
- A3.4 Ветвление и слияния
- A3.5 Совместная работа и обновление проектов
- A3.6 Осмотр и сравнение
- A3.7 Отладка
- A3.8 Внесение исправлений
- A3.9 Работа с помощью электронной почты
- A3.10 Внешние системы
- A3.11 Администрирование
- A3.12 Низкоуровневые команды
10.3 Git изнутри - Ссылки в Git
Ссылки в Git
Если вас интересует история репозитория начиная с определённого коммита, например 1a410e
, то для её отображения вы можете воспользоваться командой git log 1a410e
, однако при этом вам всё ещё необходимо помнить хеш коммита 1a410e
, который является начальной точкой истории.
Было бы неплохо, если бы существовал файл, в который можно было бы сохранить значение SHA-1 под простым именем, а затем использовать это имя вместо хеша SHA-1.
В Git такие файлы называются ссылками («references» или, сокращённо, «refs») и расположены в каталоге .git/refs
.
В нашем проекте этот каталог пока пуст, но в нём уже прослеживается некая структура:
$ find .git/refs
.git/refs
.git/refs/heads
.git/refs/tags
$ find .git/refs -type f
Чтобы создать новую ссылку, которая поможет вам запомнить SHA-1 последнего коммита, технически, достаточно выполнить примерно следующее:
$ echo 1a410efbd13591db07496601ebc7a059dd55cfe9 > .git/refs/heads/master
Теперь в командах Git вместо SHA-1 можно использовать только что созданную ссылку:
$ git log --pretty=oneline master
1a410efbd13591db07496601ebc7a059dd55cfe9 Third commit
cac0cab538b970a37ea1e769cbbde608743bc96d Second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit
Тем не менее, редактировать файлы ссылок вручную не рекомендуется, вместо этого 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, а также указатели на вершины веток](png/data-model-4.png)
При выполнении команды git branch <branch>
, в действительности Git запускает команду update-ref
, которая добавляет SHA-1 хеш последнего коммита текущей ветки в файл с именем указанной ветки.
HEAD
Как же Git получает хеш последнего коммита при выполнении git branch <имя ветки>
?
Ответ кроется в файле HEAD.
Файл HEAD — это символическая ссылка на текущую ветку. Символическая ссылка отличается от обычной тем, что она содержит не сам хеш SHA-1, а указатель на другую ссылку.
В некоторых случаях файл HEAD может содержать SHA-1 хеш какого-либо объекта. Это происходит при извлечении тега, коммита или удалённой ветки, что приводит репозиторий в состояние "detached HEAD".
Если вы заглянете внутрь HEAD, то увидите следующее:
$ cat .git/HEAD
ref: refs/heads/master
Если выполнить git checkout test
, Git обновит содержимое файла:
$ cat .git/HEAD
ref: refs/heads/test
При выполнении git commit
Git создаёт коммит, указывая его родителем объект, SHA-1 которого содержится в файле, на который ссылается HEAD.
При желании, можно вручную редактировать этот файл, но лучше использовать команду 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
Символическую ссылку на файл вне .git/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
для этого хеша:
$ 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 cat-file blob junio-gpg-pub
В репозитории ядра Linux также есть тег, указывающий не на коммит: самый первый тег указывает на дерево первичного импорта.
Ссылки на удалённые ветки
Третий тип ссылок, который мы рассмотрим — ссылки на удалённые ветки.
Если вы добавили удалённый репозиторий и отправили в него какие-нибудь изменения, Git сохранит последнее отправленное значение SHA-1 в каталоге 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 checkout
, но Git не установит HEAD на неё, а значит вы не сможете фиксировать свои изменения в ней с помощью git commit
.
Git воспринимает удалённые ветки как закладки на последние известные состояния веток на удалённых серверах.