Отмена изменений в Git: Reset, Restore, Revert — объяснение
Поймите, как работают git restore, reset и revert, чтобы снимать файлы с индексации, отменять локальные правки, откатывать коммиты и избегать перезаписи общей истории.
Отмена изменений в Git: Reset, Restore, Revert — объяснение
Отмена изменений в Git безопасна, если вы знаете, какой слой изменяете: рабочую директорию, область подготовки (staging area) или историю коммитов. Основные команды — git restore, git reset и git revert — решают разные задачи.
Главное правило простое: используйте restore для файлов, reset для локальных изменений истории и revert для отмены коммитов, которые уже могли быть у других.
Понимание ключевых понятий
Запомните эти области:
- Рабочая директория: файлы, которые вы редактируете.
- Область подготовки (индекс): изменения, выбранные для следующего коммита.
- История коммитов: уже записанные коммиты.
HEAD: текущий коммит, на который указывает ваша ветка.
Перед любой отменой выполните git status. Он покажет, какие изменения не проиндексированы, проиндексированы или уже закоммичены.
git restore: для отмены изменений в рабочей директории и области подготовки
Используйте git restore, когда нужно изменить файлы в рабочей директории или области подготовки без перемещения указателя ветки.
Снятие файлов с индексации
Если вы случайно проиндексировали файл, снимите его с помощью --staged:
git restore --staged <файл>
Чтобы снять всё:
git restore --staged .
Ваши правки в файлах останутся в рабочей директории. Они просто будут исключены из следующего коммита.
Отмена изменений в рабочей директории
Чтобы отбросить неиндексированные правки в одном файле:
git restore <файл>
Это приведёт копию в рабочей директории к состоянию индекса. Если файл не проиндексирован, обычно это означает возврат к HEAD. Сначала выполните git diff, так как эта команда удаляет локальные правки.
Чтобы отбросить как проиндексированные, так и неиндексированные изменения для файла и восстановить его из HEAD:
git restore --source=HEAD --staged --worktree <файл>
Восстановление файла из определённого коммита
Вы также можете вернуть один файл из старого коммита:
git restore --source=<коммит> -- путь/к/файлу
Это изменит файл в вашей рабочей директории. Если старая версия нужна в будущем, сделайте коммит.
git reset: переписывание истории
Используйте git reset, когда нужно переместить указатель текущей ветки. В зависимости от режима он также может изменить область подготовки и рабочую директорию.
Понимание режимов (--soft, --mixed, --hard)
Три основных режима:
git reset --soft HEAD^
Перемещает HEAD на один коммит назад и оставляет изменения отменённого коммита проиндексированными.
git reset --mixed HEAD^
Перемещает HEAD на один коммит назад и оставляет изменения отменённого коммита неиндексированными. --mixed используется по умолчанию, поэтому git reset HEAD^ делает то же самое.
git reset --hard HEAD^
Перемещает HEAD на один коммит назад и удаляет соответствующие изменения из области подготовки и рабочей директории. Это разрушительное действие. Не выполняйте его бездумно.
Полезные шаблоны reset:
git reset --soft HEAD^ # переделать последний локальный коммит, оставить изменения проиндексированными
git reset HEAD^ # отменить последний локальный коммит, оставить изменения неиндексированными
git reset # снять все проиндексированные изменения
git reset --hard origin/main # отбросить локальные изменения и синхронизироваться с origin/main
Сброс к старому коммиту
Чтобы переместить ветку на два коммита назад, сохранив изменения в рабочей директории:
git reset --mixed HEAD~2
Сбрасывайте только локальные коммиты или те, которые ваша команда согласилась переписать. Если коммиты уже находятся в общей ветке, предпочтительнее git revert.
git revert: создание нового коммита для отмены изменений
git revert создаёт новый коммит, который применяет обратные изменения к предыдущему коммиту. Он не удаляет и не перемещает исходный коммит, поэтому безопасен для общих веток.
Отмена одного коммита:
git revert <хэш-коммита>
Отмена диапазона:
git revert HEAD~3..HEAD
Если возникли конфликты, разрешите их, проиндексируйте файлы и продолжите:
git add <исправленные-файлы>
git revert --continue
Отмена merge-коммита требует особой осторожности, так как Git должен знать, какой родитель считать основной линией:
git revert -m 1 <merge-коммит>
Делайте это только если понимаете, что привнесло слияние. Для продакшен-веток перед отменой слияний запрашивайте ревью.
Выбор правильной команды
Используйте эту краткую памятку:
- Снять файл с индексации:
git restore --staged <файл>. - Отбросить неиндексированные правки в файле:
git restore <файл>. - Отменить последний локальный коммит и оставить изменения проиндексированными:
git reset --soft HEAD^. - Отменить последний локальный коммит и оставить изменения неиндексированными:
git reset HEAD^. - Разрушительно отбросить локальные изменения и коммиты:
git reset --hard <коммит>. - Безопасно отменить отправленный коммит:
git revert <хэш-коммита>.
Практический вывод
Перед любой отменой выполните git status и решите, что именно вы меняете. Используйте restore для очистки на уровне файлов, reset для локальных неотправленных коммитов и revert для общей истории. Если команда содержит --hard, остановитесь и сначала проверьте git diff.