Как откатить коммит в Git: reset, revert, checkout
Закоммитил не то? Разбираем git revert, git reset и git restore — когда использовать каждый инструмент, таблица сравнения трёх режимов reset и три практических сценария.
Каждый разработчик рано или поздно делает коммит, который нужно отменить. Закоммитил не ту ветку, запушил секрет, сломал рабочий код — ситуации разные, но вопрос один: как это исправить? В 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 "Добавил новую фичу". Флаг --no-edit пропускает этот шаг и принимает сообщение автоматически.
Сценарий: вы запушили в main коммит с ошибкой, коллеги уже сделали pull. Использовать git reset здесь опасно — история разойдётся. Правильное решение: git revert HEAD и git push. Все получат отмену через обычный pull.
git reset: три режима работы
git reset перемещает указатель HEAD на указанный коммит, переписывая историю. Используйте только для локальных коммитов, которые ещё не запушены в общую ветку. Команда имеет три режима, которые отличаются тем, что происходит с индексом (staging area) и рабочей директорией.
- --soft — история откатывается, но все изменения остаются в индексе (готовы к коммиту)
- --mixed (по умолчанию) — история откатывается, изменения возвращаются в рабочую директорию, но из индекса убираются
- --hard — история откатывается, все изменения удаляются и из индекса, и из рабочей директории
Сравнение трёх режимов git reset:
- --soft: история изменяется, индекс сохраняется, рабочая директория сохраняется — применять, когда нужно переформулировать коммит или объединить несколько коммитов в один
- --mixed: история изменяется, индекс очищается, рабочая директория сохраняется — применять, когда нужно перевыбрать файлы для коммита
- --hard: история изменяется, индекс очищается, рабочая директория очищается — применять, когда нужно полностью выбросить изменения и вернуться к чистому состоянию
Практический пример: вы сделали три коммита с правками в одном файле и хотите отправить их как один. Используйте git reset --soft HEAD~3 — все три коммита исчезнут из истории, но изменения останутся в индексе. Остаётся сделать один финальный коммит.
git restore и git checkout: отмена изменений в файлах
Если нужно отменить изменения не в истории коммитов, а в конкретных файлах, используйте git restore (доступен с Git 2.23) или его предшественника git checkout -- file.
Сценарий: вы случайно добавили в 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, не трогает историю коммитов; подходит для отмены несохранённых изменений
Часто задаваемые вопросы
Можно ли отменить git reset --hard, если я случайно его выполнил?
Да, если прошло немного времени. Git хранит рефлог — журнал всех перемещений HEAD. Выполните git reflog, найдите хеш нужного состояния и восстановите его: git reset --hard a1b2c3d. Рефлог хранит записи около 90 дней.
В чём разница между git reset HEAD~1 и git revert HEAD?
git reset HEAD~1 удаляет последний коммит из истории (по умолчанию с флагом --mixed). git revert HEAD добавляет новый коммит, который отменяет изменения из последнего. Первый переписывает историю, второй — нет. Используйте reset только для локальных коммитов, revert — всегда безопасен.
Как откатить несколько коммитов сразу?
Если коммиты локальные: git reset HEAD~3 — откатит три последних коммита. Если уже запушены: используйте git revert для каждого коммита по отдельности или укажите диапазон: git revert HEAD~3..HEAD — создаст три коммита-отмены.
Запомните простое правило: если коммит уже попал в общую ветку — только git revert. Если ещё локальный — можно использовать git reset с нужным флагом. А git restore — для быстрой отмены изменений в файлах до коммита. Эти три инструмента покрывают 95% ситуаций, с которыми сталкиваются разработчики в повседневной работе.