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

Вы случайно убрали проверку остатков в корзине, закоммитили правку и заметили ошибку только после этого. Что делать — зависит от одного вопроса: коммит уже попал к коллегам или пока живёт только у вас. На примере ветки с изменением корзины разберём, как откатить файл, снять его с индекса или отменить опубликованный коммит; команды рассчитаны на Git 2.23 и новее.
Сначала выясните, где находятся изменения
Не начинайте с git reset --hard. Эта команда может удалить незакоммиченные правки в отслеживаемых файлах, и Git не спросит, точно ли вы этого хотите. Сначала посмотрите состояние рабочей копии и последние коммиты:
git status --short
git log -5 --oneline
В выводе git status --short первые два символа показывают, что происходит с файлом. Изменение только в рабочей копии обычно помечается как M; изменение, добавленное в индекс, — как M ; ?? означает новый неотслеживаемый файл. Если видите буквы в обеих позициях, файл могли менять и после добавления в индекс.
Дальше важно не только состояние файла, но и история: локальный коммит можно убрать с вершины ветки, а уже опубликованный обычно безопаснее отменить новым коммитом. Переписывание общей истории может осложнить работу коллегам.
Живой пример: сломали проверку корзины
Представим условный проект интернет-магазина и файл src/cart.js. Вы удалили из него проверку остатка товара. Коммит «Упростили проверку корзины» создан, но ещё не отправлен на сервер. Сначала подтвердите, что вершина ветки — именно этот коммит: команда ниже покажет его первым в списке.
git log -5 --oneline
Если это последний коммит и вы хотите исправить код, но не выбрасывать сделанную работу, уберите коммит, сохранив изменения в файле:
git reset --mixed HEAD~1
Теперь коммита в текущей ветке нет, а изменения остались в рабочей копии, не добавленные в индекс. Проверьте это командами:
git status --short
git diff -- src/cart.js
Убедитесь, что правка отображается в выводе git diff. Исправьте файл, добавьте в индекс нужные изменения и создайте новый коммит. Если передумали сохранять правку совсем, после сброса восстановите файл из текущего коммита:
git restore -- src/cart.js
Проверка: git status --short больше не показывает изменений в этом файле. Эта команда удаляет его незакоммиченные правки — сначала убедитесь, что в них нет нужного кода.
Перед откатом ответьте на два вопроса: хочу ли я сохранить сами изменения и успел ли кто-нибудь получить этот коммит? Ответ определяет безопасную команду лучше, чем название команды.
Выберите действие по состоянию файла и коммита
| Ситуация | Что сделать | Что останется | Риск |
|---|---|---|---|
| Изменение только в рабочей копии | git restore -- файл | Версия файла из индекса | Правки файла будут потеряны |
| Изменение уже добавлено в индекс | git restore --staged -- файл | Правки останутся в рабочей копии | Низкий: файл просто перестанет быть подготовленным к коммиту |
| Локальный коммит нужно убрать, правки сохранить | git reset --mixed HEAD~1 | Правки останутся вне индекса | Ветка переместится на предыдущий коммит |
| Коммит уже опубликован | git revert HEAD | История сохранится, появится новый отменяющий коммит | Возможны конфликты с последующими изменениями |
Индекс1 — промежуточная область Git: сюда попадают изменения, которые вы подготовили командой git add для следующего коммита. Рабочая копия и индекс могут содержать разные версии одного файла.
Изменение не добавлено в индекс
Если git status --short показывает изменение только в рабочей копии и оно вам не нужно, используйте git restore -- имя-файла. Git возьмёт для файла версию из индекса. Чтобы отменить правки во всём проекте, можно указать точку вместо имени файла: git restore .. Это широкое действие: сначала запустите git diff и проверьте, что именно исчезнет.
Файл уже добавлен через git add
Если хотите убрать файл из будущего коммита, но оставить редактирование, выполните git restore --staged -- src/cart.js. Команда меняет индекс, а не содержимое рабочей копии. Проверьте результат через git status --short: файл должен остаться изменённым, но больше не числиться подготовленным к коммиту.
Если нужно выбросить и подготовленную версию, и правки в рабочей копии, используйте git restore --source=HEAD --staged --worktree -- src/cart.js. Это не команда «на всякий случай»: она вернёт файл к версии последнего коммита. Сначала сохраните нужный фрагмент отдельно или сделайте временный коммит.
Локальный коммит нужно удалить целиком
Если изменения не нужны и коммит точно не отправляли коллегам, можно передвинуть ветку назад вместе с рабочей копией: git reset --hard HEAD~1. После этого исчезнут и последний коммит, и его правки в отслеживаемых файлах. Для ситуации, где нужно оставить изменения, безопаснее git reset --mixed HEAD~1, как в примере выше.
Не путайте эти команды: --mixed сохраняет изменения в рабочей копии, а --hard удаляет их. Незакоммиченные изменения, которые существовали ещё до отката, тоже могут пострадать. Перед сбросом сохраните нужную работу отдельным коммитом или скопируйте файл.
Если коммит уже отправили в общую ветку
Для опубликованного коммита обычно используйте git revert, а не сброс истории. Если неудачный коммит последний, команда выглядит так:
git revert HEAD
Git создаст новый коммит, который отменяет изменения предыдущего. Исходный коммит останется в истории, поэтому коллегам не придётся чинить ветку после переписывания её вершины. Убедитесь, что новый коммит появился в выводе git log -5 --oneline, а рабочее дерево чистое по результату git status --short.
Если отменяете не последний коммит, возьмите его хеш из git log --oneline и укажите вместо HEAD. Когда Git сообщит о конфликте, откройте перечисленные файлы, вручную выберите итоговый вариант и добавьте исправленные файлы в индекс командой git add. Затем продолжите отмену командой git revert --continue. Если выбрали не тот коммит, пока операция не завершена, отменить её можно командой git revert --abort.
Что чаще всего идёт не так
- Нужные правки исчезли после
git restore. Команда восстановила версию из индекса. Проверьте статус и различия до отката; если файл важен, сначала сохраните изменения отдельной копией. - После
git reset --mixedкоммит всё ещё виден коллегам. Сброс изменил только вашу локальную ветку. Если коммит уже отправили, ориентируйтесь наgit revert, чтобы не переписывать общую историю. git revertостановился с сообщением о конфликте. Это значит, что отменяемые строки пересекаются с более поздними правками. Разрешите конфликт, проверьте итоговый diff и только затем выполнитеgit revert --continue.- Новый файл не пропал после восстановления.
git restoreпредназначен для отслеживаемых файлов; неотслеживаемый файл с пометкой??— отдельный случай. Не запускайте вслепую команды массовой очистки: сначала проверьте, что в файле нет нужного содержимого.
Что делать дальше
После любого отката проверьте три вещи: git status --short показывает ожидаемое состояние, git diff не содержит неожиданных правок, а тесты проекта проходят. Если команда затрагивает файлы, которые вы редактировали параллельно, сравните изменения до создания следующего коммита. Чтобы снизить риск в будущем, перед сбросом сохраняйте важную работу отдельным коммитом, а перед отправкой проверяйте подготовленные изменения через git diff --cached.
1 Индекс также называют staging area или областью подготовки: это не резервная копия, а набор изменений для следующего коммита.
Редактор изображений: Убрать лишнее, заменить фон, добавить объект, расширить кадр — на вашем изображении.
Спросить за 20 ₽Источники: Официальная документация Git: git-reset, Официальная документация Git: git-revert
Частые вопросы
Как отменить последний коммит, но оставить файлы?
Что безопаснее для общей ветки: reset или revert?
Удаляет ли git restore новый файл с пометкой ???
Что делать, если git revert сообщил о конфликте?
Подойдут ли команды для другой версии Git?
Можно ли вернуть изменения после git reset --hard?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.