git reflog: cara memulihkan commit dan branch yang hilang
git reflog adalah jurnal lokal tempat Git mencatat setiap perpindahan HEAD dan branch: commit, reset, checkout, rebase, merge. Cari di git reflog entri sebelum kesalahan terjadi, misalnya HEAD@{2}, lalu kembalikan keadaan dengan git reset --hard HEAD@{2} atau buat branch dengan git branch rescue HEAD@{2}.
git reflog adalah jurnal referensi (reference log): Git mencatat di dalamnya setiap perpindahan HEAD dan ujung branch. Anda membuat commit, berpindah branch, menjalankan reset, rebase, atau merge — reflog akan mendapat satu baris berisi hash yang ditunjuk referensi setelah operasi tersebut. Karena itu, bahkan commit yang sudah tidak dirujuk oleh branch mana pun masih bisa ditemukan dan dikembalikan.
Hal terpenting yang perlu diketahui: reflog bersifat lokal. Ia hanya ada di clone Anda, tidak dikirim ke server, dan tidak ikut saat git clone. Namun di repositori Anda sendiri, reflog menyelamatkan Anda dari hampir semua kesalahan pada riwayat.
Cara membaca output git reflog
git reflog
3c4d5e6 (HEAD -> main) HEAD@{0}: reset: moving to HEAD~2
9a8b7c6 HEAD@{1}: commit: Tambahkan validasi e-mail
1f2e3d4 HEAD@{2}: commit: Pindahkan konfigurasi ke file terpisah
3c4d5e6 (HEAD -> main) HEAD@{3}: checkout: moving from feature to main
7b6a5c4 (feature) HEAD@{4}: commit: Draf form login
Setiap baris adalah satu keadaan HEAD, yang terbaru di paling atas:
- hash — commit yang ditunjuk HEAD setelah operasi;
- HEAD@{n} — «di mana HEAD berada n perpindahan yang lalu»; ini referensi lengkap yang bisa diberikan ke perintah apa pun;
- deskripsi — jenis operasi (commit, reset, checkout, rebase, merge, pull, cherry-pick, commit (amend)) beserta detailnya.
Dari contoh terlihat: dua commit — «Pindahkan konfigurasi» dan «Tambahkan validasi» — sudah dibuat, lalu reset HEAD~2 memundurkan branch. Di git log keduanya sudah tidak ada, tetapi di reflog masih tersimpan.
Reflog untuk branch tertentu
Setiap branch punya jurnalnya sendiri. Jurnal ini lebih pendek dan lebih berguna ketika Anda sering berpindah-pindah branch:
git reflog show feature
git reflog show origin/main # bagaimana branch remote berubah saat fetch
Referensi berdasarkan waktu
Selain nomor, Anda bisa menyebut titik waktu — Git akan mencari ke mana referensi menunjuk saat itu:
git show main@{yesterday}
git diff main@{"2 hours ago"} main
git log -g --since="1 day ago" --oneline
Flag -g (--walk-reflogs) pada git log menelusuri reflog alih-alih hubungan parent, sehingga Anda bisa memakai format dan filter yang sudah biasa. Untuk menampilkan tanggal, gunakan git reflog --date=iso.
Cara mengembalikan commit setelah git reset --hard
Situasi paling umum: Anda menjalankan git reset --hard ke commit yang salah, dan pekerjaan Anda «hilang». Sebenarnya commit itu tidak ke mana-mana — hanya tidak terlihat dari branch.
- Buka jurnal:
git reflog. - Temukan baris tepat sebelum
reset: moving to ...— itulah keadaan sebelum kesalahan. Pada contoh di atas:HEAD@{1}dengan hash9a8b7c6. - Pastikan itu yang benar:
git log --oneline -5 HEAD@{1}. - Kembalikan branch:
git reset --hard HEAD@{1}.
git reset --hard HEAD@{1}
HEAD is now at 9a8b7c6 Tambahkan validasi e-mail
Hati-hati: setelah setiap operasi, nomornya bergeser. Yang tadinya HEAD@{1}, setelah reset menjadi HEAD@{2}. Karena itu, lebih aman menyalin hash daripada nomor.
Batasan penting: reflog hanya menyimpan yang sudah di-commit. Perubahan yang belum di-commit dan terhapus oleh reset --hard atau git checkout -- file tidak bisa dikembalikan lewat reflog. Masih ada sedikit harapan jika file tersebut sudah ditambahkan ke index — bahasannya ada di bawah.
Cara memulihkan branch yang terhapus
Anda menghapus branch dengan git branch -D feature, padahal di dalamnya ada commit yang belum di-push. Jurnal branch itu ikut terhapus, tetapi jurnal HEAD tetap ada — dan HEAD pernah berada di commit-commit branch tersebut saat Anda mengerjakannya.
git reflog | grep feature
7b6a5c4 HEAD@{4}: commit: Draf form login
3c4d5e6 HEAD@{3}: checkout: moving from feature to main
# Commit terakhir branch — commit tempat Anda meninggalkannya
git branch feature 7b6a5c4
Cari baris checkout: moving from feature to ...: hash pada entri sebelumnya (lebih bawah dalam daftar) adalah keadaan terakhir branch. Omong-omong, saat menghapus, Git sendiri mencetak hash-nya: Deleted branch feature (was 7b6a5c4). — jika terminal masih terbuka, itu sudah cukup.
Cara membatalkan rebase yang gagal
Rebase menulis ulang commit, dan jika Anda salah menyelesaikan konflik di tengah prosesnya, hasilnya bisa lebih buruk daripada aslinya. Reflog menyimpan keadaan sebelum rebase dimulai.
git reflog
e1f2a3b HEAD@{0}: rebase (finish): returning to refs/heads/feature
e1f2a3b HEAD@{1}: rebase (pick): Draf form login
c4d5e6f HEAD@{2}: rebase (start): checkout main
7b6a5c4 HEAD@{3}: commit: Draf form login
git reset --hard HEAD@{3}
Yang Anda perlukan adalah entri sebelum rebase (start). Ada juga jalan pintas: sebelum operasi berisiko (rebase, merge, reset), Git menyimpan posisi sebelumnya di referensi ORIG_HEAD, jadi tepat setelah rebase Anda bisa menjalankan git reset --hard ORIG_HEAD. Namun ORIG_HEAD akan ditimpa oleh operasi serupa berikutnya, sedangkan reflog menyimpan seluruh riwayat.
Cara mengembalikan commit sebelum git commit --amend
--amend tidak mengubah commit, melainkan membuat commit baru sebagai penggantinya. Commit lama tetap ada di reflog:
git reflog
5a6b7c8 HEAD@{0}: commit (amend): Tambahkan validasi e-mail
9a8b7c6 HEAD@{1}: commit: Tambahkan validasi e-mail
git diff HEAD@{1} HEAD # apa yang diubah oleh amend
git reset --soft HEAD@{1} # kembalikan commit lama, perubahan amend tetap di index
Pemulihan yang aman: branch, bukan reset
Jika Anda tidak yakin commit mana yang dibutuhkan, jangan menjalankan reset --hard secara membabi buta. Buat branch penyelamat — ini tidak merusak apa pun dan melindungi commit yang ditemukan dari penghapusan:
git branch rescue HEAD@{5}
git log --oneline rescue
git switch rescue
Setelah itu, commit dari rescue bisa dipindahkan dengan cherry-pick atau di-merge, lalu branch-nya dihapus setelah semuanya kembali normal.
Berapa lama reflog disimpan
Entri reflog tidak abadi. Entri dibersihkan oleh git gc, yang dijalankan Git sendiri secara berkala. Batas waktunya diatur lewat konfigurasi:
| Konfigurasi | Default | Artinya |
|---|---|---|
gc.reflogExpire | 90 hari | Batas untuk entri dengan commit yang masih dapat dijangkau dari branch saat ini |
gc.reflogExpireUnreachable | 30 hari | Batas untuk entri dengan commit yang tidak dapat dijangkau dari branch mana pun — justru yang «hilang» |
gc.pruneExpire | 2 minggu | Kapan objek tak terjangkau yang sudah tidak dirujuk apa pun benar-benar dihapus |
Kesimpulan praktisnya: commit yang hilang dijamin bisa diakses lewat reflog sekitar satu bulan. Jangan menunda pemulihan, dan jangan menjalankan git gc --prune=now atau git reflog expire --expire=now --all secara manual sebelum yang Anda butuhkan kembali.
Jika reflog tidak membantu: git fsck
Ada kasus ketika commit tidak tercatat di reflog: misalnya dibuat oleh git stash, lalu stash dihapus dengan git stash drop, atau perubahan hanya ada di index. Dalam kasus ini, carilah objek «dangling» (menggantung):
git fsck --lost-found
dangling commit 2b3c4d5e6f...
dangling blob 8e9f0a1b2c...
git show 2b3c4d5e6f # lihat isinya
git branch recovered 2b3c4d5e6f
Commit dangling dari stash yang dihapus berisi pesan «WIP on ...». Blob dangling adalah isi file yang pernah ditambahkan dengan git add tetapi tidak di-commit. Blob tidak punya nama file, jadi Anda harus mengenalinya dari isinya — namun dengan cara ini kadang pekerjaan setelah reset --hard bisa diselamatkan. Dengan flag --lost-found, Git juga menyalinnya ke .git/lost-found/.
Apa yang tidak bisa dilakukan reflog
- Tidak bekerja antar-mesin. Jika rekan kerja melakukan force push dan menimpa commit Anda di server, carilah commit itu di reflog orang yang memilikinya secara lokal — misalnya
git reflog show origin/mainpada siapa saja yang melakukan fetch sebelum penimpaan. - Tidak melihat yang belum di-commit. Karena itu, asuransi terbaik sebelum operasi berisiko adalah commit atau
git stash. - Tidak menyimpan riwayat selamanya. Batas waktunya ada di atas, ditambah clone baru selalu dimulai dengan jurnal kosong.
Praktik: pengaman sebelum operasi berisiko
Reflog memang menyelamatkan, tetapi pemulihan lewat reflog butuh ketelitian: Anda harus menemukan entri yang tepat di antara puluhan entri yang mirip. Jauh lebih mudah memasang penanda terlebih dahulu. Sebelum rebase, reset besar, atau eksperimen dengan riwayat, buat branch atau tag sementara:
git branch backup/before-rebase
git rebase -i main
# ada yang salah
git reset --hard backup/before-rebase
# semuanya berhasil
git branch -D backup/before-rebase
Hanya butuh satu perintah dan Anda tidak perlu mencari-cari hash. Reflog tetap menjadi cadangan untuk saat Anda baru teringat pengaman ketika sudah terlambat.
Cara cepat menemukan entri yang tepat
Di jurnal yang panjang, filter sangat membantu. Cari berdasarkan jenis operasi atau teks pesan commit, dan untuk kasus yang meragukan, periksa isinya:
git reflog | grep -E "reset|rebase \(start\)"
git log -g --grep="validasi" --oneline
git show --stat HEAD@{7}
Perintah git log -g dengan --grep mencari di pesan commit dari reflog, sedangkan git show --stat menampilkan file yang terdampak — dari situ commit yang tepat mudah dikenali, bahkan jika pesannya tidak informatif seperti «wip».
Kesimpulan
git reflog adalah jaring pengaman Git: semua yang di-commit di repositori Anda dalam beberapa minggu terakhir bisa ditemukan dan dikembalikan. Urutannya selalu sama: buka jurnal, temukan entri sebelum kesalahan, periksa dengan git log atau git show, lalu buat branch atau jalankan reset --hard. Penggunaan restore, reset, revert, dan pemulihan setelah kesalahan dibahas secara praktis di kursus Git.
Pertanyaan umum
Apa bedanya git reflog dengan git log?
git log menelusuri hubungan parent antar-commit dan menampilkan riwayat branch. git reflog menampilkan ke mana HEAD dan branch berpindah di repositori Anda, termasuk commit yang sudah tidak ada di riwayat branch.
Apakah reflog ikut terkirim ke GitHub atau GitLab?
Tidak, reflog hanya disimpan di folder lokal .git/logs dan tidak dikirim saat push maupun clone.
Bisakah reflog dibersihkan?
Bisa, dengan perintah git reflog expire --expire=now --all diikuti git gc --prune=now, tetapi setelah itu commit yang hilang tidak bisa dipulihkan lagi.
Di mana reflog disimpan secara fisik?
Di file teks .git/logs/HEAD dan .git/logs/refs/heads/nama-branch, satu baris untuk setiap perpindahan.
Apakah reflog berfungsi di repositori bare di server?
Secara default reflog dinonaktifkan di repositori bare (core.logAllRefUpdates), jadi di server Anda tidak bisa mengandalkannya.
Topik ini dibahas mendalam dengan praktik di kursus “Git dari Nol hingga Pengembang Percaya Diri”.
Ke kursus