git reset --soft HEAD~1 убирает коммит и оставляет все изменения в индексе — ровно в том виде, в каком они были за секунду до коммита. Это ответ для типичного случая. Но важнее флага то, в каком случае вы находитесь.
1. Ещё не пушили — снять коммит, оставить работу в индексе
$ clai отмени последний коммит, но оставь изменения в индексе→ git reset --soft HEAD~1$ git status --shortM f.txt
Коммита в логе нет, файлы не тронуты, всё осталось в индексе. Поправьте сообщение или добавьте забытый файл и коммитьте заново.
2. Оставить изменения, но убрать из индекса
$ clai отмени последний коммит и убери изменения из индекса→ git reset HEAD~1
--mixed — режим по умолчанию. То же, что soft, но на шаг дальше: файлы остаются на диске, индекс очищается. Берите, когда хотите разложить работу по другим коммитам.
3. Выбросить работу совсем
$ clai удали последний коммит вместе со всеми изменениями насовсем→ git reset --hard HEAD~1⚠ DANGER — незакоммиченные изменения в рабочем дереве будут уничтожены
--hard — единственный из трёх, который теряет работу. Закоммиченное можно достать через reflog, а вот изменённое и не закоммиченное — нет.
4. Уже запушили — не reset, а revert
$ clai отмени коммит, который я уже запушил, не переписывая историю→ git revert HEAD
revert создаёт новый коммит, отменяющий старый. История остаётся целой, и тем, кто уже сделал pull, ничего делать не нужно. На общей ветке это единственный правильный ответ.
5. Нужно всего лишь поправить сообщение
$ clai поменяй сообщение последнего коммита→ git commit --amend -m "Fix cache invalidation on write path"
Если в индексе пусто, --amend перепишет только сообщение. Если там что-то есть — заодно вольёт эти изменения в предыдущий коммит. Полезно, но легко сделать случайно.
6. Выбрали не то — вернуть назад
$ clai покажи, где был HEAD до этого reset→ git reflog4d2e830 HEAD@{0}: reset: moving to HEAD~1dc4fa62 HEAD@{1}: commit: second4d2e830 HEAD@{2}: commit (initial): first$ git reset --hard dc4fa62
Reflog помнит каждое положение HEAD — по умолчанию 90 дней. --hard на потерянный коммит возвращает его ровно таким, каким он был.
Грабли
- Никогда не пушьте reset с force в общую ветку. Переписанная история ломает клоны у тех, кто уже сделал pull. Для этого и существует
revert. HEAD~1иHEAD^здесь одно и то же — один коммит назад. Различаются они только на merge-коммитах, гдеHEAD^2означает второго родителя.--amendпосле пуша тоже переписывает историю. Он создаёт новый объект коммита с новым хешем, так что правило то же.
Похожие вопросы
Как отменить три последних коммита, сохранив все изменения? git reset --soft HEAD~3 — всё из этих коммитов окажется в индексе одной кучей.
Reset удаляет коммит навсегда? Не сразу. Коммит становится недостижимым, но reflog указывает на него ещё около 90 дней, пока не отработает сборка мусора.
Reset или revert в ветке, которой больше никто не пользуется? Reset, он чище. Revert — с того момента, как кто-то мог сделать pull.
Читайте также
- Git-задачи как мысль вслух: «покажи коммиты, которые я не запушил»
- SAFE, CAUTION, DANGER: как CliAI классифицирует команду перед запуском
- Первый день онбординга: как CliAI заменяет «спроси сеньора в Slack»
CliAI помечает reset --hard как DANGER и требует подтверждения вводом — это единственная команда git, которая реально теряет работу. Установка одной строкой.