Инструкция

git checkout, switch и restore: что когда использовать

Обновлено: · Skillaria.Top

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

Почему у git checkout две роли

git checkout исторически делает две принципиально разные операции. С именем ветки он переключает HEAD и обновляет рабочую папку. С путём к файлу он берёт версию файла из индекса или коммита и молча перезаписывает ваши изменения. Одна и та же команда то безопасно переходит между ветками, то необратимо выбрасывает несохранённую работу.

Из-за этого в Git 2.23 появились две отдельные команды: git switch — для веток, git restore — для файлов. Checkout никто не удалял, он полностью рабочий, но в новом коде, документации и подсказках самого Git используются switch и restore. Если вы только учитесь, начинайте с них; checkout знать всё равно нужно — он встречается в инструкциях, скриптах и на собеседованиях.

Соответствие команд

Задачаgit checkoutНовая команда
Переключиться на веткуgit checkout maingit switch main
Создать ветку и перейтиgit checkout -b featuregit switch -c feature
Создать или сбросить веткуgit checkout -B featuregit switch -C feature
Вернуться на прошлую веткуgit checkout -git switch -
Перейти на коммит (detached HEAD)git checkout 3f2a1c9git switch --detach 3f2a1c9
Отменить изменения в файлеgit checkout -- app.jsgit restore app.js
Убрать файл из индексаgit reset HEAD app.jsgit restore --staged app.js
Взять файл из другой ветки или коммитаgit checkout main -- app.jsgit restore --source=main --staged --worktree app.js
Отменить все изменения в папкеgit checkout -- .git restore .

Обратите внимание на -- в командах checkout. Это разделитель «дальше идут пути». Он защищает от двусмысленности, когда файл и ветка называются одинаково. В restore такой проблемы нет, потому что команда работает только с файлами.

git checkout для веток

git checkout feature/login        # переключиться
git checkout -b feature/login     # создать от текущего коммита и переключиться
git checkout -b hotfix origin/main   # создать от удалённой ветки
git checkout -t origin/feature/x  # локальная ветка, отслеживающая удалённую

Если локальной ветки нет, но на сервере есть ветка с таким именем, git checkout feature/x (как и git switch feature/x) сам создаст локальную ветку и настроит отслеживание. Перед этим нужен git fetch, иначе Git не знает о новой удалённой ветке.

Переключение не теряет незакоммиченные изменения: они переносятся в другую ветку, если не конфликтуют с ней. При конфликте Git откажет и предложит закоммитить или спрятать изменения через git stash. Флаг -f (--force) переключит ветку, выбросив локальные правки, — это уже опасная операция.

git switch: только ветки

Switch повторяет ветковую часть checkout, но с более строгими правилами. Главное отличие: он не переходит на коммит или тег без явного --detach. Команда git switch v1.0 выдаст ошибку вместо незаметного перехода в detached HEAD, поэтому случайно оказаться «вне ветки» труднее.

git switch main
git switch -c feature/cart
git switch -c feature/cart origin/main
git switch --detach v1.0
git switch -              # предыдущая ветка
git switch -m main        # перенести правки с трёхсторонним слиянием

git restore: кнопка отмены для файлов

Restore возвращает файлы к сохранённому состоянию и никак не трогает историю коммитов. Чтобы пользоваться им уверенно, нужно помнить три области Git: рабочую папку (что вы видите в редакторе), индекс (что подготовлено через git add) и коммиты.

Как отменить изменения в файле до git add

git restore app.js         # вернуть версию из индекса
git restore src/           # все файлы в папке
git restore .              # все изменённые файлы проекта

Без флагов restore восстанавливает рабочую папку из индекса. Если файл не добавлялся в индекс после последнего коммита, это то же самое, что версия из последнего коммита. Изменения исчезают без следа, в корзину они не попадают, поэтому перед git restore . взгляните на git diff.

Как убрать файл из индекса после git add

git restore --staged app.js

Файл перестаёт быть подготовленным к коммиту, но ваши правки в нём остаются. Это самая безопасная форма restore: ничего не теряется. Именно эту команду подсказывает git status в разделе «Changes to be committed».

Как отменить всё: и в индексе, и в файле

git restore --staged --worktree app.js
# короткая форма
git restore -SW app.js

Как вернуть файл из другого коммита или ветки

git restore --source=HEAD~2 app.js          # версия двухкоммитной давности
git restore --source=main config.yml        # версия из ветки main
git restore --source=3f2a1c9 -- docs/       # целая папка из коммита

По умолчанию с --source меняется только рабочая папка. Добавьте --staged, если хотите сразу подготовить изменение к коммиту. Старый вариант git checkout main -- app.js всегда меняет и индекс, и рабочую папку.

Как восстановить удалённый файл

git restore deleted.txt                          # удалён, но ещё не закоммичено
git restore --source=HEAD~1 deleted.txt          # удаление уже закоммичено

Если неизвестно, в каком коммите файл удалили, найдите его: git log --oneline -- deleted.txt. Последний коммит в списке — тот, где файл удалён, восстанавливать нужно из его родителя: git restore --source=<хеш>~1 deleted.txt.

