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:
| Task | Pekerjaan | Jejak di .git |
|---|---|---|
gc | perawatan penuh: expire reflog, repack, prune (chapter git gc ) | satu pack tunggal di objects/pack/ |
commit-graph | menulis berkas akselerasi penelusuran riwayat secara bertahap, lalu memverifikasi hasilnya | objects/info/commit-graph |
prefetch | menarik objek terbaru dari semua remote ke ruang nama khusus tanpa menggerakkan remote-tracking branch | refs/prefetch/remotes/<remote>/... |
loose-objects | mengemas objek lepas ke pack kecil berawalan loose- (maksimum 50 ribu objek per batch) | objects/pack/loose-<hash>.pack |
incremental-repack | menggabungkan pack kecil menjadi pack lebih besar melalui multi-pack-index | objects/pack/multi-pack-index |
pack-refs | merangkum berkas refs lepas menjadi satu berkas | packed-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:
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 -vOutput yang Dihasilkan:
count: 9
size: 36
in-pack: 0
packs: 0
size-pack: 0
prune-packable: 0
garbage: 0
size-garbage: 0Sembilan objek lepas — tiga commit, tiga tree, tiga blob. Tugas pertama mengemasnya tanpa menyentuh apa pun yang lain:
git maintenance run --task=loose-objects
ls .git/objects/pack/Output yang Dihasilkan:
loose-f96e021356525a782ea12412fd6d3baf137389a3.idx
loose-f96e021356525a782ea12412fd6d3baf137389a3.pack
loose-f96e021356525a782ea12412fd6d3baf137389a3.revSeluruh 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:
git maintenance run --task=incremental-repack
ls .git/objects/pack/Output yang Dihasilkan:
loose-f96e021356525a782ea12412fd6d3baf137389a3.idx
loose-f96e021356525a782ea12412fd6d3baf137389a3.pack
loose-f96e021356525a782ea12412fd6d3baf137389a3.rev
multi-pack-indexmulti-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:
git maintenance run --task=pack-refs
cat .git/packed-refsOutput yang Dihasilkan:
# pack-refs with: peeled fully-peeled sorted
7dd70ee13add79e4e772a505785acfcae4a8a13c refs/heads/main
7dd70ee13add79e4e772a505785acfcae4a8a13c refs/remotes/origin/mainBerkas 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:
git maintenance run --task=gc
git count-objects -vOutput yang Dihasilkan:
count: 0
size: 0
in-pack: 9
packs: 1
size-pack: 2
prune-packable: 0
garbage: 0
size-garbage: 0ls .git/objects/pack/Output yang Dihasilkan:
pack-6d5ed2e05807e9bfb8bfc44480f0c1d0703727c3.idx
pack-6d5ed2e05807e9bfb8bfc44480f0c1d0703727c3.pack
pack-6d5ed2e05807e9bfb8bfc44480f0c1d0703727c3.revTugas 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:
git maintenance run --task=commit-graph
ls .git/objects/info/Output yang Dihasilkan:
commit-graph
packsTugas 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:
git maintenance run --task=prefetch
git for-each-ref refs/prefetchOutput yang Dihasilkan:
7dd70ee13add79e4e772a505785acfcae4a8a13c commit refs/prefetch/remotes/origin/mainPrefetch 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.
mkdir -p ../rumah
export HOME="$PWD/../rumah"
git maintenance register
git config --global --get-all maintenance.repoOutput yang Dihasilkan:
/home/z/my-project/tutorial-extracted/work/sandbox/internals-dan-performa/part-b/latihan-maintenanceJalur pada keluaran menyesuaikan lokasi direktori. Selain mendaftarkan, register menulis dua pengaturan ke konfigurasi lokal repository ini:
git config maintenance.auto
git config maintenance.strategyOutput yang Dihasilkan:
falseincrementalmaintenance.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:
| Task | Frekuensi strategi incremental |
|---|---|
commit-graph, prefetch | tiap jam |
loose-objects, incremental-repack | tiap hari |
pack-refs | tiap minggu |
gc | dinonaktifkan |
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:
git maintenance startOutput yang Dihasilkan:
fatal: neither systemd timers nor crontab are availableSandbox 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:
git maintenance stop
git maintenance unregister
git config --global --get-all maintenance.repostop 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:
| Aspek | Cron git gc manual | git maintenance start |
|---|---|---|
| Pemasangan | baris crontab ditulis dan dirawat sendiri | register + start otomatis |
| Strategi | satu gc besar sekaligus | incremental: tugas kecil per jam, hari, minggu |
| Registrasi repository | diedit manual satu per satu | daftar maintenance.repo dikelola Git |
| Dampak ke proses lain | gc penuh merombak pack saat mungkin dipakai | tugas kecil aman bersanding proses Git aktif |
Pemeriksaan --auto di depan | tetap berjalan, pekerjaan bisa dobel | maintenance.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
.