-
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 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 <[email protected]> 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 [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 checkout, но Git не установит HEAD на неё, а значит вы не сможете фиксировать свои изменения в ней с помощью git commit.
Git воспринимает удалённые ветки как закладки на последние известные состояния веток на удалённых серверах.