Logo baru selesai dikerjakan desainer, di-commit, lalu kita penasaran apa yang berubah — dan git diff hanya menjawab satu baris: Binary files a/logo.png and b/logo.png differ. Tidak ada +, tidak ada -, tidak ada petunjuk sama sekali. Perlakuan ini disengaja: alat diff baris-per-baris tidak berarti untuk berkas biner, jadi Git memilih diam. Kabar baiknya, diam bukan satu-satunya pilihan — --numstat tetap mencatat kehadiran berkas biner, --binary mengemas byte-byte-nya menjadi patch yang benar-benar bisa diterapkan, dan driver textconv mengajarkan Git membaca isinya lewat konversi. Chapter ini membedah ketiganya dengan berkas biner kecil sungguhan, lalu menutup dengan pengantar ke masalah yang lebih besar: berkas biner yang ukurannya besar.

Diff Biner Bawaan: Satu Baris “differ” #

Kita siapkan berkas biner mungil yang meniru ciri logo: nomor sihir \x89PNG, teks deskripsi, dan byte NUL di ekor. Dua versi dibuat agar ada yang bisa dibandingkan:

bash
mkdir latihan-biner && cd latihan-biner
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf '\x89PNG\r\n\x1a\nlogo v1 lebar 64 tinggi 32\n\x00\x00\x00\x0d' > logo.png
git add logo.png
git commit -m "Tambah logo awal"
printf '\x89PNG\r\n\x1a\nlogo v2 lebar 128 tinggi 64\n\x00\x00\x00\x0d' > logo.png
git diff

Output yang Dihasilkan:

text
diff --git a/logo.png b/logo.png
index 9751028..64834cf 100644
Binary files a/logo.png and b/logo.png differ

Baris Binary files a/logo.png and b/logo.png differ menggantikan seluruh hunk. Vonis “biner” jatuh dari heuristik sederhana: Git memeriksa potongan awal berkas (8.000 byte pertama), dan kehadiran satu byte NUL (\x00) di sana sudah cukup. Konsekuensinya berlaku dua arah — berkas teks yang kebetulan memuat NUL ikut diperlakukan biner, dan berkas tanpa NUL dibedah baris demi baris meski ekstensinya .png.

Statistik ringkas pun menyerah:

bash
git diff --numstat

Output yang Dihasilkan:

text
-	-	logo.png

Dua kolom hitungan baris diganti tanda - — biner tidak dihitung per baris. Format ini justru berguna ketika menyorot berkas teks di antara banyak perubahan: baris - - logo.png tetap terlihat lompong tanpa mengaburkan angka berkas lain.

–binary: Patch Biner yang Bisa Diterapkan #

Teks tak terbaca bukan berarti byte tak tersentuh. Opsi --binary mengemas isi berkas lama dan baru ke dalam format patch sehingga perubahan biner bisa dikirim sebagai berkas teks dan diterapkan kembali:

bash
git diff --binary

Output yang Dihasilkan:

text
diff --git a/logo.png b/logo.png
index 9751028b1a0645ac63bab6bd5d67534e51f918d7..64834cf8a51db96328fa170c8a2c35f7f4370845 100644
GIT binary patch
literal 40
vcmeAS@N?(olH$tAPtR8<Gg8P&O-d|MFf_7ID9OxAPtQ~^GvQ)jVBiG+=Pe3H

literal 39
ucmeAS@N?(olH$tAPtR8<GgQb)O-d|MFf&mo$;?Yn&r~or;$mQ6-~|BP910Ks

Kita bedah strukturnya:

  1. GIT binary patch — penanda bahwa hunk berikut membawa isi berkas, bukan baris teks.
  2. literal 40 — panjang berkas hasil (versi v2, 40 byte), diikuti datanya yang terenkode base85 agar aman dikirim sebagai patch teks.
  3. literal 39 — pasangan baliknya: berkas sebelumnya (39 byte) supaya patch juga bisa dibalikkan.

