Kolaborator baru join, menjalankan git clone, lalu menunggu — dan menunggu, dan menunggu. Setelah 700 MB terunduh barulah ketahuan penyebabnya: repository menyimpan ratusan versi berkas video yang masing-masing utuh. Inilah sifat paling kejam dari berkas besar di Git: masalahnya bukan sekali waktu, melainkan permanen — selama blob tersebut ada di riwayat, setiap clone, fetch, dan CI baru membayar ongkos yang sama. Chapter ini membedah mengapa ukurannya menumpuk, cara mengukur blob terbesar dengan alat bawaan Git, lalu aturan pencegahan sebelum kita melanjutkan ke solusi khusus: Git LFS.

Setiap Versi Tersimpan Utuh Sebagai Blob #

Git adalah penyimpan snapshot, bukan delta: satu commit menyimpan seluruh isi berkas pada saat itu, dan revisi berikutnya menyimpan salinan utuh lagi — kompresi hanya bekerja dalam satu pack, tidak lintas versi untuk berkas acak/binary. Kita buktikan dengan berkas 5 MB yang dibuat dari data acak (acak dipilih agar tidak termampatkan, seperti rekaman video sungguhan). Bilangan acak dibangkitkan dengan benih tetap agar hasilnya identik antar mesin:

bash
mkdir latihan-besar && cd latihan-besar
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
python3 -c "import random; random.seed(2026); open('rekaman-demo.mp4','wb').write(random.randbytes(5000000))"
git add rekaman-demo.mp4
git commit -m "Tambah rekaman demo"
git count-objects -vH

Output yang Dihasilkan:

text
count: 3
size: 4.78 MiB
in-pack: 0
packs: 0
size-pack: 0 bytes
prune-packable: 0
garbage: 0
size-garbage: 0 bytes

Perintah git count-objects -vH menghitung isi object database; dua kolom kuncinya: count = jumlah objek longgar (loose), dan size = total ukurannya dalam format yang terbaca manusia (-H). Tiga objek pertama adalah blob rekaman, tree, dan commit — hampir seluruh 4,78 MiB berasal dari satu blob itu. Sekarang kita ganti seluruh isinya dengan versi kedua dan commit lagi:

bash
python3 -c "import random; random.seed(2027); open('rekaman-demo.mp4','wb').write(random.randbytes(5000000))"
git add rekaman-demo.mp4
git commit -m "Rekam ulang demo versi kedua"
git count-objects -vH
git gc
git count-objects -vH

Output yang Dihasilkan:

text
count: 6
size: 9.56 MiB

Output yang Dihasilkan:

text
count: 0
size: 0 bytes
in-pack: 6
packs: 1
size-pack: 9.54 MiB
prune-packable: 0
garbage: 0
size-garbage: 0 bytes

Berkas yang diubah sedikit saja pun menambah ukuran penuh. Tiga objek baru muncul sehingga total menjadi enam, dan size melipat dua menjadi 9,56 MiB — meski isi berkas hanya berganti. git gc lalu memadatkan keenam objek ke satu pack (in-pack: 6, size-pack: 9.54 MiB), dan pack tetap sebesar itu: kompresi zlib tidak bisa menyatukan dua blob acak yang isinya berbeda total. Sepuluh revisi video berarti sepuluh salinan — persis pola yang diperkenalkan di File Biner dan Diff .

Clone Mengunduh Semua Versi, Bukan Hanya Terbaru #

Working directory hanya memuat satu berkas 5 MB, jadi mungkin terasa wajar mengira clone sebesar itu juga. Kenyataannya:

bash
cd ..
git clone latihan-besar klon-besar
du -sh klon-besar/.git
stat -c '%s %n' klon-besar/rekaman-demo.mp4

Output yang Dihasilkan:

text
9.8M    klon-besar/.git
5000000 klon-besar/rekaman-demo.mp4

Direktori .git klon berukuran 9,8M — hampir dua kali isi working directory-nya. Clone memindahkan seluruh object database yang relevan dengan riwayat: kedua versi rekaman ikut terunduh karena keduanya dirujuk commit di main. git fetch dan git pull teratur kemudian hanya menambah objek baru, tetapi setiap anggota tim baru, setiap runner CI, dan setiap salinan kerja baru harus membayar 9,8M ini dari nol. Angka di mesin kita mungkin sedikit berbeda karena ukuran blok filesystem, tetapi rasionya konsisten.

Mengukur Blob Terbesar di Riwayat #

Sebelum mengobati, kita perlu mendiagnosis. Ukuran working directory bisa dicek cepat lewat du:

bash
git ls-files | xargs -d '\n' du -ch

Output yang Dihasilkan:

text
4.8M    rekaman-demo.mp4
4.8M    total

git ls-files mencetak daftar berkas terlacak; xargs -d '\n' meneruskannya aman dari spasi di nama; du -ch menjumlahkan dan menutup dengan total. Namun pengukuran ini buta terhadap riwayat — versi lama yang sudah dihapus dari working directory tidak terlihat. Untuk mengintip seluruh object database, kita pasangkan git rev-list --objects --all (mencari setiap objek dirujuk refs mana pun, lengkap dengan path-nya) dengan git cat-file --batch-check (membaca tipe, hash, dan ukuran tiap objek tanpa mengunduh isinya):

bash
git rev-list --objects --all \
  | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' \
  | awk '/^blob/ {print $3, $4}' \
  | sort -rn | head -n 5

Output yang Dihasilkan:

text
5000000 rekaman-demo.mp4
5000000 rekaman-demo.mp4

Dua baris untuk satu nama berkas: dua blob berukuran 5.000.000 byte — versi pertama dan kedua, keduanya masih hidup di riwayat. Inilah alat diagnosis utama saat repository terasa gemuk: jalankan di repo proyek nyata, dan daftar blob terbesar segera menunjuk biang keroknya.

Dampak dan Pencegahan #

Dampaknya menumpuk di banyak tempat sekaligus:

AspekDampak berkas besar di riwayat
git cloneMengunduh semua versi, bukan hanya terbaru — makin banyak revisi makin lambat
git fetch / git pullObjek baru ikut di-pack; transfer rutin jadi berat
CI/CDSetiap pipeline men-clone ulang; menit-menit hangat terbuang di tiap build
PenyimpananServer hosting dan setiap mesin anggota tim menyimpan salinan penuh
Toolinggit status, gc, dan operasi index melambat pada tree raksasa

Pencegahan selalu lebih murah daripada pengobatan. GitHub menolak berkas di atas 100 MB per berkas dan memberi peringatan mulai 50 MB — angka yang layak dijadikan ambang praktis: di atas itu, pertimbangkan Git LFS yang kita bahas di chapter berikutnya (kebijakan lengkapnya di dokumentasi GitHub ). Kebiasaan yang paling berdampak: siapkan .gitignore sejak commit pertama — build, dependensi, dan berkas hasil ekspor tidak pernah masuk riwayat sejak awal. Disiplin ukuran commit juga membantu: periksa dengan git count-objects -vH atau du sebelum push kalau ragu.

Bila berkas besar memang bagian sah dari proyek — aset game, model AI, video — mengabaikannya bukan pilihan. Git punya mekanisme khusus yang menyimpan isi di luar object database: pointer kecil di repository, berkas asli di penyimpanan LFS. Lanjut ke Git LFS .