Setiap operasi yang menulis ulang riwayat — reset --hard, commit --amend, git branch -D, sampai rebase — meninggalkan mayat: objek lama yang kehilangan seluruh penunjuknya namun tetap utuh di .git/objects. Objek dangling itulah sisa operasi yang belum dibersihkan, dan justru karena Git menahannya beberapa lama sebelum dihapus, mayat-mayat itu bisa dibangkitkan. git fsck sudah mengenalkan temuan dangling commit; chapter ini menjalankan jalur penyelamatnya ujung-ke-ujung: sebuah commit “hilang” akibat rebase, reflog-nya sengaja kita tuaikan, lalu fsck menjadi satu-satunya detektor — temuan, verifikasi, dan pemulihan lengkap dengan branch baru.

Membuat Commit “Hilang” lewat Rebase #

Repository latihan-dangling menyiapkan cerita klasiknya: branch fitur berangkat dari commit kedua, sementara main berjalan duluan, lalu fitur di-rebase agar berdiri di ujung main:

bash
mkdir latihan-dangling && cd latihan-dangling
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf 'beranda\n' > situs.md
git add situs.md
git commit -m "Buat halaman beranda"
printf 'beranda\nfaq\n' > situs.md
git add situs.md
git commit -m "Tambah halaman faq"
git switch -c fitur
printf 'galeri v1\n' > galeri.md
git add galeri.md
git commit -m "Mulai halaman galeri"
git switch main
printf 'kontak v1\n' > kontak.md
git add kontak.md
git commit -m "Tambah halaman kontak"
git switch fitur
git rebase main
git log --oneline -2 fitur

Output yang Dihasilkan:

text
Successfully rebased and updated refs/heads/fitur.

Output yang Dihasilkan:

text
74102f2 Mulai halaman galeri
2ad3a53 Tambah halaman kontak

Rebase sukses dan riwayat fitur tampak normal — tapi perhatikan hashnya: Mulai halaman galeri kini bernomor 74102f2. Commit aslinya yang dulu dibuat di atas Tambah halaman faq tidak lagi dirujuk fitur — hash di mesin pembaca akan berbeda. Dari sudut pandang branch, commit lama itu sudah “hilang”.

Jaring Pertama: Reflog — dan Saat Jaring Itu Menipis #

Jaring penyelamat pertama tetap reflog : perjalanan fitur terekam lengkap,

bash
git reflog show fitur

Output yang Dihasilkan:

text
74102f2 fitur@{0}: rebase (finish): refs/heads/fitur onto 2ad3a53e09f48029f64d4a83dac6a69f28c59371
fd76e17 fitur@{1}: commit: Mulai halaman galeri
272ea05 fitur@{2}: branch: Created from HEAD

Baris fitur@{1} masih menyimpan alamat commit asli: fd76e17. Namun entri reflog tidak abadi — Git secara berkala menghapus entri lama. Kita percepat proses itu untuk melihat keadaan “insiden berumur lebih dari sebulan”, lalu periksa jaringnya lagi:

bash
git reflog expire --expire-unreachable=now --all
git reflog show fitur

Output yang Dihasilkan:

text
272ea05 fitur@{0}: branch: Created from HEAD

Dua entri lenyap sekaligus: commit: Mulai halaman galeri (menunjuk objek tak terjangkau) dan rebase (finish) (berangkat dari objek tak terjangkau). Sisa reflog fitur hanya mencatat penciptaan branch — alamat fd76e17 resmi lenyap dari tempat terakhirnya.

Jalur Penyelamat: fsck → show → branch #

Inilah momen fsck menjadi pahlawan. Database objek masih memuat segalanya:

bash
git fsck

Output yang Dihasilkan:

text
dangling commit fd76e1713a3e2f4de61a3457554dd963d16db254
bash
git fsck --unreachable

Output yang Dihasilkan:

text
unreachable tree e4f90c64b685b3194738b945c21d7ba98e3c342e
unreachable commit fd76e1713a3e2f4de61a3457554dd963d16db254

Perbandingan dua keluaran itu merangkum kembali beda dangling dan unreachable : commit fd76e17 adalah ujung rantai yang menggantung, sementara tree snapshot-nya e4f90c6 tak terjangkau tapi masih dirujuk commit itu. Blob galeri.md tidak muncul sama sekali — isi berkasnya identik, sehingga commit hasil rebase memakai ulang blob yang sama dan objeknya tetap terjangkau. Langkah verifikasi wajib sebelum memulihkan apa pun:

bash
git show fd76e17

Output yang Dihasilkan:

text
commit fd76e1713a3e2f4de61a3457554dd963d16db254
Author: Budi Santoso <[email protected]>
Date:   Sat Oct 24 10:35:00 2026 +0700

    Mulai halaman galeri

diff --git a/galeri.md b/galeri.md
new file mode 100644
index 0000000..8581b10
--- /dev/null
+++ b/galeri.md
@@ -0,0 +1 @@
+galeri v1

Isinya utuh: commit asli beserta berkas galeri.md yang dibuatnya. Pulihkan dengan branch baru — bukan reset — agar tidak satu pun ref yang digeser:

bash
git branch pulihan fd76e17
git log --oneline pulihan

Output yang Dihasilkan:

text
fd76e17 Mulai halaman galeri
272ea05 Tambah halaman faq
016e8f4 Buat halaman beranda

Commit “hilang” resmi bangkit sebagai branch pulihan. Riwayatnya memperlihatkan garis waktu lama — Tambah halaman faq tanpa Tambah halaman kontak — sesuai basis ketika commit itu dibuat. Perintah git branch tidak mencetak keluaran; bukti keberhasilannya memang dibaca dari git log.

Masa Hidup Objek Menggantung #

Seberapa lama jendela penyelamatan ini terbuka? Git menjawabnya lewat tiga pengaturan dengan nilai bawaan berikut:

PengaturanNilai bawaanEfek
gc.pruneExpire2 mingguobjek lepas lebih tua dari dua minggu boleh dihapus oleh git gc
gc.reflogExpireUnreachable30 harientri reflog yang menunjuk objek tak terjangkau dihapus setelah sebulan
gc.reflogExpire90 harientri reflog HEAD dan branch lokal dihapus setelah tiga bulan

Tabel ini adalah tabel garansi waktu: selama objek berumur kurang dari dua minggu, git gc menahannya apa pun yang terjadi; reflog umumnya menjaga lebih lama lagi. Sebaliknya, commit yang “hilang” setahun lalu tanpa cadangan berada di luar garansi — objeknya boleh sudah terhapus. Detail mekanisme pembersihannya dibahas di Garbage Collection , sementara rujukan pengaturannya ada di git-gc .

Semua senjata darurat kini terkumpul — tapi masih ada satu lapis pertahanan yang lebih baik daripada pemulihan terbaik: mencegah data benar-benar hilang dengan cadangan. Git menyediakan dua jalur resminya, clone --mirror dan git bundle, yang dibahas di Backup Repository .