Perawatan di git gc efektif, tetapi bergantung pada ingatan kita — tidak ada yang mengingatkan saat gc sudah dua bulan tak dijalankan, dan cron buatan sendiri hanya mengenal satu obat untuk segala penyakit. Git 2.30 membawa jawabannya: git maintenance, sub-sistem penjadwalan bawaan yang memecah perawatan menjadi enam tugas kecil, menjalankannya bertahap di latar belakang, dan mengelola sendiri daftar repository yang dirawatnya. Chapter ini menjalankan keenam tugas satu per satu dengan bukti berkasnya, mendaftarkan repository lewat register dan start, lalu membandingkan daemon ini dengan cron manual.

Enam Tugas dalam Satu Payung #

git maintenance run mengeksekusi satu atau lebih task lewat opsi --task=<nama>. Tanpa opsi itu, hanya tugas gc yang aktif — maintenance.gc.enabled satu-satunya yang bernilai true secara bawaan — sehingga git maintenance run polos praktis setara git gc. Tabel ini merangkum keenam tugas beserta jejak berkas yang mereka tinggalkan:

TaskPekerjaanJejak di .git
gcperawatan penuh: expire reflog, repack, prune (chapter git gc )satu pack tunggal di objects/pack/
commit-graphmenulis berkas akselerasi penelusuran riwayat secara bertahap, lalu memverifikasi hasilnyaobjects/info/commit-graph
prefetchmenarik objek terbaru dari semua remote ke ruang nama khusus tanpa menggerakkan remote-tracking branchrefs/prefetch/remotes/<remote>/...
loose-objectsmengemas objek lepas ke pack kecil berawalan loose- (maksimum 50 ribu objek per batch)objects/pack/loose-<hash>.pack
incremental-repackmenggabungkan pack kecil menjadi pack lebih besar melalui multi-pack-indexobjects/pack/multi-pack-index
pack-refsmerangkum berkas refs lepas menjadi satu berkaspacked-refs

Tugas gc sengaja berdiri terpisah dari lima lainnya: gc merombak object database sekaligus, sedangkan tugas-tugas kecil dirancang aman berdampingan dengan proses Git yang sedang berjalan. loose-objects dan incremental-repack bahkan bekerja dua tahap — berkas baru ditulis lebih dulu, sisa lama dibersihkan pada eksekusi berikutnya — supaya perintah concurrent tidak pernah menemukan object database setengah jadi.

Menjalankan Setiap Tugas dengan Bukti #

Repository latihan — tiga commit halaman situs plus remote bare pusat.git sebagai sasaran prefetch — cukup untuk melihat semua jejak:

bash
mkdir latihan-maintenance && cd latihan-maintenance
git init -b main
git config user.name "Budi Santoso"
git config user.email "[email protected]"
printf 'halaman beranda v1\n' > beranda.md
git add beranda.md
git commit -m "Buat beranda"
printf 'halaman harga v1\n' > harga.md
git add harga.md
git commit -m "Buat halaman harga"
printf 'halaman beranda v2\n' > beranda.md
git add beranda.md
git commit -m "Perbarui beranda"
git init --bare ../pusat.git
git remote add origin ../pusat.git
git push -u origin main
git count-objects -v

Output yang Dihasilkan:

text
count: 9
size: 36
in-pack: 0
packs: 0
size-pack: 0
prune-packable: 0
garbage: 0
size-garbage: 0

Sembilan objek lepas — tiga commit, tiga tree, tiga blob. Tugas pertama mengemasnya tanpa menyentuh apa pun yang lain:

bash
git maintenance run --task=loose-objects
ls .git/objects/pack/

Output yang Dihasilkan:

text
loose-f96e021356525a782ea12412fd6d3baf137389a3.idx
loose-f96e021356525a782ea12412fd6d3baf137389a3.pack
loose-f96e021356525a782ea12412fd6d3baf137389a3.rev

