Git-инструменты отмены коммитов: как использовать git reset и git revert

Ошибки при разработке – не редкость. Можно закоммитить не тот файл, забыть про опечатку в коде или случайно смешать несколько задач в одном коммите. Git – система контроля версий, которая хранит полную историю изменений проекта и позволяет откатить практически любую оплошность буквально одной командой.

В этой статье разберем, как отменять коммиты с помощью git reset и git revert и чем они отличаются друг от друга, а также рассмотрим дополнительные инструменты отката – git checkout, git restore, git merge --abort, git reflog и git commit --amend.

Три зоны Git

Прежде чем переходить к работе с командами, полезно вспомнить, как устроен Git изнутри. Любой файл в проекте последовательно проходит через три области:

  • Рабочая директория (working directory) – папка на диске, где вы редактируете файлы.
  • Индекс (staging area) – промежуточный буфер, в который попадают файлы после команды git add. Именно из индекса Git берет данные для следующего коммита.
  • Репозиторий – хранилище, куда изменения фиксируются окончательно командой git commit.

Таким образом, путь файла выглядит так: сначала правки вносятся в рабочей директории, затем git add переносит их в индекс, а git commit записывает их в историю репозитория в виде нового коммита.

git reset

Разберем, что делает git reset. Эта команда умеет откатывать состояние сразу в одной, двух или во всех трех зонах Git, в зависимости от того, какой режим вы укажете.

Общий вид команды:

git reset [--<режим>] [<коммит>]

Где:

  • <коммит> – это точка в истории, к которой нужно вернуться. Например, HEAD~1 – на один коммит назад, HEAD~3 – на три коммита назад либо конкретный хэш коммита. 
  • <режим> – определяет, что именно произойдет с индексом и рабочей директорией. Всего есть три режима: soft, mixed и hard.

Режим soft: откат только указателя HEAD

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

Синтаксис:

git reset --soft [<коммит>]

Допустим, вы создали файл new-file.txt, добавили его в индекс и закоммитили с некорректным сообщением:

git add new-file.txt
git commit -m "wrong commit"

Чтобы отменить этот коммит, но сохранить изменения в индексе, выполните:

git reset --soft HEAD~1

Проверить результат можно командой git status – она покажет, что файл new-file.txt снова находится в состоянии «Changes to be committed», то есть готов к коммиту. Осталось сделать коммит с правильным сообщением:

git commit -m "correct commit"

История репозитория остается чистой: вместо ошибочного коммита появляется корректный, а сами изменения при этом никуда не пропадают.

Режим mixed: поведение по умолчанию

Если запустить git reset без указания режима, Git применит mixed – это поведение по умолчанию. Оно отменяет последний коммит и сбрасывает индекс, но не изменяет файлы в рабочей директории: правки остаются на месте, просто перестают быть проиндексированными.

Синтаксис:

git reset --mixed [<коммит>]

Допустим, вы закоммитили сразу три файла, хотя один из них, something.txt, добавлять было не нужно:

git add main_file.txt
git add updates.txt
git add something.txt
git commit -m "добавил файлы"

Отменяем коммит:

git reset HEAD~1

HEAD переместится на коммит назад, а все три файла снова окажутся в статусе неотслеживаемых/непроиндексированных изменений. Теперь в индекс можно добавить только нужные файлы:

git add main_file.txt
git add updates.txt

И зафиксировать новый корректный коммит:

git commit -m "Added files 1 and 2, excluding file 3"

Что делает git reset hard: полный откат изменений

git reset --hard – самый радикальный вариант, предназначенный для отмены изменений. Он отменяет коммит, очищает индекс и полностью возвращает файлы в рабочей директории к состоянию указанного коммита. Все несохраненные изменения будут безвозвратно потеряны, поэтому пользоваться этим режимом стоит осторожно.

Вы случайно закоммитили ненужный файл:

git add another_new_file.txt
git commit -m "Added incorrect file"

Чтобы полностью удалить этот коммит вместе с файлом из рабочего каталога:

git reset --hard HEAD~1

После выполнения команды файл another_new_file.txt исчезнет не только из истории, но и с диска.

git revert

В отличие от git reset, который перемещает HEAD и может стирать коммиты из истории, git revert commit работает иначе: он создает новый коммит, который отменяет изменения указанного коммита, но при этом ничего не удаляет из истории. Это делает git revert более безопасным инструментом, что особенно важно для отмены изменений в публичных ветках, с которыми уже работают другие участники команды.

Сначала нужно найти идентификатор коммита, который требуется отменить:

git log

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

commit 2e3c670bfe46a5d7c5
Author: Ivanov Ivan <ivivanov@example.com>
Date:   Fri Jul 24 15:32:46 2026 -0400
    Test commit

Далее выполняем отмену по хэшу коммита:

git revert 2e3c670bfe46a5d7c5

Git создаст новый коммит, откатывающий указанные изменения, и откроет редактор для ввода сообщения – там можно указать причину отката. Стоит учитывать, что при отмене может возникнуть конфликт слияния, если после нужного коммита файл менялся еще раз – в этом случае конфликт придется разрешить вручную.

Если нужно отменить сразу несколько коммитов подряд одним итоговым коммитом, а не по одному, можно указать диапазон и добавить флаг --no-commit (сокращенно -n): он применит все отмены к рабочей директории и индексу, но не будет создавать коммит после каждой из них, оставив это на ваше усмотрение: 

git revert --no-commit HEAD~3..HEAD
git commit -m "Откат трех последних коммитов" 

