$ sudo teach IT
Модуль 4 · Ветки · Урок 4.1

Ветки в Git

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

Теория + практика~20 минутНовичокgit branchgit switch

Ветка — параллельная история

Ветка в Git — это отдельная линия истории проекта: в ней можно делать коммиты, а рабочая версия в ветке main в это время остаётся нетронутой. Вы создадите ветку feature/projects, добавите в ней страницу проектов и научитесь переключаться между ветками командой git switch.

Отменять ошибки и доставать «потерянные» коммиты через reflog вы уже умеете. Но экспериментировать прямо в рабочей версии всё равно неуютно: пока новая страница не готова, сайт в main должен оставаться целым. Для этого и придуманы ветки.

Простыми словами

Вы пишете книгу и хотите переписать главу. Чистовик не трогаете, пробуете в черновике. Получилось — переносите главу в книгу, нет — выбрасываете черновик. Ветка — такой черновик для всего проекта.

Официальный термин

В документации ветка (branch) — это подвижный указатель на коммит: крошечная запись с хешем последнего коммита линии. При новом коммите указатель текущей ветки сам передвигается на него. Поэтому ветка создаётся мгновенно и почти ничего не весит.

Частая путаница: ветка и копия папки

Многие сначала делают «ветки» руками: копируют папку в portfolio-new или portfolio-final2. Ветка Git — не копия: папка проекта остаётся одна, а при переключении Git сам подменяет в ней файлы. Никаких дублей на диске.

Где тут HEAD

HEAD вы уже встречали, когда смотрели старый коммит: это отметка «где вы сейчас». Обычно HEAD указывает не на коммит, а на ветку: «я на ветке main». А ветка указывает на свой последний коммит:

Схема
HEAD  -->  main  -->  5acc5ae (Revert "Поменять цвет фона")

Что на схеме: вы стоите на ветке main, а main смотрит на коммит 5acc5ae — последний коммит прошлого модуля. Сделаете новый коммит — main передвинется на него, а HEAD так и останется на main.

git branch и git switch -c

Сначала посмотрим, какие ветки уже есть. Выполните в папке проекта:

Терминал
$ git branch
* main

Разбор по строкам

  • * main — ветка пока одна, main. Звёздочка отмечает текущую ветку, на которую смотрит HEAD.

Ветка main у вас с первого коммита. Создадим новую ветку и сразу перейдём на неё. Команда git switch значит «переключиться», а флаг -c (от create) — «сначала создать»:

Терминал
$ git switch -c feature/projects
Switched to a new branch 'feature/projects'
$ git branch
* feature/projects
  main

Разбор по строкам

  • Switched to a new branch 'feature/projects' — «переключились на новую ветку feature/projects».
  • * feature/projects — звёздочка переехала: теперь вы на новой ветке.
  • main — main никуда не делась. Сейчас обе ветки указывают на один и тот же коммит 5acc5ae: новая ветка начинается там, где вы стояли.

Вернуться на существующую ветку — та же команда, но без -c: git switch main. Git ответит Switched to branch 'main'. Есть и команда git branch имя — она создаёт ветку, но не переходит на неё. Удобнее сразу git switch -c.

В старых статьях: git checkout

В старых статьях и ответах вы встретите git checkout -b feature/projects — это то же, что git switch -c feature/projects, а git checkout main — то же, что git switch main. checkout работает, но умеет слишком много разного (и ветки, и файлы), поэтому в курсе — switch.

Спасти коммиты из detached HEAD можно веткой

Помните режим detached HEAD, когда вы смотрели старый коммит? Если вы успели там что-то закоммитить, эти коммиты не принадлежат ни одной ветке. Спасение — создать ветку прямо в этом состоянии: git switch -c experiment. Коммиты окажутся в ветке experiment, и их уже не потерять.

Уже ушли на main? Найдите хеш коммита в git reflog и создайте ветку на нём: git switch -c experiment <хеш>.

Коммиты в ветке

Вы на ветке feature/projects. Создайте в VS Code рядом с index.html новый файл projects.html — это отдельная страница проектов: та же шапка head, заголовок, две карточки-абзаца и ссылка обратно на главную.

HTML · projects.html
<!DOCTYPE html>
<html lang="ru">
<head>
  <meta charset="UTF-8">
  <title>Алекс Иванов - Мои проекты</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <h1>Мои проекты</h1>
  <p><strong>Сайт-визитка.</strong> Моя первая страница на HTML и CSS, история ведётся в Git.</p>
  <p><strong>Список дел.</strong> Маленькое приложение: добавить задачу и отметить её сделанной.</p>
  <p><a href="index.html">На главную</a></p>
