git reset
Перемещение HEAD и управление индексом и рабочим каталогом
Описание
git reset перемещает указатель ветки (HEAD) на указанный коммит. В зависимости от режима команда также может изменять состояние индекса (staging area) и рабочего каталога. Это мощный, но потенциально опасный инструмент: в режиме --hard изменения безвозвратно теряются.
Ключевое отличие от git revert: reset убирает коммиты из истории (переписывает её), тогда как revert создаёт новый коммит, отменяющий изменения, и сохраняет историю нетронутой. Поэтому git reset безопасно использовать только для локальных (неопубликованных) коммитов.
Три режима reset определяют, что происходит с изменениями: soft — коммиты убираются, изменения остаются проиндексированными; mixed (по умолчанию) — коммиты убираются, изменения возвращаются в рабочий каталог (не staged); hard — коммиты убираются, изменения уничтожаются полностью.
| Режим | HEAD | Индекс (staged) | Рабочий каталог |
|---|---|---|---|
--soft |
перемещён | не изменён | не изменён |
--mixed |
перемещён | сброшен | не изменён |
--hard |
перемещён | сброшен | сброшен |
Синтаксис
Флаги и опции
| Флаг | Описание |
|---|---|
--soft |
Переместить HEAD, но оставить индекс и рабочий каталог нетронутыми. Изменения остаются staged (готовы к коммиту). |
--mixed |
Переместить HEAD и сбросить индекс, но сохранить рабочий каталог. Изменения остаются в файлах, но не staged. Режим по умолчанию. |
--hard |
Переместить HEAD, сбросить индекс И рабочий каталог. Все изменения безвозвратно уничтожаются (кроме untracked-файлов). |
--merge |
Сбросить индекс и обновить файлы, участвующие в слиянии, сохраняя незафиксированные изменения. |
--keep |
Сбросить HEAD, сохраняя локальные изменения (отказывает при конфликте) |
-p, --patch |
Интерактивно выбрать фрагменты для сброса из индекса |
-N, --intent-to-add |
Только пометить файлы как планируемые к добавлению (без сброса содержимого) |
HEAD~N |
Ссылка на N коммитов назад от HEAD |
HEAD^ |
Родитель текущего коммита (эквивалент HEAD~1) |
ORIG_HEAD |
Специальная ссылка на предыдущее значение HEAD (полезно для отмены merge/rebase) |
Паттерны использования
Отменить последний коммит (сохранить изменения)
# Вернуть изменения в staged (готово к коммиту) git reset --soft HEAD~1 # Вернуть изменения в unstaged (не staged) git reset HEAD~1 # --mixed по умолчанию # После этого можно исправить и сделать новый коммит
Убрать файл из индекса (unstage)
# Убрать один файл из staging area git reset HEAD src/config.py # Современная альтернатива (Git 2.23+) git restore --staged src/config.py # Убрать все файлы из индекса git reset HEAD
Полный сброс до remote (опасно!)
# Синхронизировать с remote origin/main git fetch origin git reset --hard origin/main # ВСЕ локальные коммиты и изменения потеряны! # Untracked файлы при этом сохраняются
Отменить merge (до коммита)
# Если merge ещё не завершён (конфликт) git merge --abort # Если merge уже закоммичен (локально) git reset --hard ORIG_HEAD # ORIG_HEAD указывает на состояние до merge
Объединить несколько коммитов в один
# "Разобрать" последние 3 коммита git reset --soft HEAD~3 # Все изменения теперь staged # Создать один итоговый коммит git commit -m "feat: complete user authentication"
Восстановить случайно сброшенные коммиты
# Найти хеш потерянного коммита
git reflog
# Например: abc1234 HEAD@{3}: commit: feat: add login
git reset --hard abc1234
# Или создать ветку от потерянного коммита
git branch recovered-work abc1234
Советы и подводные камни
git reset --hard коммиты не исчезают немедленно. Git хранит reflog — журнал всех перемещений HEAD — как правило 30–90 дней. Выполните git reflog, найдите нужный хеш и восстановите через git reset --hard <хеш> или создав новую ветку.
git restore --staged <файл> вместо git reset HEAD <файл>. Команда более явная и безопасная: она работает только с файлами, не перемещая HEAD.
git reset --hard + git push --force, вы уничтожите историю для всех участников команды. Для публичных веток используйте git revert — он создаёт новый отменяющий коммит, не переписывая историю.