Pesan HEAD detached at 070aaa9 di git status cukup untuk membuat siapa pun yang baru bertemu merasa salah menekan sesuatu. Nyatanya kondisi detached HEAD bukan galat: HEAD yang biasanya menunjuk ke nama branch sedang menunjuk langsung ke sebuah commit — keadaan yang sengaja maupun tak sengaja kita ciptakan setiap kali melihat-lihat commit lama. Bahayanya baru muncul saat commit dibuat dalam kondisi ini: commit itu tidak dimiliki branch mana pun dan akan “hilang” begitu kita kembali. Chapter ini membedah keadaan tersebut dari dalam: masuk lewat dua pintu, membuktikan status dan keluarannya, lalu menyelamatkan commit yang telanjur dibuat — tentu saja dengan reflog .

Apa Itu Detached HEAD #

Dalam keadaan normal, berkas .git/HEAD berisi ref: refs/heads/main — HEAD menunjuk ke branch, dan branch menunjuk ke commit; commit baru otomatis menaikkan keduanya. Saat ter-detach, HEAD berisi hash commit mentah. Perpindahan ini terjadi setiap kali kita memeriksa commit tertentu tanpa nama branch: git switch --detach <commit>, git checkout <commit>, atau hasil sampingan prosedur seperti rebase . Mekanika berkas HEAD dibahas lebih dalam di HEAD dan Detached HEAD .

Masuk ke Kondisi Detached dengan switch –detach #

Repository latihan latihan-detached berisi dua commit di main. Cara modern masuk ke kondisi detached adalah opsi --detach:

bash
mkdir latihan-detached && cd latihan-detached
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf '# Catatan\nhalo\n' > catatan.md
git add catatan.md
git commit -m "Mulai catatan proyek"
printf '# Catatan\nhalo\ndunia\n' > catatan.md
git add catatan.md
git commit -m "Tambah salam dunia"
git switch --detach HEAD~1
git status
cat catatan.md

Output yang Dihasilkan:

text
HEAD is now at 070aaa9 Mulai catatan proyek

Output yang Dihasilkan:

text
HEAD detached at 070aaa9
nothing to commit, working tree clean

Output yang Dihasilkan:

text
# Catatan
halo

Status berterus-terang: HEAD detached at 070aaa9 — hash di mesin pembaca akan berbeda — dan working tree memuat isi commit lama: catatan.md versi “halo” tanpa “dunia”. Dalam keadaan ini kita aman melihat-lihat: git show, git log, bahkan menjalankan program versi lama. Tidak ada yang rusak selama tidak ada commit yang dibuat.

Suntingan yang Menghalangi Kepulangan #

Sebelum membahas commit, satu ganjalan kecil perlu kita alami dulu: suntingan working tree yang bertabrakan dengan branch tujuan. Dari kondisi detached di commit lama, berkas catatan.md disunting:

bash
printf '# Catatan\nhalo\nsuntingan liar\n' > catatan.md
git status --short
git switch main

Output yang Dihasilkan:

text
 M catatan.md

Output yang Dihasilkan:

text
error: Your local changes to the following files would be overwritten by checkout:
	catatan.md
Please commit your changes or stash them before you switch branches.
Aborting

git switch main menolak keras: versi catatan.md di working tree akan tertimpa versi main yang berbeda. Penolakan ini justru pengaman — suntingan belum mati. Dua pilihan standar: simpan dengan git stash, atau buang dengan git restore catatan.md bila memang tak diperlukan. Latihan ini memilih membuang:

bash
git restore catatan.md
git switch main

Perintah git restore senyap — versi commit lama kembali ke berkas. Setelah berkas bersih, kepulangan diizinkan:

Output yang Dihasilkan:

text
Previous HEAD position was 070aaa9 Mulai catatan proyek
Switched to branch 'main'

Baris Previous HEAD position was ... mencatat posisi detached yang barusan kita tinggalkan — jejak kecil pertama bahwa Git selalu tahu ke mana HEAD pernah pergi.

Pintu Lama: git checkout commit #

Perintah warisan git checkout <commit> membawa ke keadaan yang sama. Dari main, kita coba pintu lama ini:

bash
git checkout HEAD~1

Output yang Dihasilkan:

text
Note: switching to 'HEAD~1'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

(dipotong — saran git switch - dan cara mematikan advice)
HEAD is now at 070aaa9 Mulai catatan proyek

