git reflog: paano ibalik ang nawalang commit at branch
Ang git reflog ay lokal na journal kung saan itinatala ng Git ang bawat paggalaw ng HEAD at mga branch: commit, reset, checkout, rebase, merge. Hanapin sa git reflog ang entry bago ang pagkakamali, halimbawa HEAD@{2}, at ibalik ang estado gamit ang git reset --hard HEAD@{2}, o gumawa ng branch gamit ang git branch rescue HEAD@{2}.
Ang git reflog ay reference log: itinatala ng Git dito ang bawat paggalaw ng HEAD at ng dulo ng mga branch. Gumawa kayo ng commit, lumipat ng branch, nagpatakbo ng reset, rebase, o merge: may lumitaw na linya sa reflog na may hash kung saan tumuturo ang reference pagkatapos ng operasyon. Kaya kahit ang commit na wala nang branch na tumuturo rito ay mahahanap at maibabalik.
Ang dapat tandaan: lokal ang reflog. Nasa clone ninyo lang ito, hindi ipinapadala sa server, at hindi dumarating sa git clone. Pero sa sarili ninyong repository, sinasagip nito kayo mula sa halos anumang pagkakamali sa history.
Paano basahin ang output ng git reflog
git reflog
3c4d5e6 (HEAD -> main) HEAD@{0}: reset: moving to HEAD~2
9a8b7c6 HEAD@{1}: commit: Idagdag ang validation ng e-mail
1f2e3d4 HEAD@{2}: commit: Ilabas ang config sa hiwalay na file
3c4d5e6 (HEAD -> main) HEAD@{3}: checkout: moving from feature to main
7b6a5c4 (feature) HEAD@{4}: commit: Draft ng login form
Bawat linya ay isang estado ng HEAD, pinakabago ang nasa itaas:
- hash: ang commit kung saan tumuturo ang HEAD pagkatapos ng operasyon;
- HEAD@{n}: "saan naroon ang HEAD n galaw na ang nakalipas"; buong reference ito at puwedeng ibigay sa anumang command;
- paglalarawan: uri ng operasyon (commit, reset, checkout, rebase, merge, pull, cherry-pick, commit (amend)) at mga detalye.
Sa halimbawa, makikita na dalawang commit, ang "Ilabas ang config" at "Idagdag ang validation", ay nagawa, at pagkatapos ay inatras ng reset HEAD~2 ang branch. Wala na sila sa git log, pero nasa reflog pa.
Reflog ng partikular na branch
May sariling journal ang bawat branch. Mas maikli at mas kapaki-pakinabang ito kapag madalas kayong lumilipat sa pagitan ng mga branch:
git reflog show feature
git reflog show origin/main # paano nagbago ang remote branch sa bawat fetch
Mga reference ayon sa oras
Sa halip na numero, puwede ring magbigay ng panahon. Hahanapin ng Git kung saan tumuturo ang reference noon:
git show main@{yesterday}
git diff main@{"2 hours ago"} main
git log -g --since="1 day ago" --oneline
Ang flag na -g (--walk-reflogs) sa git log ay dumaraan sa reflog sa halip na sa mga ugnayan ng parent, at pinapayagan ang mga pamilyar na format at filter. Para makita ang petsa, kapaki-pakinabang ang git reflog --date=iso.
Paano ibalik ang commit pagkatapos ng git reset --hard
Pinakakaraniwang sitwasyon: nagpatakbo kayo ng git reset --hard sa maling commit, at tila nawala ang trabaho. Sa katotohanan, hindi nawala ang mga commit; hindi lang sila makikita mula sa mga branch.
- Buksan ang journal:
git reflog. - Hanapin ang linyang bago ang
reset: moving to ...: ito ang estado bago ang pagkakamali. Sa halimbawa sa itaas, angHEAD@{1}na may hash na9a8b7c6. - I-verify na tama ito:
git log --oneline -5 HEAD@{1}. - Ibalik ang branch:
git reset --hard HEAD@{1}.
git reset --hard HEAD@{1}
HEAD is now at 9a8b7c6 Idagdag ang validation ng e-mail
Mag-ingat: nagbabago ang mga numero pagkatapos ng bawat operasyon. Ang dating HEAD@{1} ay magiging HEAD@{2} pagkatapos ng reset. Kaya mas ligtas na kopyahin ang hash kaysa umasa sa numero.
Mahalagang limitasyon: tanging ang mga naka-commit ang nasa reflog. Ang mga hindi pa naka-commit na pagbabagong binura ng reset --hard o git checkout -- file ay hindi na maibabalik sa pamamagitan ng reflog. May kaunting pag-asa kung naidagdag na ang mga file sa index: tingnan sa ibaba.
Paano ibalik ang nabuburang branch
Binura ninyo ang branch gamit ang git branch -D feature, at may mga commit itong hindi pa naipapadala. Nabubura kasama ng branch ang journal nito, pero nananatili ang journal ng HEAD, at napuntahan ng HEAD ang mga commit na iyon noong nagtatrabaho pa kayo rito.
git reflog | grep feature
7b6a5c4 HEAD@{4}: commit: Draft ng login form
3c4d5e6 HEAD@{3}: checkout: moving from feature to main
# Ang huling commit ng branch ay ang umalis ka rito
git branch feature 7b6a5c4
Hanapin ang linyang checkout: moving from feature to ...: ang hash sa naunang entry (mas mababa sa listahan) ang huling estado ng branch. Sa pagbura, ipinapakita rin mismo ng Git ang hash: Deleted branch feature (was 7b6a5c4). Kung bukas pa ang terminal, sapat na iyon.
Paano i-undo ang maling rebase
Binabago ng rebase ang mga commit, at kung mali ang pag-aayos ninyo ng conflict, puwedeng mas masama ang kinalabasan kaysa sa orihinal. Itinatago ng reflog ang estado bago magsimula ang rebase.
git reflog
e1f2a3b HEAD@{0}: rebase (finish): returning to refs/heads/feature
e1f2a3b HEAD@{1}: rebase (pick): Draft ng login form
c4d5e6f HEAD@{2}: rebase (start): checkout main
7b6a5c4 HEAD@{3}: commit: Draft ng login form
git reset --hard HEAD@{3}
Kailangan ang entry bago ang rebase (start). May mas maikling daan din: bago ang mga mapanganib na operasyon (rebase, merge, reset), itinatala ng Git ang dating posisyon sa reference na ORIG_HEAD, kaya sa agarang pagkakataon pagkatapos ng rebase, gagana ang git reset --hard ORIG_HEAD. Pero na-o-overwrite ang ORIG_HEAD ng susunod na ganitong operasyon, samantalang buo ang kasaysayan ng reflog.
Paano ibalik ang commit bago ang git commit --amend
Hindi binabago ng --amend ang commit; gumagawa ito ng bago sa lugar nito. Nananatili ang luma sa reflog:
git reflog
5a6b7c8 HEAD@{0}: commit (amend): Idagdag ang validation ng e-mail
9a8b7c6 HEAD@{1}: commit: Idagdag ang validation ng e-mail
git diff HEAD@{1} HEAD # ano ang binago ng amend
git reset --soft HEAD@{1} # ibalik ang lumang commit, mananatili ang mga pagbabago ng amend sa index
Ligtas na pagbawi: branch sa halip na reset
Kung hindi kayo sigurado kung aling commit ang kailangan, huwag magpatakbo ng reset --hard nang bulag. Gumawa ng rescue branch: hindi ito nakakasira ng anuman, at pinoprotektahan nito ang nahanap na commit laban sa pagbura:
git branch rescue HEAD@{5}
git log --oneline rescue
git switch rescue
Pagkatapos, puwedeng ilipat ang mga commit ng rescue gamit ang cherry-pick o i-merge, at burahin ang branch kapag bumalik na ang lahat sa dapat nitong kinalalagyan.
Gaano katagal nananatili ang reflog
Hindi permanente ang mga entry. Binubura ang mga ito ng git gc, na awtomatikong pinapatakbo ng Git paminsan-minsan. Itinatakda ng mga setting ang mga takdang panahon:
| Setting | Default | Ibig sabihin |
|---|---|---|
gc.reflogExpire | 90 araw | Panahon para sa mga entry na may commit na naaabot mula sa kasalukuyang branch |
gc.reflogExpireUnreachable | 30 araw | Panahon para sa mga entry na may commit na hindi naaabot ng alinmang branch, ang mga "nawala" |
gc.pruneExpire | 2 linggo | Pagkatapos ng ilang panahon, binubura nang tuluyan ang mga hindi naaabot na object na wala nang tumuturo |
Praktikal na konklusyon: ang nawalang commit ay tiyak na mahahanap sa pamamagitan ng reflog nang humigit-kumulang isang buwan. Huwag ipagpaliban ang pagbawi, at huwag manu-manong patakbuhin ang git gc --prune=now o git reflog expire --expire=now --all hangga't hindi pa naibabalik ang kailangan.
Kapag hindi nakatulong ang reflog: git fsck
May mga sitwasyong wala sa reflog ang commit: halimbawa, ginawa ito ng git stash, at binura ang stash gamit ang git stash drop, o nasa index lang ang mga pagbabago. Sa ganitong kaso, hanapin ang mga "nakabiting" object:
git fsck --lost-found
dangling commit 2b3c4d5e6f...
dangling blob 8e9f0a1b2c...
git show 2b3c4d5e6f # tingnan ang nilalaman
git branch recovered 2b3c4d5e6f
Ang mga nakabiting commit mula sa binurang stash ay may mensaheng "WIP on ...". Ang mga nakabiting blob naman ay nilalaman ng mga file na minsang idinagdag sa git add pero hindi naka-commit. Walang pangalan ng file ang mga ito, kaya kailangang kilalanin sa nilalaman, pero sa ganitong paraan minsan nasasagip ang trabaho pagkatapos ng reset --hard. Gamit ang flag na --lost-found, kinokopya rin ng Git ang mga ito sa .git/lost-found/.
Ano ang hindi kayang gawin ng reflog
- Hindi gumagana sa pagitan ng mga makina. Kung nag-force push ang katrabaho at nabura ang mga commit ninyo sa server, hanapin ang mga ito sa reflog ng sinumang may lokal na kopya, halimbawa
git reflog show origin/mainsa kahit sinong nag-fetch bago ang pagbura. - Hindi nakikita ang hindi pa naka-commit. Kaya ang pinakamagandang insurance bago ang mapanganib na operasyon ay commit o
git stash. - Hindi nag-iimbak nang walang hanggan. Totoo ang mga takdang panahon sa itaas, at nagsisimula ang sariwang clone na walang laman na journal.
Praktika: insurance bago ang mapanganib na operasyon
Nakakatulong ang reflog, pero nangangailangan ng pag-iingat ang pagbawi dito: kailangang hanapin ang tamang entry sa gitna ng dose-dosenang katulad. Mas madali kung maglalagay kayo ng marka nang maaga. Bago ang rebase, malaking reset, o eksperimento sa history, gumawa ng pansamantalang branch o tag:
git branch backup/before-rebase
git rebase -i main
# may nagkamali
git reset --hard backup/before-rebase
# naging maayos
git branch -D backup/before-rebase
Isang command lang ito at iniiwasan nito ang paghahanap ng hash. Nananatili ang reflog bilang backup kung sakaling nakalimutan ninyong gumawa ng insurance.
Paano mabilis na mahanap ang tamang entry
Sa mahabang journal, nakakatulong ang pag-filter. Maghanap ayon sa uri ng operasyon o teksto ng mensahe ng commit, at kapag may duda, tingnan ang nilalaman:
git reflog | grep -E "reset|rebase \(start\)"
git log -g --grep="validation" --oneline
git show --stat HEAD@{7}
Hinahanap ng git log -g na may --grep ang mga mensahe ng commit mula sa reflog, at ipinapakita ng git show --stat kung aling mga file ang apektado. Sa pamamagitan nito, madaling matukoy ang tamang commit kahit malabo ang mensahe, gaya ng "wip".
Buod
Ang git reflog ang safety net ng Git: lahat ng naka-commit sa repository ninyo sa nakaraang ilang linggo ay mahahanap at maibabalik. Iisa ang takbo ng pagkilos: buksan ang journal, hanapin ang entry bago ang pagkakamali, i-verify ito gamit ang git log o git show, at saka gumawa ng branch o reset --hard. Ang pagbawi pagkatapos ng restore, reset, revert, at iba pang pagkakamali ay itinuturo nang praktikal sa kursong Git namin.
Mga madalas itanong
Ano ang pagkakaiba ng git reflog at git log?
Dumaraan ang git log sa mga ugnayan ng parent ng mga commit at ipinapakita ang history ng branch. Ipinapakita ng git reflog kung saan lumipat ang HEAD at mga branch sa repository ninyo, kasama ang mga commit na wala na sa history ng mga branch.
Napupunta ba ang reflog sa GitHub o GitLab?
Hindi, nakaimbak lang ito sa lokal na folder na .git/logs at hindi naipapadala sa push o clone.
Puwede bang burahin ang reflog?
Oo, gamit ang git reflog expire --expire=now --all at pagkatapos ang git gc --prune=now, pero pagkatapos nito, hindi na maibabalik ang mga nawalang commit.
Saan physically nakaimbak ang reflog?
Sa mga text file na .git/logs/HEAD at .git/logs/refs/heads/pangalan-ng-branch, may isang linya para sa bawat galaw.
Gumagana ba ang reflog sa bare repository sa server?
Bilang default, naka-disable ang reflog sa bare repository (core.logAllRefUpdates), kaya huwag itong asahan sa server.
Detalyadong tinatalakay ang paksang ito, may praktis, sa kursong “Git с нуля до уверенного разработчика”.
Pumunta sa kurso