Каждый коммит содержит - в любом случае, логически - полный снимок каждого файла (ну, каждый файл, который находится в коммите).
Если вы выбираете коммит, например, по его номеру ha sh и запустите git checkout
для этого коммита, ваше рабочее дерево заполняется из файлов, которые находятся в этом коммите. То есть ваше рабочее дерево берет этот снимок. Переключитесь с этого коммита на другой коммит, который имеет, скажем, на три файла меньше, и Git удаляет эти три файла (и обновляет оставшиеся, если / при необходимости).
Если каждый коммит объект содержит все записи объектов, в долгосрочной перспективе он займет огромное пространство.
За исключением ... это не так. Здесь задействованы два удивительных (или не очень удивительных) умения умения.
Первый обнаруживается прямо здесь:
[test]$git cat-file -p 70951b429e0e1191a8c1d9e34248cd76453ef544
100644 blob 9a6c8d12dea8859b821b2ba705f7efd6cc914aa5 a.txt
100644 blob 9a6c8d12dea8859b821b2ba705f7efd6cc914aa5 b.txt
100644 blob b6693b64f528de38cde5533acd781fde743bc3df c.txt
100644 blob 91174caefafdc81d34e302874c86c6e4d5212075 d.txt
100644 blob 29f4cfc46ba3a0bde55bce8f44ac3590e2108da4 e.txt
Обратите внимание, что blob ha sh ID 9a6c8d12dea8859b821b2ba705f7efd6cc914aa5
отображается дважды: один раз для a.txt
и один раз для b.txt
.
Существует только одна копия содержимого как a.txt
, так и b.txt
. Из этого мы можем сделать вывод, что все, что равно в a.txt
и в b.txt
, содержимое одинаково.
Итак, если вы передадите 100 файлов, затем сделайте новый коммит, в котором 99 файлов совпадают с 99 из файлов предыдущего коммита, вы просто повторно использовали 99 объектов BLOB. Их не нужно было снова сохранять.
Git автоматически удаляет дубликаты содержимого файла таким образом.
Второй бит ловкости происходит позже . Первоначально все объекты хранятся в виде zlib-сжатых файлов (файлы в .git/objects/
, хотя вы не должны на это рассчитывать). Если вы измените несколько байтов в файле и используете git add
, а новый объект BLOB-объекта не будет на 100% точно соответствовать некоторому уже существующему объекту BLOB-объекта, вы получите новый один из этих объектов. Они называются незакрепленными объектами, внутренне.
Когда вокруг достаточно много незакрепленных предметов или раньше, если необходимо, Git упаковывает незакрепленных предметов в файл пакета . В это время объекты, которые могут быть выгодно дельта-сжаты, обычно являются. Это сжатие - действительно умный код.
Когда вы используете git fetch
или git push
, Git выяснит, какие объекты необходимо передать по сети, и создаст так называемый тонкий пакет . Здесь вы видите сообщения counting
и compressing objects
. Git затем отправляет тонкий пакет по проводу; Git на другом конце исправляет тонкую пачку, чтобы сделать ее обычной (жирной) пачкой. Когда слишком много файлов пакета, Git будет перепаковывать файлы пакета, перенося вас от множества файлов *.pack
и *.idx
до нескольких (или одного) снова.
(Здесь были некоторые случайные ошибки. Недавно было исправлено большое количество файлов пакетов. Есть несколько старых ошибок, когда вокруг оставалось слишком много незакрепленных объектов. Иногда полезно работать с ручным руководством git gc
). вокруг этих ошибок, но слишком частое использование git gc
может привести к обратным результатам.)