Как откатить коммит в Git: reset, revert, checkout

Закоммитил не то? Разбираем git revert, git reset и git restore — когда использовать каждый инструмент, таблица сравнения трёх режимов reset и три практических сценария.

Обложка: Как откатить коммит в Git: reset, revert, checkout

Каждый разработчик рано или поздно делает коммит, который нужно отменить. Закоммитил не ту ветку, запушил секрет, сломал рабочий код — ситуации разные, но вопрос один: как это исправить? В Git есть три основных инструмента для отмены изменений: git revert, git reset и git restore. Разберём, когда использовать каждый из них и чем они отличаются.

Ключевые выводы

git revert создаёт новый коммит-отмену, безопасен после push в общую ветку

git reset переносит указатель HEAD назад; бывает трёх видов: --soft, --mixed, --hard

git restore / git checkout -- file отменяет изменения в рабочей директории или убирает файл из staging area

— Правило: если уже запушил — только revert; если локально — reset

git revert: безопасная отмена после push

git revert — самый безопасный способ отменить коммит. Он не переписывает историю, а создаёт новый коммит, который применяет обратные изменения. Именно поэтому revert подходит для публичных веток: коллеги, которые уже получили ваши изменения через pull, не столкнутся с конфликтами.

			# Отменить последний коммит
git revert HEAD

# Отменить конкретный коммит по хешу
git revert a1b2c3d

# Отменить без открытия редактора сообщения
git revert HEAD --no-edit
		

После выполнения команды Git откроет редактор для сообщения нового коммита — по умолчанию там будет что-то вроде Revert "Добавил новую фичу". Флаг --no-edit пропускает этот шаг и принимает сообщение автоматически.

Сценарий: вы запушили в main коммит с ошибкой, коллеги уже сделали pull. Использовать git reset здесь опасно — история разойдётся. Правильное решение: git revert HEAD и git push. Все получат отмену через обычный pull.

git reset: три режима работы

git reset перемещает указатель HEAD на указанный коммит, переписывая историю. Используйте только для локальных коммитов, которые ещё не запушены в общую ветку. Команда имеет три режима, которые отличаются тем, что происходит с индексом (staging area) и рабочей директорией.

  • --soft — история откатывается, но все изменения остаются в индексе (готовы к коммиту)
  • --mixed (по умолчанию) — история откатывается, изменения возвращаются в рабочую директорию, но из индекса убираются
  • --hard — история откатывается, все изменения удаляются и из индекса, и из рабочей директории
			# --soft: откатить последний коммит, сохранить изменения в staging
git reset --soft HEAD~1

# --mixed: откатить, убрать из staging (но файлы остаются)
git reset --mixed HEAD~1
# или просто:
git reset HEAD~1

# --hard: откатить и удалить все изменения
git reset --hard HEAD~1

# Откатиться к конкретному коммиту
git reset --hard a1b2c3d
		

Сравнение трёх режимов git reset:

  • --soft: история изменяется, индекс сохраняется, рабочая директория сохраняется — применять, когда нужно переформулировать коммит или объединить несколько коммитов в один
  • --mixed: история изменяется, индекс очищается, рабочая директория сохраняется — применять, когда нужно перевыбрать файлы для коммита
  • --hard: история изменяется, индекс очищается, рабочая директория очищается — применять, когда нужно полностью выбросить изменения и вернуться к чистому состоянию

Практический пример: вы сделали три коммита с правками в одном файле и хотите отправить их как один. Используйте git reset --soft HEAD~3 — все три коммита исчезнут из истории, но изменения останутся в индексе. Остаётся сделать один финальный коммит.

git restore и git checkout: отмена изменений в файлах

Если нужно отменить изменения не в истории коммитов, а в конкретных файлах, используйте git restore (доступен с Git 2.23) или его предшественника git checkout -- file.

			# Отменить изменения в файле (вернуть до состояния последнего коммита)
git restore README.md
# или старый синтаксис:
git checkout -- README.md

# Убрать файл из staging area (отменить git add)
git restore --staged README.md
# или старый синтаксис:
git reset HEAD README.md

# Убрать из staging и отменить изменения в файле сразу
git restore --staged --worktree README.md
		

Сценарий: вы случайно добавили в git add файл с секретом .env. Перед коммитом выполните git restore --staged .env — файл останется на диске, но выйдет из индекса и не попадёт в коммит. Лучше сразу добавить его в .gitignore, чтобы не повторялось.

Если нужно вернуть файл к состоянию из определённого коммита, а не из HEAD, передайте хеш явно: git restore --source=a1b2c3d README.md. Это удобно, если файл менялся в нескольких коммитах и нужна конкретная версия.

Три сценария и как их решать

Сценарий 1: запушил не то в общую ветку. Уже сделали git push, коллеги могли получить изменения. Единственное безопасное решение — git revert HEAD и повторный push. Переписывать историю через reset здесь нельзя.

Сценарий 2: сломал рабочую ветку локальными коммитами. Изменения ещё не запушены. Используйте git reset --hard origin/main — ветка вернётся к состоянию на удалённом репозитории, все локальные коммиты и изменения исчезнут. Или git reset --mixed, если хотите сохранить файлы.

Сценарий 3: нужно убрать файл из последнего коммита. Коммит ещё локальный. Сначала отмените коммит: git reset --soft HEAD~1. Потом уберите файл из индекса: git restore --staged secret.txt. Затем сделайте новый коммит без этого файла.

Подробнее о похожих ситуациях читайте в статье про типичные ошибки Git — там разобраны десятки реальных кейсов с решениями.

Что выбрать: reset, revert или restore

Правило трёх вопросов, которое поможет выбрать инструмент:

  • Изменения уже запушены в общую ветку? — только git revert
  • Нужно отменить коммиты локально?git reset (выберите режим по необходимости)
  • Нужно отменить изменения в файлах (не коммиты)?git restore
  • git revert — создаёт новый коммит-отмену, не переписывает историю, безопасен после push; подходит для общих веток
  • git reset — переносит HEAD назад, переписывает историю, только для локальных изменений; подходит для личных веток и правки последних коммитов
  • git restore — отменяет изменения в файлах или убирает из staging, не трогает историю коммитов; подходит для отмены несохранённых изменений
Часто задаваемые вопросы
1
Можно ли отменить git reset --hard, если я случайно его выполнил?

Да, если прошло немного времени. Git хранит рефлог — журнал всех перемещений HEAD. Выполните git reflog, найдите хеш нужного состояния и восстановите его: git reset --hard a1b2c3d. Рефлог хранит записи около 90 дней.

2
В чём разница между git reset HEAD~1 и git revert HEAD?

git reset HEAD~1 удаляет последний коммит из истории (по умолчанию с флагом --mixed). git revert HEAD добавляет новый коммит, который отменяет изменения из последнего. Первый переписывает историю, второй — нет. Используйте reset только для локальных коммитов, revert — всегда безопасен.

3
Как откатить несколько коммитов сразу?

Если коммиты локальные: git reset HEAD~3 — откатит три последних коммита. Если уже запушены: используйте git revert для каждого коммита по отдельности или укажите диапазон: git revert HEAD~3..HEAD — создаст три коммита-отмены.

Запомните простое правило: если коммит уже попал в общую ветку — только git revert. Если ещё локальный — можно использовать git reset с нужным флагом. А git restore — для быстрой отмены изменений в файлах до коммита. Эти три инструмента покрывают 95% ситуаций, с которыми сталкиваются разработчики в повседневной работе.

Рекомендуем