Membuang perubahan lokal selalu bergerak menuju satu arah: versi terakhir yang tercatat. Padahal repository menyimpan setiap versi dari setiap berkas yang pernah di-commit — dan kadang versi yang kita butuhkan justru versi lama: paragraf yang tidak sengaja tertimpa, berkas yang terhapus, atau cuplikan yang ingin dibandingkan dengan isi saat ini. Perintah git restore --source=<titik-riwayat> <berkas> membuka pintu itu: berapa pun jauhnya sebuah commit berada di belakang, isinya bisa diambil kembali ke working tree. Chapter ini juga membahas pola ekspor lewat git show untuk menyalin versi lama menjadi berkas baru.

Tiga Versi dalam Riwayat #

Kita siapkan repository dengan satu berkas yang berubah tiga kali, sehingga riwayatnya memuat tiga versi catatan-rilis.md:

bash
mkdir latihan-pulihkan && cd latihan-pulihkan
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf '# Catatan Rilis\n\n## 1.0\n\nRilis perdana aplikasi.\n' > catatan-rilis.md
git add catatan-rilis.md
git commit -m "Catatan rilis 1.0"
printf '# Catatan Rilis\n\n## 1.0\n\nRilis perdana aplikasi.\n\n## 1.1\n\nPerbaikan galat pada modul impor.\n' > catatan-rilis.md
git add catatan-rilis.md
git commit -m "Catatan rilis 1.1"
printf '# Catatan Rilis\n\n## 1.0\n\nRilis perdana aplikasi.\n\n## 1.1\n\nPerbaikan galat pada modul impor.\nPenyempurnaan tampilan daftar berkas.\n' > catatan-rilis.md
git add catatan-rilis.md
git commit -m "Lengkapi catatan rilis 1.1"
git log --oneline

Output yang Dihasilkan:

text
[main (root-commit) b38bfe9] Catatan rilis 1.0
 1 file changed, 5 insertions(+)
 create mode 100644 catatan-rilis.md
[main 66851b6] Catatan rilis 1.1
 1 file changed, 4 insertions(+)
[main 0c9fd26] Lengkapi catatan rilis 1.1
 1 file changed, 1 insertion(+)
0c9fd26 Lengkapi catatan rilis 1.1
66851b6 Catatan rilis 1.1
b38bfe9 Catatan rilis 1.0

Tiga commit tercatat: b38bfe9 memuat versi 1.0, 66851b6 memuat versi 1.1, dan 0c9fd26 memuat versi terlengkap. Nilai hash di mesin pembaca akan berbeda karena hash dihitung dari isi commit; yang penting adalah setiap commit menyimpan snapshot utuh, bukan sekadar daftar perubahan.

Memulihkan Berkas Terhapus #

Kasus paling mendesak biasanya sederhana: berkas terhapus, sengaja maupun tidak:

bash
rm catatan-rilis.md
git status

Output yang Dihasilkan:

text
On branch main
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
	deleted:    catatan-rilis.md

no changes added to commit (use "git add" and/or "git commit -a")

Bagi Git, penghapusan hanyalah salah satu bentuk perubahan working tree — petunjuk (use "git restore <file>...") yang sama seperti chapter Membuang Perubahan Lokal berlaku juga di sini. Versi terakhir berkas masih tersimpan rapi di index dan di commit, jadi pemulihannya satu perintah:

bash
git restore catatan-rilis.md
cat catatan-rilis.md

Output yang Dihasilkan:

text
# Catatan Rilis

## 1.0

Rilis perdana aplikasi.

## 1.1

Perbaikan galat pada modul impor.
Penyempurnaan tampilan daftar berkas.

Berkas kembali utuh dengan isi versi commit terakhir — penghapusan di working tree tertutup sempurna. Jika penghapusan justru yang ingin dipertahankan, jalannya berbeda: angkat penghapusan ke staging area dengan git rm, dibahas pada chapter git rm .

Mengambil Versi Lama dengan –source #

Sekarang bagian yang tidak bisa dikerjakan git restore polos: mengambil versi yang lebih tua dari commit terakhir. Opsi --source menentukan titik riwayat yang dijadikan sumber salinan:

