Memperbaiki Tautan Bukti Setelah Penulisan Ulang Riwayat Git
Hash commit berubah massal saat riwayat git ditulis ulang. Remap referensi Bukti lewat commit-map, termasuk penanganan hash nol.
Ringkasan
Jadi gini, pas riwayat repo dibersihin, hash commit ikut berubah semua, bukan cuma yang ada datanya. Hash lama di kolom Bukti jadi mati, tapi tenang, file commit-map nyimpen pemetaan lama ke baru. Pelajarannya: jangan simpen hash mentah buat jangka panjang, mending pakai tag atau branch per isu.
Tujuh isu di papan kerja sebuah proyek pengelolaan acara publik memuat kolom Bukti berisi hash commit. Saat perintah git cat-file -e dijalankan terhadap hash pertama, yang kembali hanya pesan error. Pembersihan data pribadi pada riwayat repositori sudah selesai dan dianggap sukses, tetapi tidak ada yang memeriksa dampaknya ke kolom Bukti: ketujuh tautan mati tanpa suara.
Dampak Penulisan Ulang Riwayat
Asumsi pertama yang wajar: hanya commit yang mengandung data sensitif yang hash-nya berubah. Dugaan itu keliru. Hash commit dihitung dari isi commit, mencakup pesan, identitas penulis, tree, dan hash induknya [3]. Ubah satu commit lama, maka commit itu dan seluruh keturunannya mendapat hash baru, berantai sampai ujung riwayat. Dokumentasi GitHub mencatat perubahan hash sebagai efek samping resmi: alat atau otomasi yang bergantung pada hash yang tidak berubah akan rusak atau bermasalah [2]. Efek samping lain yang ikut terdokumentasi: clone lama yang menarik-dorong ulang bisa mengembalikan data sensitif, diff pull request yang sudah tertutup hilang, dan tanda tangan commit maupun tag gugur [2].
Satu-satunya sumber tepercaya pemetaan lama ke baru adalah berkas .git/filter-repo/commit-map yang ditulis git filter-repo setiap kali dijalankan [1]. Isinya mencakup semua commit dalam rentang penulisan ulang, termasuk yang hash-nya tidak berubah [1]. Baris pertama berupa header kolom old dan new [1]. Alat ini sendiri adalah pengganti filter-branch yang direkomendasikan proyek Git, hanya butuh git minimal 2.36.0 serta Python 3.6 [4]. Nilai nol di kolom new berarti commit dihapus sepenuhnya [1]; tidak ada remap yang bisa menghidupkannya kembali, referensinya harus diarahkan ke artefak yang masih bertahan. Sebagai catatan, filter-repo juga menulis ulang referensi hash di dalam pesan commit secara default [1], dan dapat membuat replace-refs agar ID lama berukuran penuh tetap bisa di-resolve, tetapi hanya berlaku bila replace refs itu didorong dan diambil secara manual [1].
Prosedur Remap Kolom Bukti
Perbaikan berjalan empat langkah. Pertama, ekspor ketujuh hash kedaluwarsa dari papan isu ke berkas teks, misalnya stale_hashes.txt. Kedua, bangun pemetaan dari commit-map. Baris dengan hash nol di kolom new dilewati dan dicatat sebagai tidak dapat dipulihkan; referensinya dipindah ke artefak pengganti seperti commit pengganti atau tag rilis. Ketiga, perbarui setiap kolom Bukti dengan hash baru hasil pemetaan. Keempat, verifikasi setiap hash baru benar-benar menunjuk commit yang hidup:
git cat-file -e <hash_baru>^{commit}
Exit code 0 berarti hash valid. Seluruh langkah dua sampai empat bisa dibungkus satu skrip pendek:
#!/bin/bash
# Remap hash Bukti: baca hash lama, cari pemetaannya di commit-map
MAP_FILE=".git/filter-repo/commit-map"
HASH_FILE="stale_hashes.txt"
while read -r old_hash; do
mapped_line=$(grep "^${old_hash}" "$MAP_FILE")
if [ -z "$mapped_line" ]; then
echo "Hash $old_hash tidak ditemukan di commit-map"
else
new_hash=$(echo "$mapped_line" | awk '{print $2}')
if [ "$new_hash" = "0000000000000000000000000000000000000000" ]; then
echo "Hash $old_hash -> REMOVED (arahkan ke artefak pengganti)"
else
echo "Hash $old_hash -> $new_hash"
fi
fi
done < "$HASH_FILE"
Skrip ini sengaja tidak mengubah apa pun. Ia hanya mencetak pemetaan, sehingga hasilnya bisa ditinjau dulu sebelum kolom Bukti di papan isu diperbarui satu per satu.
Dua gejala yang paling sering muncul saat langkah ini dijalankan tanpa membaca aturan mainnya. Pertama, hash lama tidak ada di commit-map sama sekali; biasanya karena berkas itu tertimpa oleh run filter-repo berikutnya, dan satu-satunya jalan adalah memulihkan dari snapshot atau cadangan repositori lama. Kedua, semua hash lolos verifikasi tetapi isu tetap terlihat salah; pemetaan yang benar belum berarti kolom Bukti di papan isu benar-benar diperbarui, verifikasi akhirnya tetap membaca ulang isi kolomnya, bukan output skrip.
Mencegah Putusnya Referensi Berikutnya
Setiap hash yang disimpan di luar repositori, di papan isu, dokumen QA, atau lembar persetujuan, adalah kerusakan kolateral dari setiap penulisan ulang riwayat. Pola yang lebih tahan lama: simpan bukti sebagai tag atau branch yang dinamai dari isu, atau arahkan ke artefak yang dialamatkan konten. Bila penulisan ulang riwayat tetap diperlukan, ekspor commit-map ke lokasi tahan lama segera setelah proses selesai, sebelum berkas itu tertimpa oleh run berikutnya. Mengandalkan hash mentah sebagai referensi jangka panjang adalah praktik rapuh; pemetaannya baru terjadi sekali dan hanya bisa ditangkap di commit-map.