</body>
</html>

Коммит в ветке делается точно так же, как раньше:

Терминал
$ git status
On branch feature/projects
Untracked files:
  (use "git add <file>..." to include in what will be committed)
	projects.html

nothing added to commit but untracked files present (use "git add" to track)
$ git add projects.html
$ git commit -m "Добавить страницу проектов"
[feature/projects 294653e] Добавить страницу проектов
 1 file changed, 14 insertions(+)
 create mode 100644 projects.html

Разбор по строкам

  • On branch feature/projects — первая строка git status всегда называет текущую ветку. Привыкайте смотреть на неё.
  • [feature/projects 294653e] — коммит попал в ветку feature/projects, его хеш 294653e (у вас будет свой).
Терминал
$ git log --oneline
294653e (HEAD -> feature/projects) Добавить страницу проектов
5acc5ae (main) Revert "Поменять цвет фона"
875cb0a Поменять цвет фона
...

Разбор по строкам

  • (HEAD -> feature/projects) — HEAD указывает на ветку feature/projects, а она — на новый коммит. Ветка передвинулась сама.
  • (main) — main осталась на 5acc5ae: ваша новая работа её не тронула.

Переключение меняет рабочую папку

Теперь самое интересное. Перейдите на main и посмотрите на файлы:

Терминал
$ git switch main
Switched to branch 'main'
$ ls
README.md
index.html
notes
style.css
$ git switch feature/projects
Switched to branch 'feature/projects'
$ ls
README.md
index.html
notes
projects.html
style.css

Разбор по строкам

  • После git switch main файла projects.html нет: в ветке main его не существует, и Git убрал его из рабочей папки.
  • Файл не удалён — он хранится в коммите 294653e. После git switch feature/projects он снова на месте.
  • notes — ваши личные черновики. Их нет в Git (они в .gitignore), поэтому Git не трогает их ни в одной ветке.

Так и работает переключение: Git приводит рабочую папку к последнему коммиту выбранной ветки.

Видим ветки в истории

Обычный git log показывает только текущую ветку. Флаг --graph рисует линии, --all берёт все ветки. Перейдите на main и выполните:

Терминал
$ git switch main
Switched to branch 'main'
$ git log --oneline --graph --all
* 294653e (feature/projects) Добавить страницу проектов
* 5acc5ae (HEAD -> main) Revert "Поменять цвет фона"
* 875cb0a Поменять цвет фона
* 746ac3d Добавить описание сайта
* 12d081f Добавить .gitignore
* 284ecf7 Исправить опечатку в заголовке
* cb00bb8 Добавить раздел «Мои проекты»
* f58d529 Добавить README
* 8c23940 Добавить стили
* 027a150 Добавить главную страницу

Разбор по строкам

  • Каждая * — коммит, новые сверху.
  • (feature/projects) у верхнего коммита — ветка ушла на коммит вперёд; (HEAD -> main) — вы на main, она на шаг позади.
  • Линия пока прямая: в main после развилки ничего не появлялось. «Вилка» на графе появится, когда коммиты будут в обеих ветках.
Схема
... --- 875cb0a --- 5acc5ae --- 294653e
                       ^             ^
                      main     feature/projects

Что на схеме: коммиты одни на всех, а ветки — просто метки, приклеенные к разным коммитам одной цепочки.

Как называть ветки

Имя ветки пишут для людей. Частая договорённость — приставка по смыслу и короткое описание после косой черты:

  • feature/… — новая возможность: feature/projects, feature/footer;
  • fix/… — исправление: fix/projects-link;
  • после косой — коротко, латиницей, строчными буквами, слова через дефис;
  • без пробелов: пробел в имени ветки Git не разрешит.
Терминал
$ git switch -c "my branch"
fatal: 'my branch' is not a valid branch name
hint: See `man git check-ref-format`
hint: Disable this message with "git config advice.refSyntax false"

Разбор по строкам

  • fatal: 'my branch' is not a valid branch name — «недопустимое имя ветки»: мешает пробел. Строки hint: подсказывают, где прочитать правила имён и как отключить подсказку.

Косая черта в feature/projects — часть имени, а не папка в проекте: никакой папки feature в portfolio не появится. Подробно о ветках — в документации git switch и git branch.

Практика у себя

Если ветку и страницу вы уже создали, пока читали, просто сверьтесь с шагами.

Шаг 1. Откройте терминал в папке проекта и убедитесь, что вы на main и всё закоммичено:

