git branches

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 перемещён сброшен сброшен

Синтаксис

# Сбросить HEAD на N коммитов назад (mixed по умолчанию) git reset HEAD~<N> git reset HEAD~1 # Режимы сброса git reset --soft HEAD~1 git reset --mixed HEAD~1 # то же, что без флага git reset --hard HEAD~1 # Сбросить до конкретного коммита git reset --hard <хеш-коммита> # Убрать файлы из индекса (unstage) git reset HEAD <файл> git reset -- <файл> # Убрать все файлы из индекса git reset HEAD # Сбросить до состояния remote-ветки git reset --hard origin/main

Флаги и опции

Флаг Описание
--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

Советы и подводные камни

reflog — ваша страховка: даже после git reset --hard коммиты не исчезают немедленно. Git хранит reflog — журнал всех перемещений HEAD — как правило 30–90 дней. Выполните git reflog, найдите нужный хеш и восстановите через git reset --hard <хеш> или создав новую ветку.
git restore как современная альтернатива: в Git 2.23+ для операций с файлами рекомендуется git restore --staged <файл> вместо git reset HEAD <файл>. Команда более явная и безопасная: она работает только с файлами, не перемещая HEAD.
Никогда не делайте reset --hard на опубликованных ветках: если вы отправили коммиты на remote и затем сделали git reset --hard + git push --force, вы уничтожите историю для всех участников команды. Для публичных веток используйте git revert — он создаёт новый отменяющий коммит, не переписывая историю.