git — отменить последний коммит, сохранив изменения
Три команды покрывают почти все отмены: reset --soft/--mixed сохраняет работу, --hard держит reflog в качестве страховки, revert — для уже отправленного — каждая команда работает как есть.
■ space · прозаическая полоса
Отменить последний коммит, сохранив изменения: git reset --soft HEAD~1 (staged) или git reset HEAD~1 (unstaged).
Уже отправлен? git revert HEAD — новый коммит, который его отменяет; безопасно на общих ветках.
reset --hard — единственная строка, которая удаляет работу — и git reflog всё ещё помнит, ~90 дней.
ТРИ ПУТИ
Один лишний коммит, три выхода. Флаг решает, где осядут ваши изменения — идите по путям:
fig — единственный путь, удаляющий работу, это --hard; reflog — сточная канава, текущая под всеми тремя
СОХРАНИТЬ ИЗМЕНЕНИЯ: ДВЕ КОМАНДЫ
Самая частая ситуация: вы закоммитили, потом заметили опечатку, недостающий файл или поняли, что изменение относится к другому коммиту. Ничего не отправлено. Отмените коммит и верните всё на место:
# коммит исчез — изменения вернулись в зну staging
git reset --soft HEAD~1
# вместо этого изменения вернулись в рабочее дерево (unstaged)
git reset HEAD~1
HEAD~1 означает «на один коммит раньше того места, куда указывает HEAD сейчас». После любой из команд файлы на диске не тронуты — сдвинулся только указатель ветки. Проверьте через git status: with --soft изменения staged, готовы к перекоммиту с влитыми правками; без флага они unstaged, так что сначала можно свободно править.
проверка: git status → staged (--soft) или unstaged (по умолчанию) · git log --oneline -1 → предыдущий коммит
Более безопасная привычка, когда нужно лишь добавить файлы в последний коммит, — вообще его не отменять:
git add forgotten-file.txt
git commit --amend --no-edit
--amend заменяет последний коммит на месте (здесь без смены сообщения). Заметьте: правка отправленного коммита переписывает историю — подробнее ниже.
ТРИ ФЛАГА, БОК О БОК
Вот это стоит запомнить: флаг решает, где закончатся ваши изменения — и можно ли их потерять:
| Флаг | Коммит отменён? | Изменения на диске | Staged? | Типичное применение |
|---|---|---|---|---|
--soft | Да | Сохранены | Yes | Перекоммит с мелкими правками |
--mixed (по умолчанию) | Да | Сохранены | No | Перегруппировать изменения, индексировать выборочно |
--hard | Да | Удалены | — | Выбросить работу целиком |
git revert | Нет (новый коммит) | Сохранены | — | Отменить уже отправленный коммит |
--hard — единственный опасный: он отбрасывает коммит и изменения. Перед любым hard reset спрячьте работу в stash или ветку:
git branch backup-before-reset # дешёвая страховка
git reset --hard HEAD~1 # коммит + изменения исчезли
Уже запустили опасную версию? Не всё потеряно — git reflog помнит, где был HEAD. По умолчанию reflog хранит висячие коммиты около 90 дней, так что «я случайно сделал hard-reset» почти всегда обратимо, если успеть до garbage collection:
git reflog # или: git reset --hard <hash>
git reset --hard HEAD@{1} # or: git reset --hard <hash>
проверка: git reflog → брошенный коммит сидит в HEAD@{1}
УЖЕ ОТПРАВЛЕН?
Общая история получает новый коммит, никогда — перезапись. Если коммит на общей ветке — всё, кроме вашей собственной feature-ветки, — не переписывайте историю. git revert вычисляет обратное изменение и коммитит его. Все, кто делает pull, просто получают новый коммит, снимающий изменения старого. Ни force-push, ни сломанных коллег:
git revert HEAD
git push
Undoing a run of commits is the same move over a range: Отмена серии коммитов — то же движение по диапазону: . The alternative — — допустимо лишь на ветке, на которой никто другой не собирает: — is only acceptable on a branch nobody else builds on: --force-with-lease откажет в push, если remote сдвинулся с прошлого fetch; голый --force затирает всё, что появилось. Force-push общих веток — так команды теряют коммиты, а логи CI загадочно перестают совпадать с чекаутом кого-либо.
проверка: git log --oneline -2 → Revert "…" ложится поверх отменённого коммита
РАБОТА ХОРОШАЯ, АДРЕС НЕ ТОТ
Иногда коммит в порядке — не та ветка или слишком рано. Вместо отмены переместите его. Припаркуйте коммит целиком в новой ветке, затем почистите свою
git branch stash-commit # припарковать коммит в новой ветке
git reset --hard HEAD~1 # затем почистить текущую ветку
git cherry-pick <hash> # находясь на целевой ветке
Между reset --soft, cherry-pick and revert нет коммита, который нельзя переместить или обнулить — трюк в том, чтобы выбрать «переместить» или «отменить» до того, как тянуться к флагу.
СЛОВО ЕСТЬ КОМАНДА
Половина путаницы — словарь: шесть глаголов, которые люди вводят в поиск, и три команды, которые реально существуют. Соотнесите слово в голове с флагом, который это делает:
| Слово, которое вы ввели | Чего вы хотите | Команда | Изменения сохранены? |
|---|---|---|---|
| undo / uncommit | коммита нет, работа вернулась | git reset --soft HEAD~1 | да — staged |
| undo, unstaged | коммита нет, работа вернулась россыпью | git reset HEAD~1 | да — mixed |
| remove / drop | коммита и правок нет | git reset --hard HEAD~1 | нет — reflog ~90 дней |
| revert / cancel, отправлен | публичная отмена, история цела | git revert HEAD | да — новый коммит |
Глаголы в Git не синонимы: revert никогда не трогает прошлое, reset его переписывает. Скажете не то слово коллеге — получите не ту команду. Вся развилка, как чек-лист:
- Не отправлен, поправить и перекоммитить →
git reset --soft HEAD~1 - Не отправлен, переиндексировать выборочно →
git reset HEAD~1(mixed) - Хочу, чтобы изменения исчезли полностью →
git reset --hard HEAD~1(reflog знает, если пожалеете) - Уже отправлен на общую ветку →
git revert HEAD - Коммит должен быть на другой ветке →
cherry-pick, не отменяйте
Хотите, чтобы за вас решили? Генератор git-undo задаёт эти вопросы и печатает команду. И последний операционный совет: если плохой коммит всё же доехал до сервера — кривой deploy-хук, разбушевавшийся CI-раннер после force-push — следующее место поиска — логи машины, а не Git: на любой systemd-машине journalctl -u <service> -n 100 shows you exactly what ran and when. And when Git refuses to run at all — fatal: not a git repository — that is a different problem from undoing anything.
конец страницы отмены · ничего не скачано · всё локально