Баннер мобильный (3) Пройти тест

Git Reset, Restore и Revert: как это работает

Как правильно откатить нежелательные изменения в Git

Разбор

3 апреля 2026

Поделиться

Скопировано
Git Reset, Restore и Revert: как это работает

Содержание

    Разбираемся, чем отличаются git reset, git restore и git revert, как откатить изменения в файле, удалить локальный коммит и не запутать историю ветки. 

    Как отменить изменения в Git

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

    Чтобы выбрать правильную команду, нужно понять, в какой зоне находятся изменения и какой статус у файла. В Git есть три основные зоны — рабочая директория, индекс (область подготовленных файлов или staging) и история коммитов

    Основные зоны Git схема
    • Новый файл, который Git еще не отслеживает, находится в рабочей директории под статусом untracked
    • После первой команды git add файл становится отслеживаемым и попадает в индекс (staging). 
    • Команда git commit сохраняет в истории коммитов текущее содержимое индекса. 
    • Если отслеживаемый файл изменили, то он получает статус modified. Чтобы включить эти изменения в следующий коммит, файл нужно снова добавить в индекс командой git add. Затем надо выполнить git commit, чтобы добавить содержимое индекса в историю.
    • Если изменений в соответствии с последним коммитом нет, то файл находится в состоянии unmodified.
    Как меняется статус файла в Git
    Жизненный цикл статуса файла от untracked до staged. Источник

    В официальной документации Git указано, что для отмены изменений есть три команды:

    • Git Revert создает новый коммит, который отменяет изменения предыдущего. Эту команду используют, когда коммит уже опубликован или когда историю ветки нежелательно переписывать.
    • Git Restore возвращает файл к сохраненному состоянию. Это используют, когда нужно вернуть файл в рабочей директории к сохраненному состоянию или убрать изменения из индекса через —staged.
    • Git Reset используют в двух разных ситуациях: либо чтобы отменить изменения в индексе, либо чтобы откатить локальный коммит.

    Что и где нужно отменить

    Перед откатом изменений нужно выяснить, на каком этапе они находятся.

    Изменения только в рабочей директории (команда git restore)

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

    Например, если вы отредактировали файл README.md, а потом оказалось, что правки не нужны, их можно отменить следующей командой: 

    git restore README.md

    Локальный файл вернется к состоянию последнего коммита, то есть к HEAD (указателю на последний коммит в текущей ветке).

    Если нужно восстановить файл не из текущего HEAD, а из другого коммита, можно указать источник явно. Например, чтобы вернуть файл на один коммит раньше, можно использовать команду:   

    git restore --source=HEAD~1 README.md

    При этом сама ветка не сдвинется, изменится только содержимое файла.

    Важно: git restore отменяет изменения только в уже отслеживаемых файлах. 

    Если вы создали новые файлы со статусом untracked и хотите отменить вообще все локальные изменения, одной команды git restore будет недостаточно. Для удаления неотслеживаемых файлов Git использует git clean.

    Изменения уже добавлены в индекс (команды restore —staged и reset <path>)

    После команды git add Git фиксирует, что эти изменения нужно будет включить в следующий коммит, но сам коммит еще не создан. Если изменения попали в индекс слишком рано, их можно убрать оттуда, не удаляя правки из файла.

    Для этого обычно используют команду git restore —staged. Например, чтобы убрать файл app.js из списка подготовленных к коммиту, нужно использовать следующую команду:

    git restore --staged app.js

    Изменения уйдут из индекса, но останутся в рабочей директории.

    Есть и другой способ снять изменения с индекса через git reset:

    git reset app.js

    Изменения также уйдут из зоны индекса, а правки останутся локально.

    Команду git restore —staged используют, когда нужно убрать изменения из области индекса.

    Команда git reset <path> тоже умеет это делать, но на этом его возможности не заканчиваются. Он также может работать с историей коммитов, о чем расскажем ниже.

    Уже есть локальный коммит с изменениями (команды reset —soft, —mixed, —hard)

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

    Оставить изменения в индексе (—soft)

    Если нужно отменить последний коммит, но оставить все изменения подготовленными к новому коммиту, подойдет такая команда:

    git reset --soft HEAD~1

    Это нужно, если вы слишком рано сделали коммит, забыли поправить сообщение или хотите тут же пересобрать его заново.

    Оставить изменения только в рабочей директории (—mixed)

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

    git reset HEAD~1 

    Эта функция по умолчанию работает в режиме —mixed, то есть Git переносит HEAD на предыдущий коммит и обновляет индекс под новое состояние ветки, не трогая файлы рабочей директории. В результате последний коммит исчезает из текущей ветки, изменения убираются из индекса, но правки остаются в файлах.

    Удалить локальный коммит вместе с изменениями (—hard)

    Если же нужно полностью удалить последний локальный коммит вместе со всеми внесенными в него изменениями, то используют команду:

    git reset --hard HEAD~1 

    Git не только уберет коммит, но и приведет рабочую директорию к выбранному состоянию. Этот режим стоит использовать осторожно, чтобы не потерять локальные изменения. Документация отдельно отмечает, что —hard сбрасывает и индекс, и рабочее дерево, а изменения в отслеживаемых файлах после выбранного коммита удаляются.

    Откат к конкретному коммиту

    По тому же принципу можно откатываться не только на один коммит назад, но и к конкретному коммиту по хешу. Например, возьмем три команды, обращающиеся к коммиту по хешу:

    git reset --soft a1b2c3d
    git reset a1b2c3d
    git reset --hard a1b2c3d

    Первая сохранит изменения в индексе, вторая оставит их как локальные правки (в рабочей директории), а третья полностью удалит.

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

    После этого можно вернуться к нужному состоянию через git reset —hard <hash> или создать новую ветку от найденного коммита. Но если изменения вообще не были сохранены в коммите и потом были перезаписаны, например через git reset —hard, восстановить их уже, скорее всего, не получится.

    Коммит уже опубликован (команда revert)

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

    Например, если после push выяснилось, что последний коммит сломал сборку или внутреннюю логику, можно создать коммит-откат с помощью следующей команды:

    git revert HEAD 

    История останется последовательной, то есть будет видно и проблемный коммит, и его отмену.

    Если нужно отменить не последний, а конкретный коммит, можно также обратиться к коммиту по хэшу: 

    git revert <hash>

    Это оптимальный вариант для общих веток вроде main или dev, где нежелательно переписывать уже опубликованную историю.

    Важно помнить о двух ограничениях. 

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

    Во-вторых, нужно быть внимательными с merge-коммитами. Команды git revert <hash> для merge-коммита недостаточно, потому что Git должен понимать, какого родителя считать основной линией. Для этого используют параметр —mainline

    Документация также предупреждает, что отмена merge-коммита влияет и на будущие слияния. Git будет считать, что изменения из этого merge больше не нужно возвращать. Поэтому такой откат нужно делать осознанно.

    Дополнительные сценарии для каждой команды

    git restore —patch

    Мы уже разобрали сценарий, когда нужно просто вернуть файл к предыдущему состоянию через git restore —source. У git restore также есть опция частичной отмены изменений через режим —patch

    Например, внесем изменение в README проекта по управлению банковскими картами.

    Код для git restore —patch пример

    Изменили две строки. Вызываем в корне проекта команду:

    git restore --patch README.md

    Консоль предложит принять или отклонить изменения по порядку. Сперва она спросит про первое, нужно ли его откатить:

    Пример кода для git restore

    Согласимся откатить изменение, отправив y. Затем консоль предложит второе:

    Пример кода git restore patch

    Его мы оставим, отправив n. Тогда в проекте мы увидим такие изменения:

    Пример кода git restore patch

    По скриншоту видно, что осталось только то изменение, которое не откатили.

    Также нужно помнить, что по умолчанию команда git restore берет содержимое из индекса. То есть Git восстанавливает рабочую версию файла из того состояния, которое подготовлено к коммиту. А вот для git restore —staged источник по умолчанию — HEAD, то есть последний коммит текущей ветки (из истории коммитов).

    git reset —patch (-p)

    У git reset также есть частичная отмена изменений из индекса. Если вы добавили в индекс слишком большой набор правок, но потом решили разбить его на несколько аккуратных коммитов, не обязательно откатывать файл целиком. Вместо этого можно использовать git reset —patch (или git reset -p).

    Например, вы изменили app.js, добавили файл через git add app.js, а потом выяснилось, что в одном коммите должны остаться только изменения валидации, а правки логирования лучше вынести отдельно. В такой ситуации подойдет следующая команда:

    git reset -p app.js

    Принцип запуска здесь такой же, как у git restore —patch. Git также предложит выбрать, какие фрагменты изменений нужно убрать из индекса. При этом важно понимать, что изменения пропадут именно из индекса, а в рабочей директории останутся.

    git revert —no-commit

    Обычно git revert сразу создает отдельный коммит-откат. Но если нужно отменить одновременно несколько коммитов и оформить это не серией мелких откатов, а одним общим коммитом, используют git revert —no-commit или короткую форму git revert -n. 

    В этом режиме Git готовит откат локально: вносит обратные изменения в файлы и добавляет их в индекс, но сам коммит автоматически не создает. 

    После этого можно проверить результат, при необходимости что-то поправить и только потом вручную выполнить git commit.

    Например, если нужно отменить два подряд идущих неудачных коммита и оформить это одним общим откатом, можно сделать так:

    git revert --no-commit <hash1> <hash2>
    git commit -m "Отмена некорректных изменений"

    После первой команды Git подготовит суммарный откат в локальных файлах и в индексе, а после второй вы сами сохраните его одним коммитом.

    Git reset, restore и revert: коротко о главном

    • Команда git restore подходит, когда нужно вернуть файл к сохраненному состоянию или снять изменения из индекса через —staged. По умолчанию он не двигает ветку и не меняет историю.
    • Команды git reset <path> и git reset —patch работают только с индексом. Они убирают из него изменения, но не двигают HEAD и не переписывают историю. 
    • Команды git reset —soft, —mixed и —hard используют для отката локальных коммитов. Эти режимы двигают HEAD, —mixed и —hard дополнительно меняют индекс, а —hard еще и рабочую директорию. 
    • Команда git revert нужна для уже опубликованных коммитов, когда историю ветки переписывать нежелательно. Он не удаляет старый коммит, а создает новый коммит-откат. 
    • git reflog помогает вернуть «исчезнувший» после reset коммит, но не гарантирует восстановление изменений, которые никогда не были сохранены в коммите.
    • Для новых untracked файлов git restore не подходит. Их удаляют отдельно, обычно через git clean. 

    Разбор

    Поделиться

    Скопировано
    0 комментариев
    Комментарии