Урок курса
Ветка — указатель, а не копия папки
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. Где находится Б?
Продолжить с сохранением прогресса
Перейдите к уроку в учебном кабинете.
