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

Создание и переключение веток

git switch перемещает HEAD между ветками, а git switch -c создаёт ветку за один шаг. git branch создаёт без переключения, -d/-D удаляют, -m переименовывает, -vv выводит со связью. Незакоммиченные изменения могут заблокировать переключение; checkout коммита отсоединяет HEAD.

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

Теперь ты знаешь, что ветка — это указатель, а HEAD называет текущую. Повседневная работа — двигать этот указатель: создать новую ветку под фичу, перепрыгнуть на неё, вернуться на main, выбросить ветку, когда закончил. Годами единственным глаголом для всего этого был перегруженный git checkout, который ещё и восстанавливал файлы — частый источник «стоп, я переключил ветку или выбросил свою работу?». Git 2.23 разделил его на два более ясных глагола.

К концу этого урока ты сможешь создавать, переключать, выводить, переименовывать и удалять ветки современными командами и узнавать старые формы checkout, которые ты будешь видеть повсюду.

Цель

После этого урока ты сможешь создавать и переключать ветки через git switch / git switch -c, создавать без переключения через git branch, удалять через -d против -D, переименовывать через -m, выводить через -vv, сопоставлять это со старыми формами git checkout и объяснять, почему незакоммиченное изменение может заблокировать переключение.

1

git switch перемещает HEAD на существующую ветку; git switch -c создаёт новую ветку и переходит на неё за один шаг. Это современный, специально созданный глагол (git 2.23+):

git switch main              # перейти на существующую ветку
git switch -c feature-login  # создать 'feature-login' на текущем коммите, затем переключиться

-c — это «create» (создать). Новая ветка начинает указывать туда, где сейчас HEAD, поэтому git switch -c — повседневная команда «начать фичу от текущего состояния». После неё HEAD → feature-login → <текущий коммит>.

2

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

git branch hotfix      # создать 'hotfix' на текущем коммите; HEAD НЕ двигается
git branch             # вывести локальные ветки; * отмечает текущую
git branch -vv         # вывести с вершиной каждой ветки и её upstream (отслеживаемой) веткой

git branch сам по себе — это глагол создать-или-вывести; он никогда не меняет, на какой ветке ты находишься. -vv — это вывод, к которому тянешься, когда нужно увидеть, что каждая ветка отслеживает на удалённом сервере.

3

Удаляй через -d (безопасно) или -D (принудительно); переименовывай через -m. Уборка указателей:

git branch -d feature-login   # удалить, но ОТКАЗАТЬ, если есть не слитые коммиты
git branch -D feature-login   # удалить принудительно, даже если не слита (можешь потерять коммиты)
git branch -m old-name new-name   # переименовать ветку

-d — это страховочное ограждение: оно удаляет только ветку, чьи коммиты уже достижимы откуда-то ещё, так что ты не осиротишь не слитую работу случайно. -D отменяет эту проверку — тянись к нему только когда действительно хочешь выбросить уникальные коммиты ветки.

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

Зачем разделять checkout на switch и restore? Старый git checkout делал две не связанные работы: перемещал HEAD между ветками и перезаписывал файлы в твоём рабочем дереве из коммита. Это перекрытие вызывало реальные аварии — git checkout файл молча отбрасывал незакоммиченные правки этого файла, тогда как git checkout ветка переключал ветку, и опечатка могла превратить одно в другое. Git 2.23 ввёл git switch (сменить ветку) и git restore (сменить файлы), чтобы каждый глагол делал ровно одно дело. checkout всё ещё работает и встречается во всех туториалах, но разделённые глаголы безопаснее.

4

Старые формы git checkout всё ещё встречаются повсюду — знай соответствие. Для работы с ветками они эквивалентны:

git checkout main             # == git switch main
git checkout -b feature       # == git switch -c feature
git checkout <commit-id>      # отсоединяет HEAD на этот коммит (без ветки)

Последняя — это как ты попадаешь в отсоединённый HEAD: checkout коммита (или тега) вместо ветки указывает HEAD прямо на коммит. Git печатает ясное предупреждение и говорит создать ветку, если хочешь сохранить любые коммиты, сделанные там. Чтобы выйти, просто переключись назад на настоящую ветку: git switch main. Современный эквивалент для осмотра коммита — git switch --detach <commit-id>.

5

Незакоммиченные изменения могут заблокировать переключение — и это фича. Если у тебя есть локальные правки, которые целевая ветка перезаписала бы, git отказывается вместо того, чтобы молча их затереть:

git switch other-branch
# error: Your local changes to the following files would be
# overwritten by checkout: app.js
# Please commit your changes or stash them before you switch.

Твои варианты: закоммитить их, отложить через stash (git stash, отложить на потом) или отбросить. Git защищает работу, которую не может безопасно перенести через переключение. Если правки не конфликтуют с различиями между ветками, git переносит их с собой, и переключение проходит успешно.

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

Фича от старта до уборки.

Ты на main и хочешь собрать форму логина, не трогая main:

git switch -c feature-login   # создать + переключить; HEAD → feature-login → (коммит main)
# ...правишь файлы...
git commit -m "Add login form"   # feature-login продвигается; main не тронут

Ты заканчиваешь, сливаешь это в main, затем прибираешься:

git switch main               # HEAD → main
git branch -d feature-login   # безопасное удаление; успех, потому что она слита

А теперь представь, что ты вместо этого бросил фичу, не слив её, и пробуешь то же удаление:

git branch -d feature-login
# error: The branch 'feature-login' is not fully merged.

Git отказывается, потому что -d не осиротит не слитые коммиты. Если ты правда хочешь её убрать, git branch -D feature-login сделает это принудительно — и те коммиты станут недостижимыми. Эта разница в одну букву, -d против -D, — граница между безопасной уборкой и выбрасыванием работы.

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

Классическая ловушка: запустить git checkout <commit-id>, чтобы «посмотреть» старую версию, закоммитить там быстрый фикс, затем переключиться назад — и обнаружить, что фикс исчез. Те коммиты были сделаны в отсоединённом HEAD, не привязаны ни к какой ветке, поэтому переключение их осиротило. Лечится созданием ветки перед уходом: git switch -c rescue-fix превращает отсоединённые коммиты в настоящую ветку. Если ты уже ушёл, git reflog ещё какое-то время может найти идентификатор осиротевшего коммита.

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

В чём разница между git branch -d и git branch -D?

Итог

git switch <ветка> перемещает HEAD на существующую ветку; git switch -c <имя> создаёт ветку на текущем коммите и переключается на неё за один шаг. git branch <имя> создаёт без переключения, git branch -vv выводит ветки с их вершинами и upstream-ветками, -d безопасно удаляет (отказывая не слитым веткам), -D удаляет принудительно, а -m переименовывает. Это соответствует старым git checkout / git checkout -b, а checkout коммита приземляет тебя в отсоединённый HEAD. Незакоммиченные изменения, которые переключение перезаписало бы, блокируют его намеренно — сначала закоммить или отложи через stash. Дальше ты возьмёшь две разошедшиеся ветки и соединишь их обратно через git merge.

Практика

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

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

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

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

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

Trademarks belong to their respective owners. Editorial reference only.