bash
git restore --source=b38bfe9 catatan-rilis.md
cat catatan-rilis.md
git status -s
git diff --stat

Output yang Dihasilkan:

text
# Catatan Rilis

## 1.0

Rilis perdana aplikasi.
 M catatan-rilis.md
 catatan-rilis.md | 5 -----
 1 file changed, 5 deletions(-)

Empat keluaran di atas berasal dari empat perintah berurutan: isi berkas kembali ke versi 1.0, git status -s melaporkan M karena working tree kini berbeda dari index, dan git diff --stat merangkum jaraknya — lima baris harus dihapus dari versi HEAD untuk sampai ke versi 1.0.

Sesi ini kita pakai jalur kedua: git restore catatan-rilis.md dijalankan senyap, dan git status -s kembali tidak mencetak apa pun — catatan-rilis.md bersih kembali di versi terbaru.

Pola Ekspor: git show #

Kadang versi lama tidak ingin ditaruh di berkas aslinya — kita hanya ingin salinannya, misalnya untuk diperbandingkan berdampingan. Pola git show <titik>:<berkas> > <berkas-baru> membaca isi berkas pada titik riwayat tertentu dan menuliskannya ke berkas tujuan — notasi <titik>:<berkas> dirinci pada dokumentasi git show :

bash
git show b38bfe9:catatan-rilis.md > catatan-rilis-1.0.md
cat catatan-rilis-1.0.md
git status -s

Output yang Dihasilkan:

text
# Catatan Rilis

## 1.0

Rilis perdana aplikasi.
?? catatan-rilis-1.0.md

Notasi b38bfe9:catatan-rilis.md berarti “isi catatan-rilis.md sebagaimana tersimpan di commit b38bfe9” — keluarannya murni isi berkas, bukan diff. Operator > dari shell kemudian mengarahkannya menjadi berkas baru catatan-rilis-1.0.md, yang muncul sebagai untracked. Berkas aslinya tidak tersentuh sama sekali.

Referensi Relatif Tanpa Mencari Hash #

Hash jarang tersimpan di kepala. Referensi relatif menggantikannya: HEAD~1 berarti satu commit sebelum HEAD, HEAD~2 dua commit sebelumnya, dan seterusnya:

bash
git restore --source=HEAD~1 catatan-rilis.md
cat catatan-rilis.md
git status -s

Output yang Dihasilkan:

text
# Catatan Rilis

## 1.0

Rilis perdana aplikasi.

## 1.1

Perbaikan galat pada modul impor.
 M catatan-rilis.md
?? catatan-rilis-1.0.md

Isi berkas kini versi 1.1 — hasil yang sama dengan --source=66851b6 tanpa perlu mencari hash di git log. Baris kedua keluaran status adalah berkas ekspor dari bagian sebelumnya, yang memang masih dibiarkan untracked; berkas catatan-rilis.md sendiri kembali bisa dikembalikan ke versi terbaru kapan saja dengan git restore catatan-rilis.md.

Ketika Titik yang Dicari Tidak Lagi Terjangkau #

Opsi --source dan pola git show menjangkau titik riwayat yang masih tercatat pada referensi — commit yang dirujuk HEAD, branch, atau tag. Keadaan berubah bila commit yang memuat versi yang dicari sudah tidak dirujuk apa pun, misalnya setelah riwayat ditulis ulang. Kabar baiknya, Git tetap menyimpan jejak setiap pergerakan HEAD di sebuah log internal bernama reflog, dan dari jejak itu commit “hilang” masih bisa ditemukan kembali — pembahasan lengkapnya menempuh satu section tersendiri: Pemulihan dan Recovery .

Dengan --source dan pola ekspor di tangan, versi mana pun dalam riwayat sudah bisa diambil dan diperiksa. Pertanyaan berikutnya menggeser fokus: bagaimana cara membaca keluaran git diff secara saksama — baris demi baris — agar setiap perbedaan benar-benar dipahami sebelum diambil keputusan? Lanjut ke Melihat Perbedaan Perubahan .