open atlas
↑ К треку
Git: от нуля до сеньора GIT · 03 · 01

Ветки — это указатели

Ветка в git — это всего лишь файл в 41 байт под .git/refs/heads/ — подвижный указатель на один коммит. HEAD указывает на текущую ветку. Поэтому создание ветки O(1) и дёшево, в отличие от систем, копирующих целые рабочие каталоги.

GIT Junior ◷ 15 min
Уровень
ОсновыJuniorMiddleSenior

О ветках в git говорят так, будто каждая — это тяжёлая копия всего проекта, поэтому их боятся создавать, как боялись бы продублировать папку на 2 ГБ. Правда почти комично мала: ветка в git — это один текстовый файл с одним 40-символьным идентификатором коммита. Создание ветки пишет 41 байт. Это вся её стоимость.

К концу этого урока ты сможешь сказать, чем именно ветка является на диске, на что указывает HEAD и почему коммит «двигает» ветку вперёд, ничего при этом не копируя.

Цель

После этого урока ты сможешь объяснить, что ветка — это подвижный указатель (ref) на коммит, хранимый файлом под .git/refs/heads/, описать цепочку HEAD → ветка → коммит и сказать, почему создание ветки и коммит в неё — обе дешёвые операции за константное время.

1

Ветка — это именованный подвижный указатель на один коммит, и не более того. Git хранит её крошечным файлом. Перечисли ветки командой:

git branch
# * main
#   feature-login

* отмечает ветку, на которой ты сейчас находишься. Каждому из этих имён соответствует файл на диске. Посмотри напрямую:

cat .git/refs/heads/main
# 9d1f7a3c2b8e4a6f0c1d2e3f4a5b6c7d8e9f0a1b

Эта 40-символьная шестнадцатеричная строка — идентификатор коммита, на который указывает ветка. Вся ветка — это та одна строка. main ничем особенным для git не является — это просто общепринятое имя ветки по умолчанию, на которой стартует свежий репозиторий (старые репозитории использовали master).

2

Коммит двигает указатель текущей ветки вперёд; он никогда не копирует ветку. Когда ты делаешь коммит, git записывает новый объект-коммит, а затем переписывает файл текущей ветки, чтобы он держал идентификатор нового коммита. Старый коммит никуда не делся — новый записывает его как своего родителя. Так что ветка всегда является вершиной цепочки, уходящей назад по истории:

git commit -m "Add login form"
# main теперь указывает на новый коммит;
# родитель нового коммита — прежняя вершина

В остальных ветках ничего не изменилось. Только в файл ветки, на которой ты был, записалась новая 40-символьная строка.

3

HEAD — это указатель на текущую ветку, указатель на указатель. Git нужно знать, на какой ветке «ты находишься», чтобы коммит знал, какой файл двигать. Это и есть HEAD. Обычно он указывает не на коммит напрямую, а на имя ветки:

cat .git/HEAD
# ref: refs/heads/main

Читай это как цепочку: HEAD → main → коммит 9d1f7a3…. Когда ты переключаешь ветку, меняется только HEAD — его перенаправляют на файл другой ветки. Когда ты коммитишь, HEAD говорит git, какой файл ветки двигать. Два уровня косвенности, и оба — просто текст.

Почему это работает

Эта косвенность — это почему ветвление в git дёшево, а в старых системах не было. В инструментах, которые ветвились копированием рабочего дерева (или серверного пути), ветка стоила времени и диска пропорционально размеру проекта. В git коммиты уже существуют как общие, неизменяемые объекты; ветка лишь добавляет имя, указывающее в этот существующий граф. Создание ветки — O(1), один маленький файл, неважно, 10 файлов в репозитории или 100 000.

4

«Отсоединённый HEAD» (detached HEAD) — это когда HEAD указывает прямо на коммит, минуя уровень ветки. Если ты переключишься на конкретный коммит вместо ветки, HEAD будет держать идентификатор коммита напрямую, а не строку ref: refs/heads/…:

git checkout 9d1f7a3
# You are in 'detached HEAD' state.
cat .git/HEAD
# 9d1f7a3c2b8e4a6f0c1d2e3f4a5b6c7d8e9f0a1b

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

Разбор примера

Наблюдаем, как двигаются указатели.

Стартуем на main, указывающей на коммит A. То есть HEAD → main → A.

Создай ветку и останься на месте:

git branch feature

Теперь под .git/refs/heads/ два файла — main и feature — оба содержат идентификатор A. HEAD по-прежнему указывает на main. Ни один коммит не скопирован; ты лишь добавил один файл в 41 байт.

Переключись на неё и закоммить:

git switch feature
git commit -m "Start feature"   # создаёт коммит B, родитель A

HEAD → feature → B, и родитель B — это A. Файл main не тронут — он по-прежнему держит A. Две ветки теперь разошлись: main на A, feature на B. Всё, что произошло: записан один новый объект-коммит и переписаны несколько байт файла feature — с идентификатора A на идентификатор B. Это и есть вся механика ветвления.

Частая ошибка

Частое заблуждение: «если я удалю ветку, потеряю ли я эти коммиты?» Удаление ветки убирает только указатель — объекты-коммиты остаются в хранилище объектов, пока до них может дотянуться что-то ещё (другая ветка, тег или твой reflog). Удалить feature после слияния в main ничего не теряет, потому что main всё ещё может дотянуться до этих коммитов. Именно об удалении не слитой ветки git предупреждает, потому что тогда указатель был единственным путём назад к той работе.

Проверь себя
Викторина

Что физически происходит на диске, когда ты создаёшь новую ветку в git?

Итог

Ветка — это подвижный указатель на один коммит, хранимый файлом в 41 байт под .git/refs/heads/ — этот маленький файл и есть ветка. HEAD — это указатель на текущую ветку (ref: refs/heads/main), образующий цепочку HEAD → ветка → коммит. Коммит двигает файл текущей ветки на новый коммит; ничего не копируется, поэтому создание ветки и коммит — обе дешёвые операции за константное время. Когда HEAD указывает прямо на коммит вместо ветки, ты в отсоединённом HEAD — нормально для осмотра, рискованно для новой работы. Дальше ты выучишь команды, которые создают эти указатели и двигают HEAD между ними: git switch и git branch.

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 4 завершено

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.