Как GIT работает глубоко внутри

Как GIT работает глубоко внутри

24 октября 2022 г.

Если вы программист, вы, вероятно, используете GIT. Но задумывались ли вы когда-нибудь, как GIT работает глубоко внутри? Я делаю. К счастью, в Интернете можно найти множество документов о внутреннем устройстве GIT. Когда я читаю их, я должен понимать, что GIT — относительно простая, но очень гениальная система. В этой статье я хотел бы показать вам, как работает GIT внутри. Пойдем со мной в самую глубь кроличьей норы.

Когда вы клонируете свой любимый репозиторий из GitHub или любого другого репозитория git, вы получаете файлы и папку .git. Эта единственная папка .git содержит все. Это не проблема, если вы удалите другие файлы, вы можете просто восстановить их с помощью команды «checkout». Это возможно, потому что все дерево файлов описано в папке .git.

Заглянем в папку .git. Он содержит некоторые файлы и папки. Одной из самых важных является папка объектов. Git — это что-то вроде специальной файловой системы, в которой файл с одним и тем же содержимым хранится только один раз. Таким образом, если у вас есть разные папки, содержащие один и тот же файл, содержимое будет сохранено только один раз. Когда вы сохраняете файл в репозитории Git, он вычисляет хэш SHA1 файла и сохраняет его в папке объектов. Если файл существует в разных местах дерева, он будет сохранен только один раз, потому что SHA1 сопоставит одно и то же содержимое с одним и тем же файлом.

Хэш SHA1 содержимого составляет 20 байт. Первый байт (2 шестнадцатеричных символа) определяет папку в папке объектов, а остальные 19 байт (38 шестнадцатеричных символов) будут именем файла. Например, если хэш контента равен 10116ede2f0bcf2ec0720843616e4a5250ae5268, он будет сопоставлен с objects/10/116ede2f0bcf2ec0720843616e4a5250ae5268.

Если вы клонировали репозиторий и ничего не меняли, то, скорее всего, вы не найдете никакого объектного файла, а только пак-папку и .pack-файл в нем. Это оптимизация. Git извлекает объектные файлы с сервера в один пакетный файл. Вы можете просто распаковать этот единственный файл, если переместите его за пределы каталога .git и запустите

git unpack-objects < ./{pack_file_name}.pack

Эта команда распаковывает объекты в папку объектов в указанном выше формате.

Объектные файлы заархивированы, поэтому, если вы откроете один из них, вы не сможете его прочитать, но вы можете легко распаковать его с помощью следующей команды:

pigz -d < ./.git/objects/10/116ede2f0bcf2ec0720843616e4a5250ae5268

Объекты организованы в деревья. Дерево — это что-то вроде папки в файловой системе, хранящейся в другом файле в папке объектов. Дерево выглядит так:

100644 blob 5f71dbb20efc1dc9bd95e116ebc403659556b58a    .gitignore
100644 blob f288702d2fa16d3cdf0035b15a9fcbc552cd88e7    LICENSE
100644 blob 49e96aecc3c354402c153d759e900354cfcb7c80    README.md
040000 tree 7054d5d9fd2431c4ff4f27537d6a5388b3c73ca9    database
100644 blob 9b50d8c47e0ad56aab6aa570f344c6db5409a955    env.development
100644 blob a473235e1bf1461feef090b2a62b2066d75c7d97    env.template
100644 blob a0f18dc0b81d5122a8eeca6903868f1ea4721ebc    package.json
040000 tree ae9e90c2dcc818fab099dd22093ac5e5adb87bbb    public
040000 tree 0bef5a72fa773367998e501275c262bb0ec75544    scripts
040000 tree 878c06bb25e1752fa6271c6eef51edad0942c3ff    src
100644 blob 604c913eebc2578696d37b7346be681db2591816    tsconfig.json
040000 tree cdd80d4ee72ce05a172e9d6bc05b2d946767d079    views

Этот вывод генерируется командой git cat-file, которая может читать и анализировать любой файл из папки объектов по хешу. Приведенный выше вывод создается:

git cat-file -p 54ca9b88af96f27e181b9a059ca4be1f60e720ba

В первом столбце показан файловый режим, подобный Linux, во втором столбце — тип объекта, в третьем — хэш объекта, а в последнем столбце — имя файла. Дерево Git очень похоже на папку Linux, которая может содержать файлы (BLOB-объекты) и другие папки (дерево). При желании вы можете проверить содержимое некоторых файлов или деревьев с помощью команд, которые мы использовали ранее.

Git можно представить как виртуальную файловую систему, где каждая ветка и каждый коммит в ветках являются папками. Когда вы делаете заказ, вы копируете содержимое выбранной папки за пределы каталога .git. В стандартной файловой системе для этого требуется огромное количество дискового пространства, но из-за продуманного решения Git на основе хэшей и сжатия данные хранятся оптимальным образом.

Для создания ветки потребуется полная копия каталога в стандартной файловой системе, но Git генерирует только один файл, указывающий на дерево источника ветки. Если вы измените файл и сделаете фиксацию, будет создан только объект фиксации, указывающий на измененное дерево, содержащее файл (3 файла вместо полной копии каталога).

Каждый коммит содержит хэш предыдущего коммита (как блокчейн), поэтому историю можно полностью отследить. Это делает эту специальную файловую систему системой контроля версий.

Когда вы вытягиваете или нажимаете, Git отправляет эти объектные файлы другой части в упакованном формате. Из-за именования на основе хэша объекты никогда не будут конфликтовать. Вы можете без проблем скопировать каждый объект из каждого репозитория Git в мире в одну папку. Вот почему для разветвления репозитория на GitHub требуется всего несколько секунд. GitHub ничего не копирует, только создает запись в базе данных, аналогичную ветвлению.

В двух словах, так работает Git. Это хранилище файлов на основе хэшей, которое является сущностью системы, используется многими другими децентрализованными системами. IPFS или Swarm также используют это представление на основе хэшей. Отличие состоит в том, что эти системы добавляют к ним систему обнаружения для поиска заданных хэшей в распределенном сетевом хранилище узлов.

Сочетание системы обнаружения этих децентрализованных файловых систем и возможностей управления версиями Git могло бы стать основой полностью децентрализованной альтернативы GitHub, но это уже другая история…

Если вы хотите узнать больше о Git, вы можете найти все на веб-сайте Git или в Книга Git.


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE