Урок курса

Ветка — указатель, а не копия папки

Git и GitHub с нуля: бесплатный курс с практикой

Коммит хранит снимок, git log показывает историю, а git revert добавляет обратное изменение. Ветка хранит указатель на коммит; переключение в чистом рабочем состоянии обновляет отслеживаемые файлы и индекс до выбранного снимка без создания отдельной копии папки.

Ветка как указатель и HEAD как ссылка на текущую ветку

Ветка в Git — это просто имя, которое хранит хеш одного коммита. Не папка, не копия проекта, не отдельная файловая система — один указатель весом в несколько десятков байт.

Когда вы делаете новый коммит, Git записывает снимок, а затем автоматически сдвигает указатель активной ветки на этот новый коммит. Старый коммит никуда не исчезает — ветка просто перестаёт на него смотреть напрямую и начинает смотреть на новый.

HEAD — отдельный уровень косвенности поверх веток. Это специальная ссылка, которая указывает не на коммит, а на ветку. Обычная схема выглядит так:

HEAD → main → c3d4e5f

HEAD говорит: «я сейчас на ветке main». Ветка main говорит: «мой последний коммит — c3d4e5f». При переключении в чистом состоянии Git обновляет отслеживаемые рабочие файлы и индекс до снимка этого коммита.

Когда вы делаете коммит на ветке main, цепочка меняется так:

HEAD → main → a1b2c3d  (новый коммит)
                 ↑
              c3d4e5f  (родитель)

HEAD при этом не трогается — он по-прежнему указывает на main. Просто main теперь смотрит на другой коммит.

В чистом состоянии отслеживаемая часть рабочей папки и индекс совпадают со снимком HEAD через текущую ветку. Незакоммиченные правки и untracked-файлы могут отличаться от него; их поведение при switch рассматривается отдельно. Git не держит несколько копий файлов на диске параллельно: есть одна рабочая папка и одна активная позиция в истории.

Создание ветки и переключение: git branch и git switch -c

Создайте новую отдельную учебную папку и откройте в ней терминал. Выполните команды по одной:

git init -b main
git config user.name "Учебный автор"
git config user.email "learner@example.invalid"

В обычном текстовом редакторе создайте README.md со строкой «# Проект», сохраните файл. Затем выполните:

git add README.md
git commit -m "Начальный коммит"
git status

В этой папке main содержит один коммит, файл отслеживается, рабочая папка и индекс чисты. Для примеров создания веток используйте эту новую папку. В схемах и сокращённом выводе c3d4e5f — условный ID; свой получите через git log --oneline.

git branch <имя> создаёт новую ветку, но не переключается на неё. HEAD остаётся там, где был. Это удобно, когда нужно зафиксировать точку отсчёта, не прерывая текущую работу.

Пример: находимся на main, последний коммит — c3d4e5f.

$ git branch feature-x

После этой команды существуют две ветки — main и feature-x — и обе указывают на c3d4e5f. HEAD по-прежнему смотрит на main.

$ git branch
  feature-x
* main

Звёздочка у main подтверждает: HEAD не сдвинулся.

git switch -c <имя> делает два действия за раз: создаёт ветку на текущем коммите и переключает на неё HEAD. Флаг -c означает create.

$ git switch -c task/fix-readme

Теперь:

$ git branch
  feature-x
  main
* task/fix-readme

HEAD сдвинулся и теперь указывает на task/fix-readme. Содержимое рабочей папки при этом не изменилось — обе ветки всё ещё смотрят на один и тот же коммит c3d4e5f, поэтому менять нечего.

Ключевая разница между командами: git branch <имя> создаёт ветку и оставляет HEAD на месте; git switch -c <имя> создаёт ветку и переводит HEAD на неё. Для большинства рабочих сценариев удобнее switch -c — один шаг вместо двух.

Коммит в ветке задачи и возврат на main: расхождение указателей

В этом чистом опыте, пока в новой ветке нет ни одного коммита, обе ветки указывают на один коммит и отслеживаемое содержимое одинаково при переключении. Расхождение начинается в момент первого коммита в ветке задачи.

Для этого независимого опыта используйте ещё одну новую папку, отдельно от примеров feature-x и task/fix-readme.

Создайте новую отдельную учебную папку и откройте в ней терминал. Выполните команды по одной:

git init -b main
git config user.name "Учебный автор"
git config user.email "learner@example.invalid"

