Структура репозитория#

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

Введение: что такое репозиторий Git#

Репозиторий Git — это сердце системы контроля версий. Его можно представить как специальную базу данных, которая хранит не только все файлы вашего проекта, но и полную историю их изменений, а также всю служебную информацию, необходимую для работы. Физически эта «база данных» представляет собой скрытую папку .git в корне вашего проекта.

Существует два основных типа репозиториев:

  • Локальный репозиторий: Полноценная копия репозитория, расположенная на вашем компьютере. С ней вы работаете напрямую (совершаете коммиты, просматриваете историю, создаёте ветки и т.п.).

  • Удалённый репозиторий: Версия вашего проекта, размещённая на сервере (например, на GitLab или внутреннем корпоративном сервере). Используется для обмена изменениями между разработчиками и для резервного копирования кода.

Любая работа начинается с создания или получения локальной копии репозитория.

Логическая структура: состояния файлов#

Прежде чем углубляться в физическое устройство, важно понять логику работы Git. Любой файл в вашем проекте может находиться в одном из четырех основных состояний (три из которых являются непосредственно отслеживаемыми Git):

  1. Не отслеживаемый (Untracked) - Файл, который существует в вашей рабочей папке, но Git никогда о нём не знал ( к примеру только что созданный файл) или вы явно сказали Git его игнорировать. Может не являться состоянием файла в репозитории, так как он только что создан, либо является игнорируемым файлом.

  2. Изменён (Modified) - Файл был изменён в вашей рабочей папке, но Git ещё не знает, что вы планируете сохранить эти изменения. Другими словами, изменения есть, но они не подготовлены к сохранению, но зафиксированы VCS. Является состоянием уже существующего в репозитории файла.

  3. Подготовлен (Staged): - Вы сообщили Git, что конкретная версия файла должна войти в следующий «снимок» проекта (Это делается с помощью команды git add). Файл помещается в специальную промежуточную область, называемую в техническом контексте Индекс (Staging Area).

  4. Зафиксирован (Committed): - Подготовленные изменения были окончательно сохранены в локальную базу данных репозитория (в локальную папку .git) в виде нового коммита. Файл становится частью истории проекта.

Основные состояния соответствуют трём ключевым физическим секциям проекта Git, которые будут рассмотрены далее:

  • Рабочий каталог (Working Tree): Ваши файлы и папки проекта, с которыми вы работаете напрямую.

  • Область подготовленных файлов (Staging Area / Index): Промежуточная зона, где формируется следующий коммит.

  • Каталог .git (Git Directory / Repository): База данных, хранящая всю историю и метаданные.

Рабочий процесс работы с состоянием файлов#

Процесс перемещения изменений из рабочего каталога в базу данных репозитория - это перемещение изменений между этими областями: untracked или modified -> staged -> committed. Он может осуществляться через различные интерфейсы, два основных из которых - командная строка (Terminal / CLI) и интегрированная среда разработки (IDE).

Работа через командную строку (Terminal / CLI)#

  • Отслеживание состояний: - Основным инструментом для определения состояния файлов служит команда git status. Она выводит отчет, разделяющий файлы по их текущим состояниям:

    Пример отслеживания состояний

    • Staged - Перечисляются файлы в секции Changes to be committed, т.е. подготовленные зафиксированные в локальном репозитории.

    • Modified - Перечисляются файлы в секции Changes not staged for commit, т.е. файлы изменённые, но не добавленные в фиксацию следующего коммита.

    • Untracked - Перечисляются файлы в секции Untracked files, т.е. не отслеживаемые файлы, к примеру только что созданные.

    Зафиксированные файлы (Состояние Committed) и файлы, которые игнорируются репозиторием

  • Ключевые операции:

Работа через интегрированную среду разработки (IDE)#

Физическая структура#

При инициализации репозитория в корне вашего проекта создаётся скрытая папка с именем .git. Эта папка и есть репозиторий Git. Все остальные файлы и папки в вашем проекте (кроме .git) составляют рабочую копию (каталог).

