>> store = header + content
=> "blob 16\u0000what is up, doc?"
>> require 'digest/sha1'
=> true
>> sha1 = Digest::SHA1.hexdigest(store)
=> "bd9dbf5aae1a3862dd1526723246b20206e5fc37"
Git сжимает новые данные при помощи zlib, в Ruby это можно сделать с помощью одноимённой библиотеки. Сперва необходимо подключить её, а затем вызвать Zlib::Deflate.deflate():
>> require 'zlib'
=> true
>> zlib_content = Zlib::Deflate.deflate(store)
=> "x\x9CK\xCA\xC9OR04c(\xCFH,Q\xC8,V(-\xD0QH\xC9O\xB6\a\x00_\x1C\a\x9D"
После этого запишем сжатую zlib’ом строку в объект на диск. Определим путь к файлу, который будет записан (первые два символа хеша используются в качестве названия директории, оставшиеся 38 — в качестве имени файла в ней). В Ruby для безопасного создания нескольких вложенных директорий можно использовать функцию FileUtils.mkdir_p(). Далее, откроем файл вызовом File.open() и запишем сжатые данные вызовом write() для полученного файлового дескриптора:
>> path = '.git/objects/' + sha1[0,2] + '/' + sha1[2,38]
=> ".git/objects/bd/9dbf5aae1a3862dd1526723246b20206e5fc37"
>> require 'fileutils'
=> true
>> FileUtils.mkdir_p(File.dirname(path))
=> ".git/objects/bd"
>> File.open(path, 'w' ) { |f| f.write zlib_content }
=> 32
Вот и всё, мы создали корректный блоб Git. Все другие объекты создаются аналогично, меняется лишь запись о типе в заголовке (blob, commit либо tree). Стоит добавить, что хотя в блобе может храниться почти любое содержимое, содержимое деревьев и коммитов записывается в очень строгом формате.
Для просмотра истории можно выполнить команду типа git log 1a410e, но вам всё ещё придётся запоминать, что именно коммит 1a410e является последним, чтобы иметь возможность найти все наши объекты. Было бы неплохо, если бы существовал файл с понятным названием, содержащий этот 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 схематично выглядит так, как показано на рисунке:

Рисунок 4. Объекты в директории .git, а также указатели на вершины веток.
Когда выполняется команда git branch (имя ветки), Git, по сути, выполняет update-ref для добавления хеша последнего коммита текущей ветки под указанным именем в виде новой ссылки.
Как же Git получает хеш последнего коммита при выполнении git branch (имя ветки)? Ответ кроется в файле HEAD.
Файл HEAD — это символическая ссылка (не в терминах файловой системы) на текущую ветку. Символическая ссылка отличается от обычной тем, что она содержит не сам хеш SHA-1, а указатель на другую ссылку. Если вы заглянете внутрь 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 можно так:
Читать дальше