Bukti bahwa format ini benar-benar hidup: simpan keluarannya ke berkas, pulihkan logo ke versi lama, lalu terapkan:

bash
git diff --binary > tambalan-logo.patch
git checkout -- logo.png
git status --short
git apply tambalan-logo.patch
git status --short

Output yang Dihasilkan:

text
?? tambalan-logo.patch

Output yang Dihasilkan:

text
 M logo.png
?? tambalan-logo.patch

Sebelum git apply, hanya tambalan-logo.patch yang untracked dan logo.png bersih; setelahnya logo.png berstatus M — byte versi v2 direkonstruksi dari blok literal tanpa berkas aslinya pernah dikirim. Pola checkout -- lalu apply inilah yang dipakai saat berkolaborasi lewat patch, misalnya mengirim tambalan lewat surel.

textconv: Membaca Isi Biner Lewat Konversi #

--binary memindahkan byte, bukan maknanya. Untuk membuat diff terbaca, kita mendaftarkan konversi sehingga diff berjalan pada hasil konversi berkas, bukan byte mentahnya. Mekanismenya dua potong: baris di .gitattributes memetakan pola berkas ke nama driver, dan konfigurasi diff.<driver>.textconv menentukan perintah konversinya:

ini
*.png diff=tekslogo
bash
git config diff.tekslogo.textconv strings
git diff

Output yang Dihasilkan:

text
diff --git a/logo.png b/logo.png
index 9751028..64834cf 100644
--- a/logo.png
+++ b/logo.png
@@ -1 +1 @@
-logo v1 lebar 64 tinggi 32
+logo v2 lebar 128 tinggi 64

Diff tiba-tiba terbaca: -logo v1 lebar 64 tinggi 32 berganti +logo v2 lebar 128 tinggi 64. Untuk kedua versi, Git menjalankan strings — alat yang mengekstrak rangkaian karakter tercetak dari berkas biner — lalu membedah keluarannya sebagai teks. Verifikasi singkat memperlihatkan sumber baris itu:

bash
strings logo.png

Output yang Dihasilkan:

text
logo v2 lebar 128 tinggi 64

Pilihan perintah konversi bebas selama membaca berkas dan mencetak teks: od -c (dump byte per karakter) untuk format yang strukturnya penting, atau alat khusus seperti pembaca metadata video — asalkan terpasang di mesin. Pada sandbox ini strings terbukti bekerja, jadi itulah yang dipakai. Satu catatan urutan penting: --binary dan textconv saling meniadakan — begitu driver aktif, git diff memilih hasil konversi, sehingga penulisan GIT binary patch pada sesi sebelumnya dikerjakan sebelum konfigurasi ini ada.

Atribut dan konfigurasinya kita simpan sebagai penutup latihan:

bash
git add logo.png .gitattributes
git commit -m "Perbarui logo dan aktifkan driver diff teks"

Output yang Dihasilkan:

text
[main 5efb708] Perbarui logo dan aktifkan driver diff teks
 2 files changed, 1 insertion(+)
 create mode 100644 .gitattributes

Opsi-opsi diff untuk berkas biner dirangkum berikut:

PerintahHasil untuk berkas biner
git diffBinary files a/... and b/... differ
git diff --numstat- - path (tanpa hitungan baris)
git diff --binaryGIT binary patch siap git apply
git diff + textconvdiff teks hasil konversi

Biner kecil seperti logo 40 byte tidak menimbulkan masalah; Git bahkan mengemasnya dan memperlakukan diffnya dengan sopan. Persoalan dimulai ketika berkasnya besar: setiap revisi logo, video, atau model AI tersimpan penuh sebagai blob — 10 revisi berarti 10 salinan utuh, dan repository membengkak meski isinya hanya bergeser sedikit. Untuk itulah Git menyediakan strategi berkas besar dan Git LFS . Lanjut ke File Besar .