<p>Систему контроля версий Git первый раз довелось использовать в 2011 году.
Это был достаточно “сомнительный” переход с SVN, потому что еще до старта проекта горели все сроки, лид разработки решил использовать новый фреймворк, но через неделю был переведен в другую команду.
В качестве СУБД “прилетел” неведанный Firebird с ворохом хранимых процедур, потому что мы создавали web-канал взаимодействия для существующего desktop решения.
Меня торжественно нарекли новым лидом над тремя младшими специалистами, невзирая на обстоятельство, что я был четвертым участником аналогичной позиции.
За последние несколько лет моей практики альтернативы Git перестали встречаться окончательно. Единственное, что остается неизменным - это младшие специалисты и регулярные ситуации “сломалось/потерялось” и “забыли/перепутали”.
Данная статья написана по мотивам официальной target="_blank" rel="external nofollow noopener noreferrer"
>
документации Git
<svg aria-hidden="true" class="bi bi-box-arrow-up-right hi-svg-inline" fill="currentColor" height="1em" viewBox="0 0 16 16" width="1em" xmlns="http://www.w3.org/2000/svg">
Git - это распределенная система контроля версий. Технически здесь нет деления на клиента и сервер, а все участники могут существовать независимо, при необходимости равноправно обмениваясь изменениями напрямую между собой. Но с целью снижения количества связей и формализации “источника правды”, обычно выделяют сервер, с которым уже работают остальные пользователи. Репозитории участников принято называть локальными, а репозиторий на сервере - удаленным.
Вводной тест
Основные принципы работы
В большинстве сфер нашей жизни, и IT не стало здесь исключением, поведение чего-то становится для нас достаточно понятным и логичным, если есть представление о внутреннем устройстве данных механизмов.
Одним из базовых определений, которое используют все, является репозиторий. Репозиторий Git - это хранилище данных, представленное специальным набором файлов и “папок”. В локальной копии обычно существует директория .git, которая и является непосредственным корнем репозитория, а не его частью. Файлы и директории, которые находятся на одном уровне с .git - это рабочая область/дерево (working directory/tree/space). Рабочая область является разделом проекта Git, но не частью репозитория.
Третьим основным разделом проекта выделяют индекс (index/staging area), данные относящиеся к нему, хранятся внутри репозитория.
На серверах же создаются голые (bare) репозитории, т.е. какой-нибудь git@github.com:akorolev-dev/git-plumbing-and-porcelain-content.git
представляет собой директорию аналогичной структуры, что и локальная .git.
Рабочая область и индекс в них отсутствуют.
Обычно говорят, что есть два варианта создания нового репозитория:
- Инициализация пустого локального.
- Клонирование удаленного репозитория в локальный.
Информационные сообщения команды init подтверждают, что корнем репозитория является либо .git, либо корень проекта при варианте bare.

Но по факту клонирование просто начинается с инициализации пустого локального репозитория. Это можно воспроизвести разными способами. Например, запросить какой-то репозиторий на существующем сервере, где потребуется пройти аутентификацию вызова. В момент остановки команды клонирования из-за запроса аутентификационных данных уже произойдет инициализация нового пустого репозитория. А в файл конфигурации проекта Git будет добавлен первый псевдоним удаленного репозитория origin. Если аутентификация происходит успешно, то начинается загрузка данных (git fetch).

Также, если предварительно изменить шаблон локального репозитория, то мы увидим данные изменения по итогам завершения клонирования.
Устройство файловой системы
Пустой репозиторий
Репозиторий Git реализован в виде набора файлов и директорий определенной структуры, с адресацией на основе содержимого. Подробно внутреннее устройство описано в 10 разделе книги , мы затронем только отдельные моменты.
Создадим новый проект content с веткой content-article-01, и для отслеживания изменений внутренней структуры этого репозитория
сделаем его самого рабочей областью второго Git проекта, который для удобства будем называть наблюдателем (watcher), с веткой watcher-article-01.

Обратите внимание, что в репозитории уже существуют директории objects и refs, но в коммит они добавлены не были, так как еще не содержат никаких файлов.
Создание первого файла
Давайте в качестве первого файла создадим MIT лицензию, скачав её с github.
В Git существует забавное разделение всех команд на два типа:
- “Фарфор” (Porcelain) - это как раз привычные большинству пользователей команды.
- “Сантехника” (Plumbing) - это команды низкого уровня, которые в первую очередь предназначены для создания инструментов работы с репозиторием Git. Но именно “сантехника” позволяет понять принципы работы данной системы контроля версий.
Посмотрим содержимое нового объекта. Только стоит учесть, что все объекты базы данных Git сжаты алгоритмом
zlib и открыть напрямую их не получится.

Любой объект репозитория создается в поддиректории каталога objects. Наименование файла объекта и наименование его родительской директории получается путем разделения вычисленной контрольной суммы на две части:
- Первые 2 символа формируют название родительской директории.
- Оставшиеся 38 символов становятся наименованием файла с данными по объекту.
Blob - это первый тип создаваемых объектов, который представляет собой снимок отдельного файла. А 1069 - количество байт исходной информации в файле LICENSE, до её сжатия. Метаинформация о типе и размере отделяются от исходного содержимого нулевым символом (NUL/null byte). Стоит обратить внимание, что метаинформация не содержит сведений о наименовании и временных метках, как и назначенных на файл прав.
Модификация первого файла
Проверим что будет, если удалить файл из индекса, изменить в нём строку и опять добавить в индекс.

- База данных практически всегда работает только на добавление новых объектов, не торопясь удалять ранее созданные, для которых уже нет исходных файлов.
- Даже при небольшом изменении файла (модификация 1 строки из 22, и добавлении 18 символов к 1069) производится полный снимок содержимого исходного файла.
Создание первого коммита
Что же, самое время отследить изменения, которые произойдут после создания первого коммита в репозитории “content”.

Объект tree — это представление какой-то директории, в данном случае корня рабочей области. Он содержит ключи объектов дочерних tree и blob. Именно в нем отражаются информация по правам доступа и наименованию файлов или директорий.
Таким образом любой коммит кроме метаинформации о себе содержит ключ полного снимка состояния рабочей директории, начиная с её корня. Да, Git не является системой контроля версий, работающей с отдельными дельтами изменений. Но и снимки состояний делаются только при необходимости.
Создание второго коммита

- commit
- новое tree, так как теперь внутри него два файла
- новый blob для main.txt А вот по части файла LICENSE, содержимое которого не поменялось, будет переиспользован ранее созданный объект, ведь его хеш-адрес остался тем же. Так что “полный снимок” не влечет многократное дублирование tree и blob объектов, если их содержимое не было изменено.
Единственное на что хотелось бы здесь заострить внимание, так это поле parent, которое содержит адрес предыдущего коммита. Именно оно формирует историю изменений. И одновременно является причиной обновления всех хеш-ключей в ветке коммитов, если внести изменения в любое не последнее звено этой цепочки.
Дополнение
Внимательный читатель мог заметить, что мы рассмотрели объекты трех типов, а в тексте было упоминание, что всего их четыре.
Это не опечатка. Четвертым типом является tag, но такие объекты порождаются для аннотированных тегов.
А вот “лёгкие” теги работают только через механизм ссылок и не приводят к созданию нового объекта.
Источник изображения в заголовке Unsplash. Автор Mr Cup / Fabien Barral .










