Reflog отвечает на вопрос «где была HEAD пять минут назад» и потому позволяет восстановить почти любое состояние, в котором ты успел побывать недавно.
Базовая форма
git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~3# 4d5e6f7 HEAD@{1}: commit: feat: add login# 8a9b0c1 HEAD@{2}: commit: docs: update README# ...
Каждая строка - состояние HEAD на момент действия. Чем выше - тем свежее. Колонки: SHA → синтаксический указатель → причина.
Самый частый сценарий
После катастрофического reset:
git reset --hard HEAD~10 # ой, не туда
git reflog # первая строка показывает SHA после reset,
# вторая - SHA до reset
git reset --hard HEAD@{1} # вернуться в состояние до resetИли явно по SHA:
git reset --hard 4d5e6f7 # из reflog
Что покрывает
Reflog запоминает практически все операции, двигающие HEAD:
commit,commit --amendcheckout/switchмежду веткамиmerge,rebase(целая серия записей)reset --hard,reset --softpull(через свой merge/rebase двигает HEAD; чистыйfetchHEAD не трогает - он обновляет толькоrefs/remotes/*, и у тех есть свой отдельный reflog)- Создание/удаление веток через
branch -d/-D(последняя позиция той ветки)
Также есть отдельный reflog у каждой ветки:
git reflog show feature # история позиций ветки feature
git reflog show HEAD # == git reflog
Когда reflog НЕ поможет
- Незакоммиченные правки. Если файл был только в working tree или индексе, никогда не закоммичен - reflog его не видит. Reflog ловит только коммиты.
- Untracked-файлы, удалённые
git clean -fd. Тот же случай. - Чужие машины. Reflog локальный. У коллеги свой reflog, твоих действий в нём нет.
- Старше срока reflog'а. По умолчанию 90 дней для достижимых
объектов, 30 для недостижимых. После -
git gcподметает. - После явного
git gc --prune=now+git reflog expire. Эти команды стирают историю принудительно.
Поправки сроков
Если работаешь с очень долгоживущими ветками или хочешь подольше страховку:
git config --global gc.reflogExpire "180 days"
git config --global gc.reflogExpireUnreachable "90 days"
Или наоборот - выключить reflog (редко нужно, занимает место):
git config --global gc.reflogExpire 0
git config --global gc.reflogExpireUnreachable 0
Подводные камни
- HEAD@{N} ≠ HEAD~N. Первое - N-е состояние в reflog
(по времени). Второе - N-й предок коммита (по графу). Это
разные вещи.
HEAD@{yesterday},HEAD@{2.hours.ago}- синтаксис «по времени». Удобно:git diff HEAD@{1.week.ago} HEAD.- Reflog хранится в
.git/logs/- просто текстовые файлы. Можно посмотреть руками, но обычноgit reflogудобнее.
- На свежеклоненном репозитории reflog пуст. История хранится не в reflog, а в коммитах. Reflog - только про локальные движения HEAD, которых на новом clone ещё нет.