Терминал
$ cd ~/projects/portfolio
$ git status
On branch main
nothing to commit, working tree clean

Шаг 2. Создайте ветку и проверьте, что вы на ней:

Терминал
$ git switch -c feature/projects
Switched to a new branch 'feature/projects'
$ git branch
* feature/projects
  main

Шаг 3. Создайте projects.html с кодом из раздела «Коммиты в ветке». git status покажет его в Untracked files.

Шаг 4. Закоммитьте страницу:

Терминал
$ git add projects.html
$ git commit -m "Добавить страницу проектов"
[feature/projects 294653e] Добавить страницу проектов
 1 file changed, 14 insertions(+)
 create mode 100644 projects.html

Шаг 5. Перейдите на main и выполните ls — projects.html исчезнет. Вернитесь на feature/projects — появится снова.

Шаг 6. Вернитесь на main и посмотрите на граф:

Терминал
$ git switch main
Switched to branch 'main'
$ git log --oneline --graph --all
* 294653e (feature/projects) Добавить страницу проектов
* 5acc5ae (HEAD -> main) Revert "Поменять цвет фона"
* 875cb0a Поменять цвет фона
* 746ac3d Добавить описание сайта
* 12d081f Добавить .gitignore
* 284ecf7 Исправить опечатку в заголовке
* cb00bb8 Добавить раздел «Мои проекты»
* f58d529 Добавить README
* 8c23940 Добавить стили
* 027a150 Добавить главную страницу

Проверьте себя

  • git branch показывает две ветки: feature/projects и main, звёздочка у main.
  • В git log --oneline --graph --all верхний коммит «Добавить страницу проектов» помечен (feature/projects), а (HEAD -> main) стоит на «Revert "Поменять цвет фона"».
  • На main файла projects.html в папке нет, на feature/projects — есть.
  • git status на main: nothing to commit, working tree clean.

Частые ошибки

Git не даёт переключиться: would be overwritten. Вы поправили файл, не закоммитили и пытаетесь уйти в ветку, где этот файл другой:

Терминал
$ git switch main
error: Your local changes to the following files would be overwritten by checkout:
	style.css
Please commit your changes or stash them before you switch branches.
Aborting

Разбор по строкам

  • error: Your local changes ... would be overwritten by checkout — «ваши локальные изменения будут затёрты», а строкой ниже — файл, который мешает (style.css). Слово checkout — наследие старой команды, git switch пишет так же.
  • Please commit your changes or stash them ... — «закоммитьте изменения или уберите их в stash».
  • Aborting — переключение отменено, ничего не потеряно.

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

Коммит не в ту ветку. Забыли git switch -c и закоммитили новую страницу прямо в main. Пока коммит есть только у вас на компьютере, это легко поправить: создать ветку на этом коммите, вернуть main на шаг назад и перейти на новую ветку.

Терминал
$ git branch feature/projects
$ git reset --hard HEAD~1
HEAD is now at 5acc5ae Revert "Поменять цвет фона"
$ git switch feature/projects
Switched to branch 'feature/projects'

Разбор по строкам

  • git branch feature/projects — ветка запоминает текущий коммит со страницей; вы остаётесь на main.
  • git reset --hard HEAD~1 — main возвращается на коммит назад (HEAD is now at ...), а страница остаётся в новой ветке.

Осторожно с reset --hard

Перед git reset --hard убедитесь, что git status чистый: незакоммиченные правки эта команда уничтожит без возврата.

«Файл пропал». Вы открыли проект и не нашли projects.html. Скорее всего, вы на другой ветке. Первым делом — git status или git branch: какая ветка текущая. Перейдите на нужную, и файл вернётся.

Опечатка в имени ветки. git switch feature/projets ответит fatal: invalid reference: feature/projets — такой ветки нет. Посмотрите точное имя в git branch.

Что важно запомнить

  • Ветка — подвижный указатель на коммит, а не копия папки. Папка одна, Git подменяет в ней файлы.
  • HEAD указывает на текущую ветку, ветка — на свой последний коммит. Коммит двигает текущую ветку вперёд.
  • git branch — список веток, git switch -c имя — создать и перейти, git switch имя — перейти.
  • git log --oneline --graph --all показывает все ветки и где какая стоит.
  • Имена: feature/…, fix/…, латиница, без пробелов.
  • Переключаться лучше с чистым git status, иначе Git может не пустить (would be overwritten).

Страница проектов готова, но живёт только в ветке feature/projects: на главной её нет. Как перенести работу из ветки в main — слияние веток, в следующем уроке.

На следующий урок