Перейти к основному содержанию
`Ctrl`+`K`

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

Описание структуры репозитория `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`.