Программирование и IT
git checkout
Исторически `git checkout` делает сразу несколько несвязанных вещей: переводит рабочую копию на другую ветку, создаёт ветку, достаёт отдельный файл из коммита. Из-за этой перегруженности в git 2.23 появились две отдельные команды — `switch` и `restore`. Разберём обе стороны: старый способ и современную замену.
В этой статье
Три работы одной команды#
Команда меняет то, на что смотрит рабочая копия. Дальше всё зависит от того,
что ей передали.
Передали имя ветки — указатель HEAD переезжает на эту ветку, а файлы в папке
проекта перерисовываются под её последний коммит. Передали хеш коммита —
файлы перерисовываются под этот коммит, но указателя ветки там нет, и ты
оказываешься в отсоединённом состоянии. Передали путь к файлу после двух тире —
ветка не меняется вообще, зато этот файл затирается версией из указанного
коммита, и твои несохранённые правки в нём пропадают без предупреждения.
Последний случай — единственное по-настоящему опасное применение. Изменения,
которых нет ни в коммите, ни в индексе, git восстановить не может: их нигде
нет. Поэтому перед откатом файла стоит либо закоммитить, либо спрятать правки
командой из статьи про git stash.
Синтаксис#
С git 2.23 те же задачи решают две узкие команды:
Разделение полезно именно тем, что switch физически не умеет трогать файлы,
а restore — переключать ветки. Промахнуться и снести работу одной опечаткой
становится труднее.
Пример: переключение и незакоммиченные правки#
## feature-search
Правка в app/views.py осталась при тебе: переключение переносит
незакоммиченные изменения на новую ветку, если они не мешают. Мешают — когда
целевая ветка меняет тот же файл. Тогда git откажется:
error: Your local changes to the following files would be overwritten by checkout:
app/views.py
Please commit your changes or stash them before you switch branches.
Aborting.
Это не ошибка, а защита: git не стал молча выбрасывать твою работу. Варианта
три — закоммитить, спрятать через git stash push, либо переключиться вместе
с правками: git switch -m other-branch попробует их перенести слиянием.
Пример: достать файл из прошлого#
Нужен старый вариант конфигурации, но история при этом остаётся нетронутой:
Файл из коммита 8a94f0c лежит теперь и в рабочей копии, и в индексе (буква
M в первой колонке). Ветка не переключалась, остальные файлы не тронуты.
Дальше это обычная правка: закоммитить или отменить.
Отсоединённый HEAD: что это и как выйти#
Переход на хеш коммита даёт предупреждение на пятнадцать строк, суть которого
в первой:
Note: switching to '9c1f8ab'.
You are in 'detached HEAD' state.
Ты смотришь на конкретный коммит, и никакая ветка сюда не указывает. Смотреть
и запускать код так можно свободно. Опасность одна: коммиты, сделанные в этом
состоянии, ни к чему не привязаны. Стоит переключиться на ветку — и добраться
до них можно будет только через git reflog.
Выходов два. Если ничего не коммитил — просто вернись: git switch -.
Если коммитил и результат нужен — закрепи его веткой прямо на месте:
Теперь коммиты принадлежат ветке experiment и никуда не денутся.
Частые ошибки#
Забыли два тире. git checkout config при наличии ветки config
переключит ветку, а не вернёт файл. Два тире говорят git: дальше пути, не
ссылки. Команда git restore от этой двусмысленности избавлена.
Ждали, что откат файла можно отменить. Нельзя. git checkout -- файл и
git restore файл уничтожают несохранённые правки безвозвратно — в отличие от
операций над коммитами, которые почти всегда возвращает журнал ссылок. Разница
между «потерять коммит» и «потерять несохранённое» подробно разобрана в статье
про git reset.
Ветка не находится. error: pathspec 'feature-x' did not match any file(s) known to git обычно значит, что ветка есть только на сервере. Сделай
git fetch origin, после чего git switch feature-x создаст локальную ветку,
следящую за серверной, автоматически.
План по этапам
- Посмотреть, где ты сейчасgit status -sb: текущая ветка и незакоммиченные файлы.
- Решить судьбу правокЗакоммитить, спрятать в stash или убедиться, что они не мешают переключению.
- Переключитьсяgit switch <ветка> или git checkout <ветка>; новой ветке — флаг -c или -b.
- Проверить, что переключилисьgit branch --show-current должен вывести ожидаемое имя.
- Восстановить файл, если нужноgit restore <файл> или git checkout <коммит> -- <файл>; помнить, что несохранённое в этом файле теряется.
Начать изучать эту тему у себя
План ляжет в твой репозиторий: отмечай этапы, веди конспект — история изменений покажет, как ты продвинулся.
Проверь себя
1.Какая команда создаст ветку hotfix и сразу перейдёт на неё?
2.Ты правил файл notes.md и выполнили git restore notes.md. Что стало с правками?
3.Ты на коммите 9c1f8ab в состоянии detached HEAD и сделал два коммита. Как их сохранить?
Источники
-
Справка git switchСовременная команда переключения ветокбесплатно
-
Справка git restoreВосстановление файлов без риска задеть веткибесплатно
-
Справка git checkoutПолный список режимов старой командыбесплатно
-
Pro Git, русское изданиеГлавы о ветвлении — что происходит с указателями при переключениибесплатно
Было полезно?