gtk/
├── .git/               # Вся служебная информация Git (сам репозиторий)   ├── hooks/*         # Директория для клиентских и серверных скриптов-хуков   ├── info/*          # Глобальные файлы исключений (не отслеживаемые файлы)   ├── objects/*       # Всё содержимое репозитория (коммиты, файлы, дерево каталогов, аннотированные теги)   ├── refs/           # Указатели (ссылки) на коммиты (ветки, теги)      ├── heads/*     # Ссылки на вершины веток (локальные указатели)      ├── remotes/*   # Ссылки на вершины веток (удалённые указатели)      └── tags/*      # Ссылки на теги   ├── COMMIT_EDITMSG  # Файл, содержащий сообщение последнего выполненного коммита   ├── config          # Конфигурационный файл именно для этого репозитория (локальная конфигурация)   ├── description     # Файл с описанием репозитория   ├── FETCH_HEAD      # Файл, который хранит информацию о последних ветках, загруженных с удаленного сервера   ├── HEAD            # Файл-указатель на текущую ветку или коммит   └── index           # Файл, который содержит набор подготовленных файлов для следующего коммита
├── src/*               # Ваши файлы проекта (рабочий каталог)
├── build.sbt           # Ваши файлы проекта (рабочий каталог)
└── README.md           # Ваши файлы проекта (рабочий каталог)

Внимание

Это не полный пример каталога, в нём так же содержатся дополнительные папки и файлы, которые не рассматриваются в данном руководстве.

Рассмотрим ключевые элементы папки .git:

Скрипты-хуки#

Глобальные файлы исключений#

База данных объектов objects/*#

Это самая важная часть репозитория. Git— это, по сути, контентно-адресуемая файловая система, которая содержит следующие данные:

  • снимки файлов blobs,

  • структура каталогов trees,

  • коммиты commits,

  • теги tags,

Они хранятся в виде объектов, каждый из которых идентифицируется своим SHA-1 хешем.

Объекты#

  • BLOB (Binary Large Object): Объект, хранящий содержимое одного файла на момент сохранения, то есть снимок относительно предыдущего изменения. Не хранит метаданные.

  • TREE (Дерево): Объект, представляющий собой один каталог. Он содержит список вложенных в него файлов (указывая на BLOB-объекты) и других каталогов (указывая на другие TREE-объекты), а также их имена.

  • Commit (Коммит): Объект, который связывает всё вместе. Он содержит:

    • Указатель на TREE-объект корневого каталога проекта на момент коммита.

    • Указатели на родительский(ие) коммит(ы): родительский коммит - это предыдущее состояние, на основе которого сделаны текущие изменения.

    • Автора (коммитера), дату и время.

    • Сообщение коммита.

Эта структура формирует направленный ациклический граф, где коммиты связаны друг с другом, что и представляет собой историю проекта.

Система ссылок#

Хранит историю в виде графа коммитов, идентифицируемых только хешами, что неудобно для человека. Для этого существуют ссылки (refs) - простые файлы, хранящие внутри SHA-1 хеш определённого коммита, но имеющие человеко-читаемые имена.

  • refs/heads/: Здесь хранятся ссылки на ветки. Имя файла - это имя ветки, а его содержимое - хеш коммита, на который эта ветка в данный момент указывает (её вершина). Например, файл refs/heads/main содержит хеш последнего коммита в ветке main.

  • refs/tags/: Здесь хранятся ссылки на теги. В отличие от веток, теги - неизменны и всегда указывают на один и тот же коммит, отмечая определённые моменты в истории (например, релизы).

Указатели#

Это специальный файл, который обычно содержит ссылку на текущую активную ветку (т.е. ссылается на файл в refs/heads/).

HEAD указывает на коммит, который в данный момент извлечён в ваш рабочий каталог. Когда вы создаёте новый коммит, он становится потомком того коммита, на который указывает текущий HEAD, а затем он же (HEAD) перемещается на этот новый коммит.

Конфигурационные файлы#

  • config: Файл конфигурации для данного конкретного репозитория. Здесь хранятся настройки, специфичные для этого проекта (например, URL удалённого репозитория, настройки хуков и т.п.).

  • .gitconfig: Глобальный файл конфигурации, применяемый ко всем вашим репозиториям на этом компьютере (например, ваше имя и почта, настройки core.editor и т.п.).

Прочие важные элементы#

  • index: Этот файл (также называемый областью подготовленных файлов) является промежуточной зоной между вашим рабочим каталогом и репозиторием. Когда вы выполняете команду git add, Git вычисляет хеш файла и сохраняет эту информацию в index. При выполнении git commit состояние index фиксируется в виде нового tree-объекта, который затем становится частью создаваемого коммита.

Логическая структура#

Любой файл в вашем рабочем каталоге может находиться в одном из трёх основных состояний, определяемых Git:

  1. Modified (Изменён): Файл был изменён в рабочем каталоге, но эти изменения ещё не были отмечены для включения в следующий коммит (не проиндексированы). Git видит изменения, но пока не готов их сохранить в текущий стейдж.

  2. Staged (Подготовлен): Изменённый файл был отмечен для включения в следующий коммит с помощью команды git add. Его текущая версия помещена в область подготовленных файлов - тот самый index-файл.

  3. Committed (Зафиксирован): Файл безопасно сохранён в вашей локальной базе данных (в папке .git/objects/). Это состояние файла в последнем сделанном коммите.

Эти три состояния соответствуют трём основным секциям проекта Git: рабочему каталогу, области подготовленных файлов ( Индексов) и каталогу .git.