Monorepo menggabungkan banyak layanan dalam satu repository agar bisa direfaktor serentak, tetapi harganya dibayar oleh semua orang: insinyur yang hanya menyentuh service-a tetap meng-clone service-b, direktori docs, dan ratusan megabyte aset yang tak pernah dibuka. Sparse checkout memotong biaya itu dari sisi working directory — Git tetap memegang repository utuh, tetapi hanya mengeluarkan direktori pilihan ke disk. Kita akan membuktikannya pada monorepo mini, membongkar pola yang Git bangun di balik layar, lalu membedakan teknik ini dari partial clone yang sering tertukar dengannya.

Monorepo Mini dan Mode Cone #

Repository latihan menampung dua layanan plus dokumentasi, dengan satu commit tambahan di service-b agar riwayatnya tidak sepele:

bash
mkdir latihan-monorepo && cd latihan-monorepo
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
mkdir service-a service-b docs
printf 'api layanan a\n' > service-a/main.go
printf 'tes layanan a\n' > service-a/main_test.go
printf 'api layanan b\n' > service-b/main.go
printf 'panduan monorepo\n' > docs/panduan.md
printf 'Monorepo Toko Berkah\n' > README.md
git add -A
git commit -m "Struktur awal monorepo"
printf 'router layanan b\n' > service-b/router.go
git add service-b/router.go
git commit -m "Tambah router layanan B"

Dari luar, repository di-clone seperti biasa, lalu mode sparse diaktifkan:

bash
cd ..
git clone latihan-monorepo klon-monorepo
cd klon-monorepo
git sparse-checkout init --cone
ls

Output yang Dihasilkan:

text
README.md

Satu baris itu adalah momen pentingnya: service-a, service-b, dan docs lenyap dari disk. Git versi 2.47 (versi yang dipakai buku ini) memakai mode cone sebagai mode bawaan; flag --cone hanya menegaskan pilihan itu. Nama “cone” menggambarkan bentuk cakupannya: berkas di root selalu diambil, lalu direktori level atas masuk hanya bila dipilih bersama seluruh isinya — seperti kerucut yang tumbuh dari root. Mode ini cepat karena Git cukup membandingkan awalan path, tanpa membaca isi berkas.

Memilih Direktori dengan set #

Perintah set menuliskan pilihan direktori sekaligus mengeluarkannya ke working directory:

bash
git sparse-checkout set service-a docs
ls

Output yang Dihasilkan:

text
README.md
docs
service-a

Perintah git sparse-checkout list menampilkan pilihan yang aktif — hanya dua nama itu, tanpa README.md, karena berkas root diambil otomatis:

text
docs
service-a

Status index menjelaskan ke mana berkas lainnya pergi. git ls-files -t menandai setiap entri dengan satu huruf:

text
H README.md
H docs/panduan.md
H service-a/main.go
H service-a/main_test.go
S service-b/main.go
S service-b/router.go

Huruf H menandai berkas terlacak normal; huruf S menandai entri ber-skip-worktree — Git mencatatnya tetap ada di index, tetapi berkas fisiknya sengaja tidak dikeluarkan. Inilah sebabnya git status tetap bersih: tidak ada berkas “hilang”, yang ada hanyalah berkas yang dijadwalkan absen. Pola lengkapnya tersimpan di .git/info/sparse-checkout:

text
/*
!/*/
/docs/
/service-a/

Empat baris ini ditulis ulang oleh Git setiap kali set dijalankan, dan cara bacanya persis gaya pola .gitignore : ambil semua di root (/*), kecuali direktori (!/*/), lalu kembalikan /docs/ dan /service-a/ beserta seluruh isinya. Riwayat tidak ikut terpangkas — git log --oneline | wc -l tetap menghasilkan 2, karena kedua commit monorepo masih utuh di object database.

add dan disable: Menambah Melepas #

Direktori bisa ditambah tanpa mengulang set dari nol. Perintah add menggabungkan pilihan baru ke daftar yang ada:

bash
git sparse-checkout add service-b
ls
git sparse-checkout list

Output yang Dihasilkan (ls):

text
README.md
docs
service-a
service-b

Output yang Dihasilkan (list):

text
docs
service-a
service-b

Perintah add sendiri tidak mencetak apa pun; dua keluaran di atas adalah bukti efeknya. Kebalikannya, git sparse-checkout disable mematikan mode sparse sepenuhnya dan mengembalikan seluruh working directory. ls kemudian menampilkan README.md, docs, service-a, dan service-b kembali — tanpa satu byte pun diunduh ulang, karena seluruh objek memang sudah ada di .git sejak clone. Ada juga pintasan di sisi klon: git clone --sparse latihan-monorepo klon-sparse menghasilkan klon yang sejak awal hanya berisi berkas root, siap di-set kemudian; ls klon-sparse di sandbox hanya menampilkan README.md.

Pola Non-Cone: Keturunan gitignore #

Mode non-cone — diaktifkan dengan git sparse-checkout set --no-cone — menerima pola bebas bergaya .gitignore seperti *.go atau !service-b/, sehingga berkas bisa dipilih per tipe, bukan per direktori utuh. Kelenturan itu berbanding mahal: Git harus mencocokkan setiap path terhadap pola, dan dokumentasi resmi git sparse-checkout menandai mode ini deprecated dengan daftar masalah perilaku yang panjang. Untuk kebutuhan umum — pilih direktori, ambil semuanya — cone mode adalah jawaban yang cepat dan cukup.

Sparse Checkout Bukan Partial Clone #

Dua teknik ini sering disebut bersama karena keduanya “mengecilkan clone”, tetapi keduanya memotong di tempat berbeda:

AspekSparse checkoutPartial clone
Working directoryHanya direktori pilihanTergantung filter; biasanya lengkap
Object databaseUtuh sejak cloneBlob diunduh saat dibutuhkan (--filter=blob:none)
Riwayat commitUtuhUtuh
Butuh server pendukungTidak — murni lokalYa — server harus mendukung filter
Beban jaringan cloneTetap penuhMenyusut sesuai filter

Sparse checkout murni urusan lokal: ia menyeleksi apa yang keluar dari object database ke disk, bukan apa yang diunduh. Partial clone menyeleksi objek apa yang ditransfer dari server — topik yang dekat dengan teknik berikutnya. Karena clone dangkal memotong sumbu ketiga, yaitu jumlah riwayat, ketiganya bisa dipakai sendiri-sendiri atau digabung, dan perbandingannya paling jelas dilihat dari sisi ukuran: lanjut ke Shallow Clone .