В обычном текстовом редакторе создайте README.md со строкой «# Проект», сохраните файл. Затем выполните:

git add README.md
git commit -m "Начальный коммит"
git status

В этой папке main содержит один коммит, файл отслеживается, рабочая папка и индекс чисты. Ниже c3d4e5f и a7f1d2e — условные ID; сравнивайте свои значения из git log --oneline.

Исходное состояние: рабочая папка чистая, находимся на main, последний коммит c3d4e5f.

$ git switch -c task/update-readme

Оба указателя — main и task/update-readme — смотрят на c3d4e5f. Проверяем:

$ git log --oneline --all
c3d4e5f (HEAD -> task/update-readme, main) Начальный коммит

Метки HEAD -> task/update-readme и main стоят рядом у одной строки — это и есть визуальное подтверждение того, что две ветки на одном коммите.

В редакторе добавьте в README.md вторую строку «Описание проекта», сохраните файл и зафиксируйте:

$ git add README.md
$ git commit -m "Обновить README"

Смотрим на граф снова:

$ git log --oneline --all
a7f1d2e (HEAD -> task/update-readme) Обновить README
c3d4e5f (main) Начальный коммит

Указатели разошлись: task/update-readme сдвинулся на новый коммит a7f1d2e, main остался на c3d4e5f. Обычный git log показывает коммиты, достижимые из HEAD по родительским связям. Сейчас коммит main — предок коммита задачи, поэтому он виден и без --all, вместе с меткой main при показанном отображении меток. Флаг --all расширяет начальные точки обхода до всех ссылок репозитория, включая другие ветки; он не показывает автоматически каждый потерявший ссылки объект.

Возвращаемся на main:

$ git switch main

Git берёт коммит, на который указывает main (c3d4e5f), и обновляет рабочую папку до его состояния. README.md возвращается к версии из c3d4e5f — строки, добавленной в task/update-readme, там нет.

$ git log --oneline
c3d4e5f (HEAD -> main) Начальный коммит

Коммит «Обновить README» не виден: он существует в истории task/update-readme, но main до него не дотягивается. git log --oneline --all покажет оба коммита одновременно и наглядно покажет, где стоит каждая ветка.

Исчезновение правок при git switch — ожидаемое поведение, а не потеря данных

После git switch main файл README.md теряет строку, которую вы только что добавили. Первая реакция — «Git удалил мои изменения». Это не так.

Git не удалял ничего. Коммит «Обновить README» целиком хранится в объектной базе и прочно привязан к ветке task/update-readme. В чистом опыте отслеживаемая часть рабочей папки отражает коммит текущей ветки — и когда вы перешли на main, Git обновил файлы до состояния коммита main.

Чтобы убедиться, что данные живы, достаточно вернуться:

$ git switch task/update-readme

README.md снова содержит добавленную строку — в точности ту, что была зафиксирована в коммите.

Это поведение — прямое следствие модели указателей. Когда рабочая папка и индекс чисты, их отслеживаемое содержимое соответствует снимку HEAD через активную ветку. После фиксации правок переключение меняет HEAD и обновляет файлы до снимка другой ветки. При незакоммиченных изменениях это совпадение не гарантировано; данный опыт таких изменений не содержит.

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

Задача 1

В чистом учебном репозитории main указывает на коммит А. Выполнили git switch -c task/description, но новых коммитов пока не делали. Как связаны HEAD и две ветки?

Выберите один вариант
Без регистрации · результат не сохраняется

Задача 2

Практика: создайте отдельный репозиторий через init -b main, обе локальные настройки автора и первый коммит README. В чистом состоянии создайте ветку task/description и переключитесь на неё. Дополните README редактором, подготовьте и сохраните правку коммитом. Проверьте общую историю известных веток, вернитесь на main, прочитайте README, затем вернитесь в ветку задачи. Запишите метки веток и HEAD до и после коммита и содержимое README при переключении в обе стороны. Письменно объясните коллеге, где сохранилась правка после возвращения на main.

Платформа проверяет только ответ ниже; действия в своём репозитории и письменные ответы вы проверяете самостоятельно.

В контрольном случае новый коммит Б сохранили только в task/description. main осталась на А. Затем переключились на main. Где находится Б?

Выберите один вариант
Без регистрации · результат не сохраняется

Продолжить с сохранением прогресса

Перейдите к уроку в учебном кабинете.

Перейти к интерактивному уроку