Catatan panjangnya menegaskan tiga hal: kita boleh melihat-lihat dan bereksperimen, commit yang dibuat bisa dibuang tanpa memengaruhi branch mana pun, dan git switch -c <nama-branch-baru> adalah jalan menyelamatkan commit yang dibuat. Keluaran di atas dipotong — baris sisanya berisi saran git switch - untuk membatalkan serta cara mematikan pengingat lewat advice.detachedHead. Kita kini berada di detached HEAD lagi, di commit pertama.

Commit di Detached HEAD Itu Terancam #

Sekarang inti bahayanya. Selagi masih detached di commit pertama, satu commit eksperimen dibuat:

bash
printf '# Catatan\nhalo\neksperimen: tema gelap\n' > catatan.md
git add catatan.md
git commit -m "Eksperimen tema gelap"

Output yang Dihasilkan:

text
[detached HEAD 5c906aa] Eksperimen tema gelap
 1 file changed, 1 insertion(+)

Commit lahir dengan label [detached HEAD 5c906aa] — bukan [main ...]. Commit ini tidak dimiliki branch mana pun. Kita kembali ke main:

bash
git switch main
git log --oneline

Output yang Dihasilkan:

text
Warning: you are leaving 1 commit behind, not connected to
any of your branches:

  5c906aa Eksperimen tema gelap

If you want to keep it by creating a new branch, this may be a good time
to do so with:

 git branch <new-branch-name> 5c906aa

Switched to branch 'main'

Output yang Dihasilkan:

text
62a46aa Tambah salam dunia
070aaa9 Mulai catatan proyek

Git dengan jujur memperingatkan: satu commit tertinggal, tidak terhubung ke branch mana pun, lengkap dengan hash dan saran git branch <nama-baru> <hash>. Riwayat main hanya memuat dua commit — “Eksperimen tema gelap” tidak tampak di mana-mana. Inilah “kehilangan” versi detached HEAD: commit tetap hidup di database objek, tetapi tidak dirujuk apa pun selain reflog.

Menyelamatkan lewat reflog #

Jadikan kehilangan tadi sebagai latihan pemulihan. Reflog mencatat seluruh perjalanan kita:

bash
git reflog

Output yang Dihasilkan:

text
62a46aa HEAD@{0}: checkout: moving from 5c906aa87fc12aabcf152c3cf2aca8163897d8cd to main
5c906aa HEAD@{1}: commit: Eksperimen tema gelap
070aaa9 HEAD@{2}: checkout: moving from main to HEAD~1
62a46aa HEAD@{3}: checkout: moving from 070aaa9780ce6a5030a5b175d05628a96c750e8b to main
070aaa9 HEAD@{4}: checkout: moving from main to HEAD~1
62a46aa HEAD@{5}: commit: Tambah salam dunia
070aaa9 HEAD@{6}: commit (initial): Mulai catatan proyek

Baris 5c906aa HEAD@{1}: commit: Eksperimen tema gelap adalah alamat lengkap commit yang “hilang” — sementara HEAD@{2} dan HEAD@{4} menunjukkan dua kunjungan detached kita sebelumnya. Penyelamatannya cukup satu perintah: branch baru yang berdiri tepat di posisi itu, sambil langsung berpindah ke sana:

bash
git switch -c selamat HEAD@{1}
git log --oneline
cat catatan.md

Output yang Dihasilkan:

text
Switched to a new branch 'selamat'

Output yang Dihasilkan:

text
5c906aa Eksperimen tema gelap
070aaa9 Mulai catatan proyek

Output yang Dihasilkan:

text
# Catatan
halo
eksperimen: tema gelap

Branch selamat memuat “Eksperimen tema gelap” di atas “Mulai catatan proyek” — keduanya kini milik branch resmi. Nama branch bisa apa pun, dan HEAD@{1} bisa diganti hash commit secara langsung. Setelah aman, git switch - melompat kembali ke branch yang terakhir kita tempati:

bash
git switch -

Output yang Dihasilkan:

text
Switched to branch 'main'

Referensi sintaks lengkap ada di git-switch . Kondisi detached kini bukan lagi momok: pintu masuknya disengaja, keluarannya jelas, dan commit yang tertinggal pun bisa diselamatkan. Perangkat darurat kita — reflog, pemulihan commit, branch, berkas, staging, hingga detached HEAD — kini lengkap; tinggal satu alat penyelamat yang belum dipegang: git stash, ruang kerja sementara bagi pekerjaan setengah jalan, di git stash .