Seluruh sembilan objek masuk ke satu pack kecil berawalan loose- — penamaan ini membedakannya dari pack hasil repack penuh; nama berkas dihitung dari isi pack sehingga berbeda di mesin pembaca. Lanjut ke penggabung pack:

bash
git maintenance run --task=incremental-repack
ls .git/objects/pack/

Output yang Dihasilkan:

text
loose-f96e021356525a782ea12412fd6d3baf137389a3.idx
loose-f96e021356525a782ea12412fd6d3baf137389a3.pack
loose-f96e021356525a782ea12412fd6d3baf137389a3.rev
multi-pack-index

multi-pack-index adalah indeks lintas pack: incremental-repack memakainya untuk menandai pack kecil yang layak digabung pada eksekusi mendatang dan membersihkan berkas lama yang tak dirujuk. Pack kecil repository ini masih di bawah ambang batch sehingga belum ada penggabungan — yang hadir lebih dulu adalah indeksnya. Tugas berikutnya merapikan refs:

bash
git maintenance run --task=pack-refs
cat .git/packed-refs

Output yang Dihasilkan:

text
# pack-refs with: peeled fully-peeled sorted 
7dd70ee13add79e4e772a505785acfcae4a8a13c refs/heads/main
7dd70ee13add79e4e772a505785acfcae4a8a13c refs/remotes/origin/main

Berkas packed-refs dari chapter git gc muncul lewat jalur khusus — dua refs dirangkum menjadi satu berkas; hash-nya berbeda di mesin pembaca. Giliran tugas paling berat:

bash
git maintenance run --task=gc
git count-objects -v

Output yang Dihasilkan:

text
count: 0
size: 0
in-pack: 9
packs: 1
size-pack: 2
prune-packable: 0
garbage: 0
size-garbage: 0
bash
ls .git/objects/pack/

Output yang Dihasilkan:

text
pack-6d5ed2e05807e9bfb8bfc44480f0c1d0703727c3.idx
pack-6d5ed2e05807e9bfb8bfc44480f0c1d0703727c3.pack
pack-6d5ed2e05807e9bfb8bfc44480f0c1d0703727c3.rev

Tugas gc menulis ulang seluruh objek menjadi satu pack tunggal: pack loose-* dan multi-pack-index lenyap digantikan pack baru. Inilah alasan gc dinonaktifkan dalam strategi latar belakang — pekerjaannya tumpang tindih dengan tugas incremental dan merobohkan hasil kerja mereka. Dua tugas terakhir menyentuh sisi lain:

bash
git maintenance run --task=commit-graph
ls .git/objects/info/

Output yang Dihasilkan:

text
commit-graph
packs

Tugas commit-graph menulis berkas cache metadata commit — parent, tanggal, nomor generasi — yang membuat git log dan git diff tidak perlu men-dekompresi objek commit satu per satu; bedah tuntas fungsinya menyusul di Repository Performance . Terakhir, prefetch bekerja diam-diam:

bash
git maintenance run --task=prefetch
git for-each-ref refs/prefetch

Output yang Dihasilkan:

text
7dd70ee13add79e4e772a505785acfcae4a8a13c commit	refs/prefetch/remotes/origin/main

Prefetch menjalankan git fetch senyap dengan refspec yang dialihkan: objek terbaru dari origin sudah diunduh, tetapi hasilnya dicatat di refs/prefetch/remotes/origin/main, bukan di refs/remotes/origin/main. Remote-tracking branch sengaja tidak digerakkan — ref itu memang seharusnya hanya berubah saat fetch sungguhan dijalankan, dan saat fetch itu tiba tinggal pointer yang dimutakhirkan tanpa transfer objek.

Register: Mendaftarkan Repository #

Tugas manual tetap menyisakan masalah penjadwalan; sub-command register menutupnya: Git mencatat repository aktif ke daftar maintenance.repo di konfigurasi global pengguna, dan scheduler latar belakang merawatnya tanpa perintah apa pun.

bash
mkdir -p ../rumah
export HOME="$PWD/../rumah"
git maintenance register
git config --global --get-all maintenance.repo

