↓Перейти к содержанию
  1. Git: руководства и команды/

git reset: полное руководство по отмене изменений и коммитов

·5 минут·

git reset — мощная команда для отмены изменений и переноса HEAD на другой коммит. Это один из важнейших инструментов, когда что-то пошло не так. Однако команда может быть опасной: в режиме --hard изменения удаляются навсегда. Разберём три режима работы, сценарии применения и более безопасные альтернативы.

Что делает git reset #

git reset перемещает указатель ветки (и HEAD) на указанный коммит. В зависимости от режима по-разному обращается с индексом и рабочей директорией.

Три области, на которые влияет reset:

  1. HEAD и ветка — указатель всегда перемещается
  2. Индекс (staging area) — зависит от режима
  3. Рабочая директория — зависит от режима

Три режима: 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 файл — убрать файл из staging
  • git restore файл — отменить изменения в файле

И всегда имейте в виду git reflog — он поможет восстановиться из практически любой ситуации.

По теме #