210 слов | 1 минута

Откат коммитов в Git

Инструкция для ситуации, когда в ветку попали «плохие» коммиты: как безопасно откатиться, найти нужное состояние кода и при необходимости перенести отдельные изменения через cherry-pick.

Сценарий

В ветке main появились три «плохих» коммита (последние 3). Нужно откатиться на 4 шага назад, проверить исчезновение ошибки, внести правки и снова запушить.

Шаг 1 — Сохранить текущую работу

Если есть незакоммиченные изменения — сохраните их в stash:

git stash push -m "WIP before rollback"

Шаг 2 — Посмотреть историю коммитов

git log --oneline --decorate --graph -n 10

Пример вывода:

* a1b2c3d (HEAD -> main, origin/main) Fix wrong validation
* d4e5f6g Add logging
* h7i8j9k Refactor auth flow
* l0m1n2o Implement new feature
* p3q4r5s Update README

a1b2c3d — текущий HEAD. Нужный коммит (4 назад) — l0m1n2o.

Шаг 3 — Получить хэш нужного коммита

git rev-parse HEAD~4

Пример вывода:

l0m1n2o9abcdef1234567890abcdef123456

Шаг 4 — Откатиться локально

git reset --hard HEAD~4

Пример вывода:

HEAD is now at l0m1n2o Implement new feature

После этого файлы находятся в состоянии коммита HEAD~4.

Шаг 5 — Проверить проект

Запустите тесты или воспроизведите сценарий с ошибкой. Если ошибка исчезла — переходите к следующему шагу. Если нет — повторите откат ещё на несколько коммитов.

Шаг 6 — Просмотреть «потерянные» коммиты через reflog

Даже после reset --hard коммиты остаются доступными:

git reflog

Пример вывода:

e1f2a3b (HEAD -> main) HEAD@{0}: reset: moving to HEAD~4
a1b2c3d HEAD@{1}: commit: Fix wrong validation
d4e5f6g HEAD@{2}: commit: Add logging
h7i8j9k HEAD@{3}: commit: Refactor auth flow

HEAD@{1..3} — «потерянные» коммиты.

Шаг 7 — Просмотреть содержимое коммита

git show a1b2c3d

Пример вывода:

commit a1b2c3d4e5f67890...
Author: Dmitry <dmitry@example.com>
Date:   Fri Nov 28 15:10:00 2025 +0300

    Fix wrong validation

diff --git a/src/auth.js b/src/auth.js
index 1234567..89abcde 100644
--- a/src/auth.js
+++ b/src/auth.js
@@ -45,7 +45,7 @@ function validate(user) {
-    if (user.password.length < 6) return false;
+    if (user.password.length < 8) return false;
 }

Шаг 8 — Восстановить коммит в отдельную ветку

Если нужно извлечь изменения из «потерянного» коммита:

git checkout -b recover-a1b2c3d a1b2c3d

Шаг 9 — Перенести нужные изменения через cherry-pick

git checkout main
git cherry-pick a1b2c3d

Пример успешного вывода:

[main 9f8e7d6] Fix wrong validation
 Date: Fri Nov 28 15:10:00 2025 +0300
 1 file changed, 1 insertion(+), 1 deletion(-)

При конфликтах Git укажет, какие файлы нужно исправить вручную.

Шаг 10 — Запушить изменения

После изменения истории через reset --hard потребуется force push:

git push --force origin main

Пример вывода:

To github.com:your/repo.git
 + a1b2c3d... l0m1n2o HEAD -> main (forced update)

Безопасный откат без изменения истории: git revert

Если другие разработчики уже синхронизировались с веткой — не переписывайте историю. Используйте revert:

git revert a1b2c3d..HEAD
git push origin main

git revert создаёт новые коммиты, отменяющие изменения, без удаления существующих.

Краткая шпаргалка

git log --oneline
git rev-parse HEAD~4
git reset --hard HEAD~4
# исправить ошибку, закоммитить
git add .
git commit -m "исправляет ошибку после отката"
git push --force
# при необходимости найти старые коммиты:
git reflog
git show <hash>

Дополнительные команды:

# проверить текущее состояние
git status

# экспериментировать безопасно в отдельной ветке
git checkout -b try-rollback
git reset --hard HEAD~4

# восстановить сохранённые изменения из stash
git stash list
git stash apply stash@{0}