git reset или git revert: что выбрать

git reset подходит для локальной, еще не опубликованной работы. Он передвигает HEAD назад и, в зависимости от режима, освобождает индекс (mixed) и рабочую директорию (hard) или оставляет их нетронутыми (soft). Все три режима переписывают историю. Отмененные коммиты перестают быть частью текущей ветки, а публиковать такую переписанную историю в общий репозиторий, где уже работают другие, небезопасно.

git revert подходит, когда коммит уже отправлен в общую ветку и его видят другие участники команды. Вместо того чтобы стирать или двигать историю, git revert добавляет новый коммит, который отменяет изменения старого. История остается линейной и полной, поэтому git revertболее безопасный выбор для командной работы и публичных веток.

git checkout и git restore

Изначально команда git checkout создавалась для переключения между ветками, но ее также можно использовать, чтобы вернуть отдельный файл к состоянию последнего коммита.

Например, вы внесли и закоммитили правки в test.sh, но результат вас не устроил:

git checkout HEAD -- test.sh

Файл вернется к состоянию, в котором был до последнего коммита. Если нужно откатиться не к предыдущему, а к конкретному более раннему коммиту, сначала найдите его хэш через git log, а затем укажите его вместо HEAD:

git checkout [<идентификатор коммита>] -- script.sh

Начиная с версии Git 2.23, для восстановления файлов рекомендуется использовать более новую и однозначную по смыслу команду git restore – она была выделена из git checkout специально для отмены изменений в файлах, тогда как за переключением веток теперь закреплена отдельная команда git switch. Тот же результат, что и в примере выше, можно получить так:

git restore --source=HEAD -- test.sh

А для отката к более раннему коммиту:

git restore --source=[<идентификатор коммита>] -- script.sh

git checkout по-прежнему работает и встречается в старых инструкциях, но для новых проектов рекомендуется использовать git restore (для файлов) и git switch (для веток) – так меньше риска перепутать назначение команды.

git merge --abort

Слияние (merge) объединяет изменения из одной ветки в другую. Если в процессе что-то пошло не так и слияние нужно прервать, выполните следующие шаги:

  1. Проверьте, идет ли сейчас слияние: git status покажет соответствующее сообщение.
  2. Прервите операцию: git merge --abort.
  3. Снова выполните git status, чтобы убедиться, что репозиторий вернулся в исходное состояние.

git reflog

Если в процессе работы с git reset вы отменили больше, чем нужно, все действия можно восстановить с помощью команды git reflog. Она хранит полный журнал перемещений указателя HEAD – переключения веток, коммиты, сбросы. Это позволяет вернуться к любому из этих состояний.

Смотрим журнал:

git reflog

В выводе каждая строка отмечена своим индексом вида HEAD@{N}. Найдя нужную точку, возвращаемся к ней:

git reset --hard HEAD@{индекс}

Таким образом можно «отменить отмену» и восстановить коммиты, которые казались потерянными.

Обратите внимание!
Записи в git reflog хранятся не бесконечно: по умолчанию Git удаляет их примерно через 90 дней для коммитов, которые еще достижимы из текущих веток, и через 30 дней – для тех, которые уже ничем не удерживаются. Поэтому git reflog – это подстраховка на ближайшее время, а не постоянный архив, и восстанавливать нужные коммиты стоит как можно быстрее после ошибки. 

Редактирование истории коммитов

Изменение текста последнего коммита

Если нужно поправить только сообщение последнего коммита (или добавить в него забытые изменения из индекса), используется команда:

git commit --amend

Она не создает новый коммит, а объединяет содержимое индекса с предыдущим коммитом и позволяет отредактировать его сообщение. Для Git такой измененный коммит выглядит как совершенно новый – у него меняется хэш.

Объединение нескольких коммитов в один

Для склеивания нескольких последних коммитов в один применяется интерактивный режим перебазирования:

git rebase -i HEAD~3

Команда откроет в текстовом редакторе список последних трех коммитов, например:

pick hfdjhj23 что-то исправляем
pick 5556f9n классное изменение
pick egrhth1 последнее изменение

Чтобы объединить второй и третий коммит с первым, замените команду pick на squash у тех коммитов, которые нужно слить:

pick hfdjhj23 что-то исправляем
squash 5556f9n классное изменение
squash egrhth1 последнее изменение

После сохранения файла Git предложит объединить сообщения коммитов в одно – его можно отредактировать. Проверить результат удобно командой git log.

Заключение

Git – незаменимый инструмент для контроля версий, который избавляет от страха потерять код или чужие правки: практически любое действие можно отменить или исправить. 

Освоив команды из данной статьи, вы сможете уверенно исправлять ошибки в истории проекта и не бояться экспериментировать с кодом, а о том, как установить и настроить Git на сервере Ubuntu 22.04, вы можете узнать из отдельной инструкции.

Обратите внимание!
Часть команд – git reset, git commit --amend и git rebaseпереписывают историю коммитов. У измененных коммитов меняется хэш, а старые версии как будто исчезают из истории. Если такие коммиты уже отправлены (запушены) в общий репозиторий и с ними мог начать работать кто-то из команды, переписывать их не стоит, так как локальная история разойдется с удаленной, что приведет к конфликтам и потере чужих изменений.

Если возникнут вопросы, напишите нам, пожалуйста, тикет из панели управления аккаунта (раздел “Помощь и поддержка”), а если вы захотите обсудить эту статью или наши продукты с коллегами по цеху и сотрудниками Beget – ждем вас в нашем сообществе в Telegram.