1. Необходимый базис Git
Цель темы: понимать, что такое Git и чем он принципиально отличается от других систем контроля версий; знать, где физически хранятся данные и как устроены базовые команды.
Определения терминов (в контексте Git)
Система контроля версий (СКВ)
Система контроля версий — инструмент, который фиксирует изменения в файлах во времени и позволяет позже вернуться к любой сохранённой версии, сравнивать изменения и совместно работать над кодом без перезаписи чужих правок.
В контексте темы важно разделение на два подхода:
- Централизованная СКВ (Subversion, CVS, Perforce): один сервер хранит полную историю; клиенты получают только рабочую копию и обращаются к серверу для коммитов и истории. Без доступа к серверу работа сильно ограничена.
- Распределённая СКВ (Git, Mercurial): у каждого участника есть полная копия репозитория, включая всю историю. Коммиты и просмотр истории возможны локально; обмен с другими выполняется через push/pull по желанию.
Репозиторий
Репозиторий — хранилище истории проекта: все коммиты, ветки, теги и служебная информация Git. Физически это каталог .git в корне проекта (при использовании git init в существующей папке) или каталог, который сам является корнем (при git clone). Вся «магия» Git — внутри .git; остальные файлы в проекте — рабочая копия.
Рабочая директория (working tree)
Рабочая директория — каталог с файлами проекта, в которых вы реально редактируете код. Это то, что вы видите в проводнике или в IDE. Изменения в рабочих файлах Git не считает «сохранёнными», пока вы не добавите их в индекс и не сделаете коммит.
Индекс (staging area)
Индекс — промежуточная область между рабочей директорией и историей. Вы явно добавляете в него файлы командой git add; коммит (git commit) сохраняет в репозиторий только то, что в индексе. Так вы контролируете, какие изменения попадут в следующий коммит (например, не включаете временные или лишние файлы).
Коммит (commit)
Коммит — снимок состояния индекса в конкретный момент времени, сохранённый в репозитории с уникальным хешем (SHA-1), сообщением, автором и указателем на родительский коммит(ы). История проекта — цепочка таких коммитов.
Ветка (branch)
Ветка — подвижный указатель на один из коммитов. При новом коммите указатель текущей ветки сдвигается вперёд. Разные ветки позволяют вести параллельные линии разработки (например, main и feature/login).
HEAD
HEAD — указатель на текущую позицию в истории. Обычно HEAD указывает на ветку (например, refs/heads/main), а та — на последний коммит этой ветки. При переходе на конкретный коммит (detached HEAD) HEAD указывает напрямую на коммит.
Объекты Git: blob, tree, commit
- Blob — объект, хранящий содержимое одного файла (без имени; имя хранится в tree).
- Tree — объект, описывающий каталог: список имён файлов/каталогов и ссылок на blob’ы и другие tree.
- Commit — объект коммита: ссылка на tree (снимок файлов), ссылка на родительский коммит(ы), автор, сообщение и т.д.
Эти объекты лежат в .git/objects/ и образуют граф истории.
Git vs централизованные СКВ
| Критерий | Git (распределённый) | SVN (централизованный) |
|---|---|---|
| История и коммиты | Полная копия у каждого | Только на сервере |
| Работа офлайн | Коммиты, просмотр логов, ветки | Почти невозможна |
| Коммит | Локально, мгновенно | Только при доступе к серверу |
| Ветки | Локальные, лёгкие, быстрые | Часто копии каталогов на сервере |
| Конфликты | При слиянии/ребейзе локально или при push | Часто при каждом commit/update |
Пример
После git clone можно делать коммиты, создавать ветки и смотреть git log без интернета. В SVN для коммита и просмотра полной истории нужен доступ к серверу.
Структура каталога .git
Понимание структуры помогает при отладке и при работе с хуками и конфигурацией.
.git/
├── HEAD # куда указывает HEAD (текущая ветка или коммит)
├── config # настройки репозитория
├── objects/ # все объекты (blob, tree, commit)
│ └── [первые 2 символа хеша]/
│ └── [остальные 38 символов]
├── refs/
│ ├── heads/ # ссылки на коммиты по именам веток (branch)
│ └── tags/ # теги
├── index # индекс (staging area) в бинарном виде
├── logs/ # журналы перемещений HEAD и веток (reflog)
└── hooks/ # скрипты на события (pre-commit, post-merge и т.д.)
- Коммиты физически хранятся в
.git/objects/по хешу. - Ветки — это файлы в
refs/heads/, в каждом файле один SHA-1 последнего коммита ветки. - Текущая ветка задаётся тем, на что указывает
HEAD(обычноref: refs/heads/main).
Базовые команды
Инициализация репозитория
git init
Создаёт каталог .git в текущей папке и превращает её в корень репозитория. После этого можно делать коммиты.
mkdir my-project && cd my-project
git init
# Initialized empty Git repository in /path/to/my-project/.git/
Добавление изменений в индекс
git add <файл или каталог>
git add . # все изменения в текущем каталоге и подкаталогах
git add -p <файл> # интерактивно по кускам (patch)
Файл переходит в состояние «staged» и попадёт в следующий коммит.
echo "Hello, World" > readme.txt
git add readme.txt
git status
# On branch main
# Changes to be committed: readme.txt (new file)
Создание коммита
git commit -m "Краткое сообщение о изменении"
Сохраняет текущее состояние индекса как новый коммит и сдвигает текущую ветку на этот коммит.
git commit -m "Add readme"
# [main (root-commit) a1b2c3d] Add readme
# 1 file changed, 1 insertion(+)
# create mode 100644 readme.txt
Просмотр состояния и истории
git status # что изменено / в индексе / не отслеживается
git log # полная история (q — выход)
git log --oneline # краткий вид, один коммит — одна строка
git log -5 # последние 5 коммитов
Практика
Перед каждым коммитом полезно выполнять git status: так вы не забудете добавить нужные файлы и не попадёт лишнее.
Примеры из production
Деплой по коммиту/ветке
В CI/CD часто собирают артефакт из конкретного коммита или ветки. Понимание того, что коммит — неизменяемый снимок с уникальным хешем, объясняет, почему деплой «по хешу» воспроизводим: один и тот же коммит даёт один и тот же код.
# В пайплайне обычно что-то вроде:
git checkout $COMMIT_SHA
docker build -t app:$COMMIT_SHA .
Аудит и расследование
При инциденте смотрят, что менялось: git log -p -- path/to/file или git blame. Знание, что история хранится локально и в удалённом репозитории одинаково (при синхронизации), позволяет проводить аудит и по клонированной копии.
Откат без потери истории
В production предпочитают revert (новый коммит, отменяющий изменения), а не reset (переписывание истории), чтобы не ломать общую историю и уже развернутые коммиты. Понимание разницы «коммит как снимок» vs «указатель ветки» важно при выборе стратегии отката.
Паттерны использования
| Паттерн | Описание |
|---|---|
| Атомарные коммиты | Один коммит — одна логическая правка (одна фича или один фикс). Упрощает ревью, откат и бисект. |
| Осмысленные сообщения | Сообщение коммита ясно описывает «что и зачем», лучше по шаблону (например, «feat: add login form»). |
Проверка через git status |
Перед коммитом смотреть, что в индексе; не коммитить случайно лишнее (секреты, билды). |
Использование .gitignore |
Заранее исключать артефакты сборки, зависимости, локальные конфиги — меньше шансов добавить их по ошибке. |
Антипаттерны
| Антипаттерн | Почему плохо | Что делать вместо |
|---|---|---|
| Коммитить всё подряд | В историю попадают билды, зависимости, секреты; репозиторий раздувается, растёт риск утечки. | Добавлять в коммит только нужные файлы; держать актуальный .gitignore. |
| Пустые или бессмысленные сообщения | Невозможно понять по истории, зачем был коммит; сложно искать изменения и откатываться. | Писать короткое, но содержательное сообщение на каждом коммите. |
| Игнорирование индекса | git add . без просмотра — риск закоммитить временные файлы или конфиги с паролями. |
Использовать git add -p или выборочно git add <file>, проверять git status и git diff --staged. |
| Один гигантский коммит | Трудно ревьюить, откатывать и искать причину бага (bisect). | Дробить изменения на логические коммиты. |
Дополнительные материалы
- Pro Git (книга, на русском) — главы 1–2: основы и работа с Git.
- Git — документация — официальная справка по командам.
- Git Glossary — глоссарий терминов Git.
- Oh Shit, Git!?! — короткие подсказки по типичным «аварийным» ситуациям (на английском).
- Learn Git Branching — интерактивный тренажёр по веткам и слиянию.