Главная правда о Git, которую стоит выучить до первой паники: закоммиченное почти невозможно потерять. У каждой ошибки есть штатная отмена, а на крайний случай существует reflog — чёрный ящик, помнящий всё. Разберём инструменты от лёгких случаев к тяжёлым.
Отменить незакоммиченное: restore
git restore file.txt # откатить файл к последнему коммиту (правки ПРОПАДУТ)
git restore --staged file.txt # убрать из индекса (правки останутся в файле)
git restore . # откатить всё незакоммиченное
Единственное место в Git, где работа теряется по-настоящему, — здесь: незакоммиченные правки после restore не вернуть. Отсюда правило: сомневаетесь — сначала закоммитьте или спрячьте в stash, откатить сможете всегда.
Спрятать на минутку: stash
Нужно срочно переключиться, а работа не доделана:
git stash # спрятать незакоммиченное в карман
git stash list # что в кармане
git stash pop # вернуть последнее спрятанное
Stash — временный карман, не архив: вернулись к задаче — сразу pop. Полгода коллекционировать stash'и — способ забыть, что в них было.
Откатить коммиты: reset против revert
Два инструмента для разных ситуаций — граница проходит по вопросу «отправлено ли это уже другим?»
reset — переписать локальную историю (коммиты ещё не пушены):
git reset --soft HEAD~1 # снять последний коммит, изменения остаются в индексе
git reset HEAD~1 # снять коммит, изменения — в рабочих файлах (по умолчанию)
git reset --hard HEAD~1 # снять коммит И ВЫБРОСИТЬ изменения
--soft — «пересобрать коммит иначе», --hard — «этого не было». С --hard — как с UPDATE без WHERE: сначала убедитесь, что выбрасываете именно то.
revert — отменить публично и честно (коммиты уже на сервере):
git revert a1b2c3 # создаёт НОВЫЙ коммит с обратными изменениями
История не переписывается — она дополняется коммитом-антиподом. Именно так откатывают влитое в main: сломавший прод PR отменяется revert-коммитом за минуту, безопасно и с сохранением летописи. Правило в одну строку: локальное — reset, отправленное — revert.
reflog: машина времени последней надежды
«Сделал reset --hard не туда», «rebase всё сломал», «удалил ветку с работой» — спокойно. Reflog — журнал всех перемещений HEAD за последние ~90 дней, включая «удалённые» состояния:
git reflog
# a1b2c3 HEAD@{0}: reset: moving to HEAD~3
# d4e5f6 HEAD@{1}: commit: та самая работа ← вот оно!
git reset --hard d4e5f6 # вернуться в состояние до аварии
# или аккуратнее: git branch rescue d4e5f6 — поставить ветку на найденный коммит
Всё, что хоть раз было закоммичено, находится в reflog. Настоящих способов потерять закоммиченную работу почти нет — и это возвращает к правилу из начала цикла: коммитьте часто; коммит — это страховка, которую нельзя отобрать.
Коротко
- Незакоммиченное — единственное по-настоящему теряемое:
restoreнеобратим. Сомневаетесь — коммит или stash. - stash — карман на минутку: спрятал → переключился → вернулся → pop.
- Локальную историю правит reset (soft — пересобрать, hard — выбросить); отправленную отменяет revert новым коммитом. «Локальное — reset, публичное — revert».
- reflog помнит все состояния ~90 дней: после любой аварии —
git reflog→ вернуться на нужный коммит. - Частые коммиты = неотбираемая страховка.
Что почитать дальше
- Rebase и cherry-pick — операции, после которых reflog особенно греет душу.
- Коммиты и история —
--amendи другие лёгкие правки. - Модели ветвления — финальная статья цикла.