restore, reset и revert: три способа отмены

Самая частая путаница в git: разбираем три команды отмены и раз навсегда запоминаем, какая для чего.

Коротко: restore отменяет изменения в файлах, reset двигает указатель ветки, revert создаёт обратный коммит.

Почему это путают

Все три команды «что-то отменяют», но работают на разных уровнях и с разными последствиями. Разберём каждую по отдельности, а в конце сведём в таблицу.

git restore — откатить файлы

git restore работает с содержимым файлов, не трогая историю. Два главных сценария:

git restore file.py            # выбросить изменения в файле (вернуть как в последнем коммите)
git restore --staged file.py   # убрать файл из индекса (но правки в файле сохранить)

Первый вариант безвозвратно теряет несохранённые правки в файле — будьте осторожны. Второй просто выводит файл из staging, ничего не удаляя.

git reset — сдвинуть указатель ветки

git reset перемещает указатель текущей ветки на другой коммит, фактически «отматывая» историю назад. У него три режима, отличающихся тем, что происходит с индексом и рабочей директорией:

РежимИсторияИндексФайлы
--softоткатсохранёнсохранены
--mixed (по умолч.)откатсброшенсохранены
--hardоткатсброшенудалены

Например, отменить последний коммит, но оставить его изменения в рабочей директории:

git reset --soft HEAD~1

А вот git reset --hard уничтожает изменения безвозвратно — это самая опасная команда в этом уроке. Используйте её, только если точно понимаете, что теряете.

git revert — безопасная отмена опубликованного

git revert не стирает историю, а создаёт новый коммит, отменяющий изменения указанного коммита. История растёт вперёд, ничего не переписывается.

git revert a1b2c3d

Вывод:

[main e4f5g6h] Revert "Добавить экспериментальный модуль"
 1 file changed, 40 deletions(-)

Главное правило выбора

Ключевой критерий — опубликован ли коммит (запушен ли он, видят ли его другие):

Хочу...Команда
выбросить правки в файлеgit restore file
убрать файл из индексаgit restore --staged file
отменить локальный (не запушенный) коммитgit reset
отменить уже опубликованный коммитgit revert

Никогда не используйте git reset для опубликованных коммитов — он переписывает историю и сломает её у коллег. Для этого есть revert.

Спасительный git reflog

Даже если вы случайно сделали git reset --hard и «потеряли» коммиты, чаще всего их можно вернуть. Git ведёт журнал перемещений HEADgit reflog. В нём видны все состояния, где вы недавно были, с их хешами. Найдя нужный хеш, вы возвращаетесь к нему командой reset. Поэтому, прежде чем паниковать из-за «потерянной» работы, всегда загляните в reflog — git редко выбрасывает что-то совсем безвозвратно.

git reflog
git reset --hard a1b2c3d   # вернуться к найденному состоянию

Сводка одной строкой

Запомните мнемонику: restore — про файлы, reset — про ветку, revert — про новый коммит-отмену. И главный предохранитель: всё, что уже опубликовано и видно другим, отменяют только через revert.

Итог

  • restore — про файлы и индекс, историю не трогает.
  • reset двигает указатель ветки; --hard опасен (удаляет изменения), только локально.
  • revert создаёт обратный коммит — безопасный способ отменить опубликованное.
Проверьте себя
1. Какую команду использовать, чтобы отменить уже опубликованный (запушенный) коммит?
Agit reset --hard
Bgit revert
Cgit restore
Dgit stash
2. Что делает git reset --hard HEAD~1?
AОтменяет коммит, сохранив изменения в файлах
BОтменяет коммит и безвозвратно удаляет его изменения из файлов
CСоздаёт обратный коммит
DУбирает файл из индекса
3. Чем занимается git restore --staged file.py?
AУдаляет файл с диска
BУбирает файл из индекса, сохраняя правки в самом файле
CСоздаёт коммит
DПереписывает историю ветки
Поддержать проект