Git отправляет строку для каждой ссылки, для которой производится обновление. В строке содержится старый хеш, новый хеш и имя обновляемой ссылки. Первая строка также содержит возможности клиента. Далее, клиент загружает упакованный файл со всеми объектами, которых ещё нет на сервере. В конце, сервер отвечает статусным сообщением сообщающем об успехе (или ошибке):
000Aunpack ok
Скачивание данных
Если выполняется скачивание данных, используются процессы fetch-pack и upload-pack. Клиент запускает процесс fetch-pack, который подключающийся к процессу upload-pack на удалённой машине для определения, какие данные будут переданы.
Существуют разные способы запуска upload-pack на удалённом репозитории. Можно запустить его по SSH так же, как и receive-pack. Ещё можно вызвать процесс через Git-демон, по умолчанию принимающий соединения на порте 9418. Процесс fetch-pack после подключения отправляет демону данные примерно следующего вида:
003fgit-upload-pack schacon/simplegit-progit.git\0host=myserver.com\0
Начальные 4 байта задают размер последующих данных, далее следует команда, которую следует запустить, завершаемая нулевым байтом, а потом имя сервера и последний нулевой байт. Git-демон проверяет возможность выполнения команды, а также, что репозиторий существует и имеет необходимые права доступа. Если всё хорошо, демон запускает процесс upload-pack и передаёт запрос ему.
Если извлечение данных производится по SSH, fetch-pack выполняет другие действия:
$ ssh -x git@github.com "git-upload-pack 'schacon/simplegit-progit.git'"
В обоих случаях, после того как fetch-pack подключится, upload-pack передаст обратно следующее:
0088ca82a6dff817ec66f44342007202690a93763949 HEAD\0multi_ack thin-pack \ side-band side-band-64k ofs-delta shallow no-progress include-tag 003fca82a6dff817ec66f44342007202690a93763949 refs/heads/master 003e085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 refs/heads/topic 0000
Это очень похоже на ответ receive-pack, но только возможности другие. В добавок upload-pack отсылает обратно ссылку HEAD, чтобы клиент понимал, на какую ветку переключиться, если выполняется клонирование.
На данном этапе процесс fetch-pack смотрит на объекты, имеющиеся в наличии и для недостающих объектов отвечает словом "want" и за ним SHA объекта. Для уже имеющихся объектов процесс отправляет их хеши со словом "have". В конце списка он пишет "done", и это даёт понять процессу upload-pack, что пора начинать отправлять упакованный файл с необходимыми данными:
0054want ca82a6dff817ec66f44342007202690a93763949 ofs-delta 0032have 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 0000 0009done
Это самый основной случай передачи данных. В более сложных случаях, клиент поддерживает функции multi_ack или side-band, но этот пример иллюстрирует основные взаимодействия используемые процессами умного протокола.
Обслуживание и восстановление данных
Иногда, требуется выполнить очистку — сделать репозиторий более компактным, почистить импортированный репозиторий, или восстановить потерянную работу. Данный раздел охватывает некоторые из этих сценариев.
Обслуживание
Иногда Git сам выполняет команду запускающую автоматический сборщик мусора. Чаще всего, эта команда ничего не делает. Однако, если неупакованных объектов слишком много, или у вас слишком много pack-файлов, Git запускает полноценную команду git gc. Здесь gc это сокращение от "garbage collect", что означает "сборка мусора". Эта команда выполняет несколько действий: собирает все объекты в рыхлом формате и упаковывает их в pack-файлы, объединяет несколько упакованных файлов в один большой, удаляет объекты недостижимые ни из одного коммита и те, которые хранятся дольше нескольких месяцев.
Вы также можете запустить сборку мусора вручную:
$ git gc --auto
Опять же, как правило, эта команда ничего не делает. Необходимо иметь 7000 несжатых объектов или более 50 упакованных файлов, чтобы запустился настоящий gc. Данные пределы можно изменить с помощью параметров gc.auto и gc.autopacklimit в конфигурационном файле.
Другое действие, выполняемое gc — упаковка ссылок в единый файл. Предположим, репозиторий содержит следующие ветки и теги:
$ find .git/refs -type f .git/refs/heads/experiment .git/refs/heads/master .git/refs/tags/v1.0 .git/refs/tags/v1.1
Если выполнить git gc, данные файлы в каталоге refs перестанут существовать. Git перенесёт их в файл .git/packed-refs в угоду эффективности. Файл будет иметь следующий вид:
$ cat .git/packed-refs # pack-refs with: peeled cac0cab538b970a37ea1e769cbbde608743bc96d refs/heads/experiment ab1afef80fac8e34258ff41fc1b867c702daa24b refs/heads/master cac0cab538b970a37ea1e769cbbde608743bc96d refs/tags/v1.0 9585191f37f7b0fb9444f35a9bf50de191beadc2 refs/tags/v1.1 ^1a410efbd13591db07496601ebc7a059dd55cfe9
При обновлении ссылки, Git не будет редактировать этот файл, а добавит новый файл в refs/heads. Для получения хеша для нужной ссылки, Git сначала проверит наличие ссылки в каталоге refs, а к файлу packed-refs обратится только в случае неудачи. Однако, если в каталоге refs файла нет, скорее всего, он в packed-refs.