Output yang Dihasilkan:

text
/home/z/my-project/tutorial-extracted/work/sandbox/internals-dan-performa/part-b/latihan-maintenance

Jalur pada keluaran menyesuaikan lokasi direktori. Selain mendaftarkan, register menulis dua pengaturan ke konfigurasi lokal repository ini:

bash
git config maintenance.auto
git config maintenance.strategy

Output yang Dihasilkan:

text
false
text
incremental

maintenance.auto=false mematikan pemeriksaan auto-maintenance di depan — mekanisme senyap yang kita lihat di chapter Garbage Collection — supaya perintah sehari-hari seperti git commit tidak mengulang pekerjaan yang sudah dijadwalkan di belakang. maintenance.strategy=incremental menetapkan ritme tugas latar belakang:

TaskFrekuensi strategi incremental
commit-graph, prefetchtiap jam
loose-objects, incremental-repacktiap hari
pack-refstiap minggu
gcdinonaktifkan

gc penuh tetap urusan manual atau CI — mahal dan mengganggu, seperti dibahas di git gc .

start, stop, dan unregister #

register hanya mendaftarkan; start yang memasang jadwal — konfigurasi yang sama dengan register ditambah scheduler latar belakang:

bash
git maintenance start

Output yang Dihasilkan:

text
fatal: neither systemd timers nor crontab are available

Sandbox container ini memang tanpa scheduler — tidak ada systemd maupun crontab. Di mesin nyata pesan itu tidak muncul: Linux memasang systemd user timers ([email protected], @daily, @weekly), macOS memakai launchd, Windows memakai Scheduled Task. Scheduler menjalankan git maintenance run --scheduled tiap jam — tengah malam menambahkan tugas harian, dini hari Minggu menambahkan tugas mingguan — sambil menelusuri seluruh daftar maintenance.repo. Penutupnya tiga sub-command senyap:

bash
git maintenance stop
git maintenance unregister
git config --global --get-all maintenance.repo

stop menghentikan jadwal tanpa menghapus repository dari daftar — cukup start ulang untuk hidup kembali. unregister kebalikannya: mencabut repository dari daftar tanpa menyentuh jadwal. Perintah terakhir di atas tidak mencetak apa pun dan keluar dengan kode 1 — kunci maintenance.repo sudah tidak ada, pertanda daftar kembali kosong. Selesai demonstrasi, kembalikan HOME ke nilai asli agar perintah berikutnya membaca konfigurasi yang benar.

Daemon Penjadwalan vs Cron Manual #

Pertanyaan klasik: mengapa tidak cukup 0 3 * * * git gc di crontab? Cron manual memang bekerja, tetapi hanya mengenal satu obat untuk semua penyakit dan menyerahkan seluruh pengelolaan pada penulisnya:

AspekCron git gc manualgit maintenance start
Pemasanganbaris crontab ditulis dan dirawat sendiriregister + start otomatis
Strategisatu gc besar sekaligusincremental: tugas kecil per jam, hari, minggu
Registrasi repositorydiedit manual satu per satudaftar maintenance.repo dikelola Git
Dampak ke proses laingc penuh merombak pack saat mungkin dipakaitugas kecil aman bersanding proses Git aktif
Pemeriksaan --auto di depantetap berjalan, pekerjaan bisa dobelmaintenance.auto=false meredamnya

Pada akhirnya git maintenance bukan sihir baru — keenam tugasnya adalah perintah-perintah yang sudah kita kuasai: git gc, git pack-refs, git commit-graph write, dan git fetch, dibungkus penjadwal yang tahu kapan masing-masing layak dijalankan. Yang belum dibahas adalah sisi konsumen: repository yang sudah terasa lambat perlu diukur dulu sebelum diobati. Repository Performance — chapter berikutnya — memulai dari pengukuran itu. Rujukan lengkap semua sub-command dan konfigurasi ada di dokumentasi git-maintenance .