- Андрей Куманяев/
- Git: руководства и команды/
- git reset: полное руководство по отмене изменений и коммитов/
git reset: полное руководство по отмене изменений и коммитов
git reset — мощная команда для отмены изменений и переноса HEAD на другой коммит. Это один из важнейших инструментов, когда что-то пошло не так. Однако команда может быть опасной: в режиме --hard изменения удаляются навсегда. Разберём три режима работы, сценарии применения и более безопасные альтернативы.
Что делает git reset #
git reset перемещает указатель ветки (и HEAD) на указанный коммит. В зависимости от режима по-разному обращается с индексом и рабочей директорией.
Три области, на которые влияет reset:
- HEAD и ветка — указатель всегда перемещается
- Индекс (staging area) — зависит от режима
- Рабочая директория — зависит от режима
Три режима: soft, mixed, hard #
–soft: только переместить HEAD #
git reset --soft HEAD~1
- HEAD: перемещается на предыдущий коммит
- Индекс: не изменяется (изменения остаются staged)
- Рабочая директория: не изменяется
Используется когда: хотите «расклеить» коммит обратно в staging area. Например, закоммитили слишком рано — все изменения вернутся в индекс готовыми для нового коммита.
git log --oneline -3
# c3d4e5f Незаконченная работа
# b2c3d4e Previous feature
# a1b2c3d Initial commit
git reset --soft HEAD~1
git log --oneline -2
# b2c3d4e Previous feature
# a1b2c3d Initial commit
git status
# Changes to be committed: ← изменения в индексе
# modified: app.js
–mixed: переместить HEAD и сбросить индекс (по умолчанию) #
git reset HEAD~1
# или явно:
git reset --mixed HEAD~1
- HEAD: перемещается
- Индекс: сбрасывается (изменения выходят из staged)
- Рабочая директория: не изменяется
Это режим по умолчанию. Используется когда: хотите отменить коммит и сам git add — но сохранить изменения в файлах.
git reset HEAD~1
git status
# Changes not staged for commit: ← изменения есть, но не в индексе
# modified: app.js
# Файлы в рабочей директории сохранены
cat app.js # Изменения на месте
–hard: удалить всё #
git reset --hard HEAD~1
- HEAD: перемещается
- Индекс: сбрасывается
- Рабочая директория: файлы возвращаются к состоянию указанного коммита
Осторожно: незакоммиченные изменения в рабочей директории удаляются безвозвратно.
git reset --hard HEAD~1
git status
# nothing to commit, working tree clean
# Изменения из отменённого коммита исчезли
Наглядное сравнение режимов #
Команда HEAD Индекс Раб.директория
git reset --soft HEAD~1 ↑ - -
git reset --mixed HEAD~1 ↑ ↑ -
git reset --hard HEAD~1 ↑ ↑ ↑
↑ = изменяется/сбрасывается
- = остаётся без изменений
Практические сценарии #
Отменить последний коммит (сохранить изменения) #
# Хотите переписать коммит или разделить на несколько
git reset HEAD~1 # mixed: изменения в рабочей директории
git reset --soft HEAD~1 # soft: изменения уже в индексе
Отменить несколько коммитов #
# Отменить последние 3 коммита
git reset HEAD~3
# Отменить до конкретного коммита
git reset --soft a1b2c3d
git reset --mixed a1b2c3d
git reset --hard a1b2c3d
Вернуть рабочую директорию в чистое состояние #
git reset --hard HEAD
# Все незакоммиченные изменения удалены
Убрать файл из staging area (unstage) #
git add . # Добавили всё
git reset app.js # Убрать app.js из индекса
# Современный способ:
git restore --staged app.js
Reset индекса полностью #
git reset # Убрать все файлы из staging (mixed HEAD)
Восстановление после неправильного reset #
Если вы случайно сделали git reset --hard и потеряли нужные коммиты — не паникуйте. Git хранит историю перемещения HEAD в reflog:
git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# b2c3d4e HEAD@{1}: commit: Нужный коммит
# c3d4e5f HEAD@{2}: commit: Предыдущий коммит
# Восстановить на нужный коммит
git reset --hard HEAD@{1}
# или
git reset --hard b2c3d4e
reflog хранит историю до 90 дней по умолчанию.
Альтернативы: git restore #
В Git 2.23 появились специализированные команды, заменяющие часть функций git reset:
git restore — отмена изменений в файлах #
# Отменить изменения в рабочей директории (было: git checkout -- файл)
git restore app.js
# Убрать файл из staging area (было: git reset HEAD файл)
git restore --staged app.js
# Убрать из staged И отменить изменения в рабочей директории
git restore --staged --worktree app.js
git restore предпочтительнее git reset для работы с отдельными файлами — синтаксис понятнее.
git revert: безопасная альтернатива для опубликованных коммитов #
Если коммит уже запушен в общую ветку, git reset опасен — вы переписываете историю, которую уже скачали другие. В этом случае используйте git revert:
# Создать новый коммит, отменяющий указанный
git revert a1b2c3d
# Отменить последний коммит
git revert HEAD
git revert не переписывает историю — он добавляет новый коммит, который «обращает» изменения. Это безопасно для публичных веток.
reset: A ← B ← C ← D → A ← B ← C (D исчез)
revert: A ← B ← C ← D → A ← B ← C ← D ← D'
Полная шпаргалка #
# Мягкая отмена коммита (изменения в индексе)
git reset --soft HEAD~1
# Стандартная отмена коммита (изменения в рабочей директории)
git reset HEAD~1
git reset --mixed HEAD~1
# Жёсткая отмена коммита (изменения удалены)
git reset --hard HEAD~1
# Отмена до конкретного коммита
git reset --hard a1b2c3d
# Убрать файл из staging area
git restore --staged файл.js
git reset файл.js # Устаревший синтаксис
# Отменить изменения в файле
git restore файл.js
# Восстановить потерянное через reflog
git reflog
git reset --hard HEAD@{N}
# Безопасная отмена опубликованного коммита
git revert HEAD
git revert a1b2c3d
Часто задаваемые вопросы #
Какая разница между --soft, --mixed и --hard? --soft перемещает только HEAD, изменения остаются в индексе. --mixed (по умолчанию) перемещает HEAD и сбрасывает индекс, изменения остаются в файлах. --hard перемещает всё и удаляет изменения в рабочей директории.
Как восстановить коммит после неправильного --hard reset? Используйте git reflog чтобы найти хеш нужного коммита, затем git reset --hard <хеш>. Git хранит reflog 90 дней.
Безопасен ли reset для опубликованных коммитов? Нет. Если коммиты уже запушены и другие могли их скачать — используйте git revert вместо git reset. Иначе вы переписываете общую историю, что вызовет проблемы у коллег.
Когда использовать reset, когда revert? Reset — для локальных коммитов, которые ещё не запушены. Revert — для уже опубликованных коммитов в общих ветках.
Как отменить изменения одного файла? git restore файл.js отменяет изменения в рабочей директории. git restore --staged файл.js убирает файл из staging area.
Заключение #
git reset — мощный инструмент, но требует осторожности. Главное правило: не используйте --hard для опубликованных коммитов — это переписывает историю и создаёт проблемы для всей команды. Для таких случаев есть git revert.
Для повседневной работы запомните:
git reset --soft HEAD~1— вернуть в indexed-состояниеgit reset HEAD~1— вернуть в рабочую директориюgit restore --staged файл— убрать файл из staginggit restore файл— отменить изменения в файле
И всегда имейте в виду git reflog — он поможет восстановиться из практически любой ситуации.