restore, reset и revert: не путать

Все три команды «отменяют», но на разной глубине:

  • restore — работает с файлами в рабочей папке и индексе, историю не меняет. Безопасен для команды.
  • reset — двигает указатель ветки назад, переписывая историю. --soft оставляет изменения в индексе, --mixed (по умолчанию) — в рабочей папке, --hard удаляет их. Для уже отправленных коммитов в общих ветках опасен.
  • revert — создаёт новый коммит, обратный указанному. История не переписывается, поэтому это правильный способ отменить коммит, который уже на сервере.

Простое правило: изменения ещё не закоммичены — restore; коммит только локальный — reset; коммит уже у коллег — revert.

Detached HEAD после checkout

Выполнив git checkout 3f2a1c9 или git checkout v1.0, вы увидите длинное предупреждение «You are in 'detached HEAD' state». HEAD теперь указывает на коммит, а не на ветку. Это удобно, чтобы посмотреть старую версию или запустить тесты на ней.

Коммитить в этом состоянии можно, но новые коммиты ни на одну ветку не попадут. Если вы что-то изменили и хотите сохранить:

git switch -c fix-for-v1

Если просто смотрели — вернитесь: git switch - или git switch main. Если ушли, забыв создать ветку, коммиты всё ещё доступны через git reflog: найдите хеш и выполните git branch rescue <хеш>.

Типичные ошибки

error: pathspec 'feature' did not match any file(s) known to git

Git не нашёл ни ветки, ни файла с таким именем. Обычно ветка есть только на сервере, а fetch не делался. Выполните git fetch и повторите. Проверьте и написание: имена веток чувствительны к регистру.

Случайно выбросил изменения через checkout -- или restore

Незакоммиченные правки, которых не было в индексе, Git не хранит, и вернуть их средствами Git нельзя. Остаётся локальная история редактора или IDE. Если же файл был добавлен через git add, его содержимое лежит в базе как «висящий» объект и находится через git fsck --lost-found.

Файл и ветка с одинаковым именем

git checkout test при наличии ветки test и папки test выдаст предупреждение о двусмысленности. Используйте git switch test для ветки и git restore test (или git checkout -- test) для файлов.

Рабочие сценарии на каждый день

Несколько ситуаций, которые встречаются постоянно, и правильная команда для каждой:

  • Начали править файл и поняли, что пошли не туда, — git restore файл.
  • Добавили в индекс лишний файл перед коммитом — git restore --staged файл.
  • Нужно срочно переключиться на другую задачу посреди работы — git stash, затем git switch ветка; вернувшись — git switch - и git stash pop.
  • Хотите взять из соседней ветки один файл, не сливая ветку целиком, — git restore --source=feature/x --staged --worktree путь.
  • Нужно проверить, работал ли баг в прошлой версии, — git switch --detach v1.0, проверка, затем git switch -.
  • Хотите откатить только часть изменений в файле — git restore -p файл: Git покажет каждый фрагмент и спросит, отменять ли его.

Интерактивный режим -p (--patch) особенно полезен: он есть и у checkout, и у restore, и позволяет выбросить отладочный вывод, сохранив полезные правки в том же файле.

Как проверить результат перед отменой

Restore и checkout с путями выбрасывают изменения без подтверждения, поэтому полезно сначала посмотреть, что именно пропадёт. git diff покажет правки в рабочей папке относительно индекса, git diff --staged — подготовленное к коммиту, git diff main -- app.js — чем файл отличается от версии в другой ветке. Если сомневаетесь, сохраните текущее состояние через git stash: из него изменения всегда можно вернуть, в отличие от restore.

Итог

git checkout совмещает переключение веток и восстановление файлов, и именно это делает его опасным. Для веток используйте git switch, для файлов — git restore: одна команда меняет только положение HEAD, другая — только содержимое файлов. Ветки, restore, reset и revert с хорошими и плохими сценариями разобраны на практике в курсе по Git.

Частые вопросы

Устарел ли git checkout?

Нет, он не объявлен устаревшим и продолжит работать. Просто для повседневной работы рекомендуют более узкие и безопасные git switch и git restore.

С какой версии Git есть switch и restore?

Обе команды появились в Git 2.23 (2019 год). Проверить версию можно командой git --version.

Можно ли отменить git restore?

Если восстанавливалась рабочая папка, выброшенные правки Git не сохранил, и отменить нельзя. git restore --staged безопасен: правки остаются в файле, их достаточно снова добавить через git add.

Как переключиться на ветку коллеги?

Выполните git fetch, затем git switch имя-ветки: Git создаст локальную ветку, связанную с origin/имя-ветки.

Чем git checkout . отличается от git reset --hard?

git checkout . (или git restore .) возвращает изменённые файлы к версии из индекса, не трогая индекс и историю. git reset --hard сбрасывает и индекс, и рабочую папку к коммиту, а с аргументом-коммитом ещё и двигает ветку.

Разберите тему на видео

Эта тема подробно разобрана с практикой в курсе «Git с нуля до уверенного разработчика».

Перейти к курсу