Пошук уроків, статей та іншого контенту
Використаєте reflog, щоб знайти попередні стани HEAD, гілок і комітів після небезпечних операцій.
reflog — це локальний журнал переміщення посилань Git. Він показує, куди раніше вказували:
HEAD;
локальні гілки;
інші локальні посилання.
Коли виконується commit, reset, checkout, merge, rebase або переміщується вказівник гілки, Git записує попередній і новий коміти до reflog.
Завдяки цьому можна знайти коміт, який більше не видно у звичайній історії гілки, і відновити роботу після небезпечної операції.
Reflog — це не історія всіх комітів у репозиторії. Це журнал того, як змінювалися посилання у локальному репозиторії.
Для перегляду журналу HEAD використовуйте:
git reflogПриклад результату:
a1b2c3d HEAD@{0}: reset: moving to HEAD~1
f4e5d6c HEAD@{1}: commit: Add validation
9a8b7c6 HEAD@{2}: commit: Add user formКожен запис містить:
скорочений ідентифікатор коміту;
спеціальне позначення позиції в reflog, наприклад HEAD@{1};
операцію, яка змінила посилання;
опис операції.
У цьому прикладі:
HEAD@{0} — поточний стан;
HEAD@{1} — попередній стан до reset;
HEAD@{2} — ще старіший стан.
HEAD@{1} — не назва коміту, а спосіб звернутися до запису журналу. Після нових операцій номери записів можуть змінитися, тому для важливих дій краще спочатку перевірити ідентифікатор коміту.
Щоб подивитися, як змінювалася локальна гілка:
git reflog show mainАбо коротше:
git reflog mainЦе відрізняється від:
git reflogКоманда git reflog показує переміщення HEAD, а git reflog main — переміщення посилання main.
Подивитися позицію гілки в конкретний момент можна так:
git show main@{1}Також можна використати дату:
git show main@{"yesterday"}Формат із датою залежить від оболонки. У деяких оболонках лапки потрібно екранувати.
git loggit log показує коміти, до яких можна дістатися з поточного посилання:
git log --onelineЯкщо після git reset --hard гілка перестала вказувати на коміт, той коміт може зникнути з git log поточної гілки.
git reflog у такій ситуації часто все ще містить попереднє положення HEAD:
git reflogТому ці команди відповідають на різні запитання:
git log — які коміти входять у доступну історію;
git reflog — куди раніше переміщувалися локальні посилання.
git reset --hardРозглянемо типову ситуацію.
Спочатку в гілці є кілька комітів:
A -- B -- C -- D (main)Потім виконано:
git reset --hard HEAD~2Тепер гілка виглядає так:
A -- B (main)
C -- D # коміти більше не досяжні з mainКоміти C і D не обов’язково видалені одразу. Їх можна знайти через reflog:
git reflogМожливий результат:
b111111 HEAD@{0}: reset: moving to HEAD~2
d444444 HEAD@{1}: commit: Fix checkout
c333333 HEAD@{2}: commit: Add checkoutПеред відновленням перевірте знайдений коміт:
git show d444444Якщо це потрібний стан, створіть від нього нову гілку:
git switch -c recovered-work d444444Тепер коміт знову досяжний через гілку recovered-work.
Якщо потрібно повернути саму main до цього коміту:
git switch main
git reset --hard d444444Безпечніший варіант — спочатку створити резервну гілку:
git branch backup-main main
git reset --hard d444444Нижче наведено послідовність команд для локального тестового репозиторію:
mkdir reflog-demo
cd reflog-demo
git init
git config user.name "Demo User"
git config user.email "demo@example.com"
printf "one\n" > file.txt
git add file.txt
git commit -m "Initial commit"
printf "two\n" >> file.txt
git commit -am "Add second line"
printf "three\n" >> file.txt
git commit -am "Add third line"
# Небезпечне переміщення гілки на два коміти назад
git reset --hard HEAD~2
# Перегляд попередніх положень HEAD
git reflog
# Створення гілки з втраченого коміту
git switch -c recovered-work HEAD@{1}
# Перевірка відновленої історії
git log --oneline --decorate --allУ цьому прикладі HEAD@{1} — це стан безпосередньо перед reset. На практиці перед створенням гілки перевірте цей стан командою git show HEAD@{1}.
Під час rebase Git послідовно переміщує HEAD і поточну гілку. Якщо результат виявився неправильним або конфлікти було розв’язано помилково, reflog допомагає знайти стан до початку операції.
Перегляньте журнал:
git reflogТиповий фрагмент може мати такий вигляд:
7f7f7f7 HEAD@{0}: rebase (finish): returning to refs/heads/feature
7f7f7f7 HEAD@{1}: rebase (pick): Add tests
4e4e4e4 HEAD@{2}: rebase (pick): Add validation
9d9d9d9 HEAD@{3}: rebase (start): checkout main
2a2a2a2 HEAD@{4}: checkout: moving from main to featureСтан безпосередньо перед rebase у цьому прикладі — feature на записі HEAD@{4}. Спочатку перевірте його:
git show HEAD@{4}Створіть резервну гілку:
git branch feature-before-rebase HEAD@{4}Якщо потрібно повернути поточну гілку:
git reset --hard feature-before-rebaseНазви та номери записів залежать від конкретної історії. Не копіюйте HEAD@{4} без перевірки: у вашому reflog потрібний запис може мати інший номер.
Якщо локальну гілку видалено командою:
git branch -D featureїї назву більше не буде показано через:
git branchАле коміти, на які вона вказувала, можуть залишатися в reflog HEAD або іншої гілки.
Знайдіть останнє положення гілки:
git reflog --allУ результаті можна побачити рядок на кшталт:
abc1234 refs/heads/feature@{0}: commit: Add searchПісля цього відновіть гілку за ідентифікатором коміту:
git switch -c feature abc1234Якщо вивід не містить потрібного рядка, перегляньте reflog HEAD:
git reflogта знайдіть коміт, який був останнім у видаленій гілці.
Після пошуку кандидата перевірте його вміст:
git show <commit>Наприклад:
git show abc1234Перевірити кілька комітів навколо нього можна так:
git log --oneline --decorate --all abc1234Коли коміт підтверджено, створіть посилання на нього:
git branch rescue abc1234Створення гілки — кращий перший крок, ніж негайний reset --hard. Воно зберігає знайдений стан і дає змогу спокійно порівняти його з поточною історією.
Порівняння можна виконати так:
git diff main..rescueReflog має кілька важливих обмежень:
він зберігається локально;
reflog одного клону не передається на сервер під час push;
на іншому комп’ютері такого самого журналу може не бути;
старі записи з часом можуть бути автоматично видалені під час очищення Git;
reflog не є заміною резервним копіям або віддаленому репозиторію.
Якщо коміт було успішно опубліковано у віддаленому репозиторії, його можна шукати також у віддалених посиланнях. Але локальний reflog і журнал віддаленого сервера — різні механізми.
Після небезпечної операції дійте послідовно:
Не виконуйте зайвих reset, rebase або очищення репозиторію.
Перегляньте reflog:
git reflog --allЗнайдіть стан до проблемної операції.
Перевірте кандидат:
git show <commit>Створіть тимчасову гілку:
git branch rescue <commit>Перегляньте відновлену історію та файли.
Лише після перевірки вирішуйте, чи потрібно переміщати основну гілку.
Reflog зберігається в конкретному локальному репозиторії. Інший розробник не побачить ваші записи reflog.
git loggit log не призначений для пошуку станів, від яких гілку вже відсунули. Для цього спочатку перевіряйте git reflog.
reset --hardПісля знаходження коміту не обов’язково відразу змінювати поточну гілку. Спочатку створіть резервну або відновлювальну гілку:
git branch rescue <commit>HEAD@{n} надовгоНомер запису відносний. Після нової операції значення HEAD@{1} може позначати вже інший стан. Для важливих дій використовуйте перевірений ідентифікатор коміту.
Якщо запис reflog уже видалено, а коміт недоступний з інших посилань, відновлення може бути неможливим. Тому після знаходження потрібного коміту одразу створіть гілку або інше посилання на нього.
git reflog показує попередні положення локальних посилань.
HEAD@{0} — поточний запис, а старші номери вказують на попередні стани.
Reflog допомагає відновити коміти після reset --hard, невдалого rebase або видалення локальної гілки.
Перед відновленням перевіряйте кандидат командою git show.
Найбезпечніший перший крок — створити нову гілку з потрібного коміту.
Reflog локальний і не замінює резервне копіювання чи віддалений репозиторій.