Сантехника и фарфор
В этой книге было описано как пользоваться Git используя примерно три десятка команд, например, checkout, branch, remote и т.п. Но так как сначала Git был скорее инструментарием для создания СУВ, чем СУВ удобной для пользователей, в нём полно команд, выполняющих низкоуровневые операции, которые спроектированы так, чтобы их можно было использовать в цепочку в стиле UNIX, а также использовать в сценариях. Эти команды как правило называют служебными ("plumbing" — трубопровод), а более ориентированные на пользователя называют пользовательскими ("porcelain" — фарфор).
Первые восемь глав книги были посвящены практически только пользовательским командам. В данной главе же рассматриваются именно низкоуровневые служебные команды, дающие контроль над внутренними процессами Git и показывающие, как он работает и почему он работает так, а не иначе. Предполагается, что данные команды не будут использоваться напрямую из командной строки, а будут служить в качестве строительных блоков для новых команд и пользовательских сценариев.
Когда вы выполняете git init в новом или существовавшем ранее каталоге, Git создаёт подкаталог .git, в котором располагается почти всё, чем он заправляет. Если требуется выполнить резервное копирование или клонирование репозитория, достаточно скопировать всего лишь один этот каталог, чтобы получить почти всё необходимое. И данная глава почти полностью посвящена его содержимому. Вот так он выглядит:
$ ls HEAD branches/ config description hooks/ index info/ objects/ refs/
Там могут быть и другие файлы, но непосредственно после git init вы увидите именно это. Каталог branches не используется новыми версиями Git, а файл description требуется только программе GitWeb, на них не стоит обращать особого внимания. Файл config содержит настройки проекта, а каталог info — файл с глобальным фильтром, игнорирующим те файлы, которые вы не хотите поместить в .gitignore. В каталоге hooks располагаются клиентские и серверные хуки, подробно рассмотренные в главе 7.
Итак, осталось четыре важных элемента: файлы HEAD, index и каталоги objects, refs. Это ключевые элементы хранилища Git. В каталоге objects находится, собственно, база данных, в refs — ссылки на объекты коммитов в этой базе (ветки). Файл HEAD указывает на текущую ветку, и в файле index хранится информация индекса. В последующих разделах данные элементы будут рассмотрены более подробно.
Объекты в Git
Git — контентно-адресуемая файловая система. Здорово. Но что это означает? А означает это, что в своей основе Git — простое хранилище ключ-значение. Можно добавить туда любое содержимое, в ответ будет выдан ключ, по которому это содержимое можно извлечь. Для примера, можно воспользоваться служебной командой hash-object, которая добавляет данные в каталог .git и возвращает ключ. Для начала создадим новый Git-репозиторий и убедимся, что каталог objects пуст:
$ mkdir test $ cd test $ git init Initialized empty Git repository in /tmp/test/.git/ $ find .git/objects .git/objects .git/objects/info .git/objects/pack $ find .git/objects -type f $
Git проинициализировал каталог objects и создал в нём подкаталоги pack и info, пока без файлов. Теперь добавим кое-какое текстовое содержимое в базу Git'а:
$ echo 'test content' | git hash-object -w --stdin d670460b4b4aece5915caf5c68d12f560a9fe3e4
Ключ -w команды hash-object указывает, что объект необходимо сохранить, иначе команда просто выведет ключ и всё. Флаг --stdin указывает, что данные необходимо считать со стандартного ввода, в противном случае hash-object ожидает имя файла. Вывод команды — 40-символьная контрольная сумма. Это хеш SHA-1 — контрольная сумма содержимого и заголовка, который будет рассмотрен позднее. Теперь можно увидеть, в каком виде будут сохранены ваши данные:
$ find .git/objects -type f .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
В каталоге objects появился файл. Это и есть начальное внутреннее представление данных в Git — один файл на единицу хранения с именем, являющимся контрольной суммой содержимого и заголовка. Первые два символа SHA определяют подкаталог файла, остальные 38 — собственно, имя.
Получить обратно содержимое объекта можно командой cat-file. Это своеобразный швейцарский армейский нож для проверки объектов в Git. Ключ -p означает автоматическое определение типа содержимого и вывод содержимого на печать в удобном виде:
$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4 test content
Теперь вы умеете добавлять данные в Git и извлекать их обратно. То же самое можно делать и с файлами. Рассмотрим пример. Наиболее простой контроль версий файла можно осуществить, создав его и сохранив в базе:
$ echo 'version 1' > test.txt $ git hash-object -w test.txt 83baae61804e65cc73a7201a7252750c76066a30
Теперь изменим файл и сохраним его в базе ещё раз:
$ echo 'version 2' > test.txt $ git hash-object -w test.txt 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
Теперь в базе содержатся две версии файла test.txt, а также самый первый сохранённый объект: