git reset --hard HEAD~2 adalah perintah yang terasa seperti tombol hapus permanen: dua commit lenyap dari git log, isi berkasnya ikut hilang dari working tree, dan terminal tidak menyisakan petunjuk. Nyatanya commit yang “terhapus” itu masih utuh di dalam database objek Git — yang hilang hanyalah penunjuk menujunya, dan reflog menyimpan salinan penunjuk tersebut. Chapter ini memutar ulang skenario terburuk itu langkah demi langkah: menyimpan hash sebelum kejadian, “kehilangan” commit, menemukannya kembali di reflog, lalu memulihkannya lewat dua jalur — branch baru dan reset balik.

Skenario: reset –hard yang Menelan Dua Commit #

Repository latihan latihan-commit diisi tiga commit berurutan. Sebelum melakukan apa pun yang berisiko, hash posisi terkini disimpan ke sebuah berkas — kebiasaan sederhana yang berfungsi seperti catatan asuransi:

bash
mkdir latihan-commit && cd latihan-commit
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf 'laporan v1\n' > laporan.md
git add laporan.md
git commit -m "Tulis laporan v1"
printf 'laporan v2\n' > laporan.md
git add laporan.md
git commit -m "Perbaiki laporan"
printf 'ringkasan singkat\n' > ringkasan.md
git add ringkasan.md
git commit -m "Tambah ringkasan"
git rev-parse HEAD > hash.txt
git log --oneline

Output yang Dihasilkan:

text
770b670 Tambah ringkasan
9226799 Perbaiki laporan
a2f06c7 Tulis laporan v1

Kondisi awalnya aman dan tercatat. Isi berkas simpanannya satu baris hash penuh:

bash
cat hash.txt

Output yang Dihasilkan:

text
770b670e18cefbcb9cddef2ea4e391b8e00e0b7b

Sekarang kecelakaannya — seolah-olah kita salah mengetik rentang reset dua commit terlalu jauh:

bash
git reset --hard HEAD~2

Output yang Dihasilkan:

text
HEAD is now at a2f06c7 Tulis laporan v1
bash
git log --oneline

Output yang Dihasilkan:

text
a2f06c7 Tulis laporan v1

git log kini hanya menampilkan “Tulis laporan v1”. Dua commit teratas — “Perbaiki laporan” dan “Tambah ringkasan” — seolah tidak pernah dibuat.

Mencari Jejak di reflog #

Inilah momen reflog menunjukkan fungsinya. Setiap commit yang barusan “lenyap” masih tercatat sebagai posisi HEAD yang pernah dicapai:

bash
git reflog

Output yang Dihasilkan:

text
a2f06c7 HEAD@{0}: reset: moving to HEAD~2
770b670 HEAD@{1}: commit: Tambah ringkasan
9226799 HEAD@{2}: commit: Perbaiki laporan
a2f06c7 HEAD@{3}: commit (initial): Tulis laporan v1

Dua baris teratas adalah kartu nama para “korban”: HEAD@{1} menunjuk commit “Tambah ringkasan” dan HEAD@{2} menunjuk “Perbaiki laporan”. Kedua commit itu tidak pernah keluar dari database — kita bisa membuktikannya langsung dengan menanyakan tipe objeknya memakai hash yang tersimpan di hash.txt:

bash
git cat-file -t $(cat hash.txt)

Output yang Dihasilkan:

text
commit

Git menjawab commit: objeknya masih hidup, utuh, dan bisa dibaca isinya kapan pun. Hash pada keluaran di atas milik mesin uji; di mesin pembaca hash akan berbeda, tetapi jawaban commit tetap sama.

Jalur Pertama: Memulihkan dengan branch Baru #

Cara paling aman memberi commit “hilang” sebuah rumah baru adalah membuat branch yang menunjuk langsung ke posisinya. Kita pakai hash dari berkas simpanan — HEAD@{1} akan bekerja sama persis:

bash
git branch pulihan $(cat hash.txt)
git log --oneline pulihan

Output yang Dihasilkan:

text
770b670 Tambah ringkasan
9226799 Perbaiki laporan
a2f06c7 Tulis laporan v1

Ketiga commit tampil utuh di branch pulihan. Peta akhirnya terlihat jelas:

bash
git log --oneline --graph --all

Output yang Dihasilkan:

text
* 770b670 Tambah ringkasan
* 9226799 Perbaiki laporan
* a2f06c7 Tulis laporan v1

main dan pulihan berbagi rantai yang sama; tidak satu byte pekerjaan yang hilang. Pendekatan branch baru punya satu kelebihan penting: main tidak disentuh sama sekali — kita bisa memeriksa isi pulihan dengan tenang sebelum memutuskan langkah berikutnya.

Jalur Kedua: Memulihkan dengan reset –hard #

Bila yang kita inginkan sederhana — mengembalikan main persis ke posisi sebelum kecelakaan — git reset --hard bisa diarahkan ke hash yang sama:

bash
git reset --hard $(cat hash.txt)

Output yang Dihasilkan:

text
HEAD is now at 770b670 Tambah ringkasan
bash
git log --oneline

Output yang Dihasilkan:

text
770b670 Tambah ringkasan
9226799 Perbaiki laporan
a2f06c7 Tulis laporan v1

Riwayat main kembali menampilkan ketiga commit. Kedua jalur tadi bisa diringkas begini:

Aspekgit branch pulihan <hash>git reset --hard <hash>
Branch asalTidak tersentuhLangsung digeser ke posisi lama
Ruang gerak setelahnyaBisa diperiksa dulu, digabung bila cocokKeputusan langsung final
Risiko bila salah pilih hashHampir nol — hanya lahir branch barumain pindah lagi (tetap bisa diulang dari reflog)

Mengapa Commit Berhasil Bertahan #

Kunci pemulihan ini ada pada cara Git menyimpan data: commit adalah objek di .git/objects/ yang tetap ada selama masih direferensikan — oleh branch, tag, atau reflog — dan masih diberi masa tenggang setelah kehilangan semua rujukan. Pengaturan gc.reflogExpireUnreachable (default 30 hari) menjaga entri reflog yang commit-nya sudah tak terjangkau; pembersihan permanen baru terjadi ketika git gc menghapus objek yang sudah tidak dirujuk siapa-siapa. Itulah sebabnya kalimat berikut layak dihafal: hampir tidak ada yang benar-benar hilang di Git — yang biasanya hilang hanyalah penunjuknya.

Dokumentasi perilaku reset --hard tersedia di git-reset . Commit yang tertelan reset kini bisa dipulihkan dengan mata terpejam — berikutnya kita naik satu tingkat: memulihkan branch utuh yang terhapus, beserta seluruh riwayatnya, di Memulihkan Branch Terhapus .