Perintah yang dia sarankan untuk melakukan ini dengan benar setelah mengimpor "sejarah yang panjang dan terlibat" adalah
Date: Wed, 5 Dec 2007 22:09:12 -0800 (PST)
From: Linus Torvalds <torvalds at linux-foundation dot org>
To: Daniel Berlin <dberlin at dberlin dot org>
cc: David Miller <davem at davemloft dot net>,
ismail at pardus dot org dot tr,
gcc at gcc dot gnu dot org,
git at vger dot kernel dot org
Subject: Re: Git and GCC
In-Reply-To: <[email protected]>
Message-ID: <[email protected]>
References: <[email protected]>
<[email protected]>
<[email protected]>
<[email protected]>
<[email protected]>
Pada Kamis, 6 Des 2007, Daniel Berlin menulis:
Sebenarnya, ternyata git-gc --aggressive
melakukan hal bodoh ini untuk mengemas file terkadang terlepas dari apakah Anda mengonversi dari repo SVN atau tidak.
Benar. git --aggressive
kebanyakan bodoh. Ini benar-benar hanya berguna untuk kasus “Saya tahu saya punya benar - benar buruk, dan saya ingin membuang semua keputusan pengepakan yang buruk yang telah saya lakukan."
Untuk menjelaskan ini, ada baiknya menjelaskan (Anda mungkin menyadarinya, tapi biarkan saya membahas dasar-dasarnya) bagaimana rantai-delta git bekerja, dan bagaimana mereka sangat berbeda dari kebanyakan sistem lain.
Di SCM lain, rantai-delta umumnya diperbaiki. Ini mungkin "maju" atau "mundur," dan mungkin berkembang sedikit saat Anda bekerja dengan repositori, tetapi umumnya itu adalah rantai perubahan ke satu file yang direpresentasikan sebagai semacam entitas SCM tunggal. Di CVS, itu jelas*,v
file, dan banyak sistem lain melakukan hal yang agak mirip.
Git juga melakukan rantai-delta, tetapi melakukannya dengan lebih “longgar”. Tidak ada entitas tetap. Delta dibuat berdasarkan versi acak lainnya yang dianggap git sebagai kandidat delta yang baik (dengan berbagai heuristik yang cukup berhasil), dan sama sekali tidak ada aturan pengelompokan yang ketat.
Ini umumnya merupakan hal yang sangat bagus. Ini bagus untuk berbagai alasan konseptual ( yaitu , git secara internal bahkan tidak pernah benar-benar perlu peduli dengan keseluruhan rantai revisi - tidak benar-benar memikirkan delta sama sekali), tetapi juga bagus karena menyingkirkan aturan delta yang tidak fleksibel berarti bahwa git tidak memiliki masalah sama sekali dengan menggabungkan dua file menjadi satu, misalnya - tidak ada *,v
“file revisi” yang memiliki arti tersembunyi.
Ini juga berarti bahwa pilihan delta adalah pertanyaan yang jauh lebih terbuka. Jika Anda membatasi rantai delta menjadi hanya satu file, Anda benar-benar tidak memiliki banyak pilihan tentang apa yang harus dilakukan tentang delta, tetapi di git, ini bisa menjadi masalah yang sama sekali berbeda.
Dan di sinilah nama yang sangat buruk --aggressive
. Meskipun git biasanya mencoba menggunakan kembali informasi delta (karena itu ide yang bagus, dan tidak membuang waktu CPU untuk menemukan kembali semua delta bagus yang kami temukan sebelumnya), terkadang Anda ingin mengatakan “mari kita mulai dari awal, dengan slate kosong, dan abaikan semua informasi delta sebelumnya, dan coba buat sekumpulan delta baru”.
Jadi --aggressive
bukan tentang menjadi agresif, tetapi tentang membuang-buang waktu CPU untuk melakukan kembali keputusan yang telah kita lakukan sebelumnya!
Terkadang itu adalah hal yang baik. Beberapa alat impor khususnya dapat menghasilkan delta yang sangat buruk. Apa pun yang menggunakan git fast-import
, misalnya, kemungkinan besar tidak memiliki tata letak delta yang bagus, jadi sebaiknya Anda mengatakan "Saya ingin memulai dari yang bersih".
Tapi hampir selalu, dalam kasus lain, itu sebenarnya hal yang sangat buruk untuk dilakukan. Ini akan membuang-buang waktu CPU, dan terutama jika Anda benar-benar telah melakukan pekerjaan delta dengan baik sebelumnya, hasil akhirnya tidak akan menggunakan kembali semua delta bagus yang sudah Anda temukan, jadi Anda akan mendapatkan banyak hasil akhir yang lebih buruk juga!
Saya akan mengirim tambalan ke Junio untuk menghapus git gc --aggressive
dokumentasinya. Ini bisa berguna, tetapi umumnya berguna hanya ketika Anda benar-benar memahami pada tingkat yang sangat dalam apa yang dilakukannya, dan dokumentasi itu tidak membantu Anda melakukannya.
Secara umum, melakukan incremental git gc
adalah pendekatan yang tepat, dan lebih baik daripada melakukan git gc --aggressive
. Ini akan menggunakan kembali delta lama, dan ketika delta lama itu tidak dapat ditemukan (alasan untuk melakukan GC inkremental di tempat pertama!) Itu akan membuat yang baru.
Di sisi lain, memang benar bahwa "impor awal dari sejarah yang panjang dan terlibat" adalah titik di mana menghabiskan banyak waktu untuk menemukan delta yang benar - benar bagus akan bermanfaat . Kemudian, setiap pengguna setelahnya (selama mereka tidak menggunakannya git gc --aggressive
untuk mengurungkannya!) Akan mendapatkan keuntungan dari peristiwa satu kali tersebut. Jadi, terutama untuk proyek besar dengan sejarah panjang, mungkin ada baiknya melakukan beberapa pekerjaan ekstra, memberi tahu kode pencarian delta untuk menjadi liar.
Jadi yang setara dengan git gc --aggressive
- tetapi dilakukan dengan benar - adalah melakukan (dalam semalam) sesuatu seperti
git repack -a -d --depth=250 --window=250
di mana kedalaman itu hanya tentang seberapa dalam rantai delta bisa (membuatnya lebih panjang untuk sejarah lama - itu sepadan dengan overhead ruang), dan masalah jendela adalah tentang seberapa besar jendela objek yang kita inginkan untuk dipindai setiap kandidat delta.
Dan di sini, Anda mungkin ingin menambahkan -f
flag (yang merupakan "hapus semua delta lama", karena Anda sekarang sebenarnya mencoba memastikan bahwa yang ini benar-benar menemukan kandidat yang baik.
Dan kemudian itu akan memakan waktu selamanya dan satu hari ( yaitu , hal "lakukan dalam semalam"). Tetapi hasil akhirnya adalah setiap orang yang berada di hilir dari repositori itu akan mendapatkan paket yang jauh lebih baik, tanpa harus mengeluarkan tenaga untuk itu sendiri.
Linus
Seperti yang saya sebutkan dalam " Pengumpulan Sampah Git tampaknya tidak sepenuhnya berfungsi ", a
git gc --aggressive
tidak cukup atau bahkan tidak cukup.Dan, seperti yang saya jelaskan di bawah , seringkali tidak diperlukan.
Kombinasi paling efektif adalah dengan menambahkan
git repack
, tetapi jugagit prune
:Catatan: Git 2.11 (Q4 2016) akan mengatur
gc aggressive
kedalaman default menjadi 50Lihat commit 07e7dbf (11 Agustus 2016) oleh Jeff King (
peff
) .(Digabung oleh Junio C Hamano -
gitster
- di commit 0952ca8 , 21 Sep 2016)(Lihat berkomitmen untuk belajar )
Berbicara tentang penyimpanan CPU, "
git repack
" belajar untuk menerima--threads=<n>
opsi dan meneruskannya ke objek paket.Lihat commit 40bcf31 (26 Apr 2017) oleh Junio C Hamano (
gitster
) .(Digabung oleh Junio C Hamano -
gitster
- di commit 31fb6f4 , 29 Mei 2017)Kami sudah melakukannya untuk
--window=<n>
dan--depth=<n>
; ini akan membantu ketika pengguna ingin memaksakan--threads=1
pengujian yang dapat direproduksi tanpa terpengaruh oleh perlombaan beberapa utas.sumber
git gc --aggressive
telah diperbaiki dua kali: Pertama, untuk melakukan apa yang disarankan Linus pada tahun 2007 sebagai "metode pengemasan yang lebih baik". Dan kemudian di Git 2.11 untuk menghindari kedalaman objek yang berlebihan seperti yang disarankan Linus, tetapi ternyata berbahaya (memperlambat semua operasi Git di masa mendatang dan tidak menghemat ruang yang layak untuk dibicarakan).man git-repack
mengatakan untuk-d
: `Juga jalankan git prune-pack untuk menghapus file objek longgar yang berlebihan.` Atau apakahgit prune
juga melakukan itu?man git-prune
berkataIn most cases, users should run git gc, which calls git prune.
, jadi apa gunanya setelah itugit gc
? Bukankah lebih baik atau cukup hanya digunakangit repack -Ad && git gc
?Masalahnya
git gc --aggressive
adalah bahwa nama opsi dan dokumentasinya menyesatkan.Seperti yang dijelaskan Linus sendiri dalam surat ini , yang
git gc --aggressive
pada dasarnya dilakukannya adalah:Biasanya tidak perlu menghitung ulang delta di git, karena git menentukan delta ini sangat fleksibel. Ini hanya masuk akal jika Anda tahu bahwa Anda memiliki delta yang sangat, sangat buruk. Seperti yang dijelaskan Linus, sebagian besar alat yang digunakan
git fast-import
termasuk dalam kategori ini.Sebagian besar waktu git melakukan pekerjaan yang cukup baik dalam menentukan delta yang berguna dan penggunaan
git gc --aggressive
akan meninggalkan Anda dengan delta yang berpotensi lebih buruk lagi sambil membuang banyak waktu CPU.Linus mengakhiri emailnya dengan kesimpulan bahwa
git repack
dengan pilihan besar--depth
dan--window
lebih baik di sebagian besar waktu; terutama setelah Anda mengimpor proyek besar dan ingin memastikan bahwa git menemukan delta yang bagus.sumber
Peringatan. Jangan dijalankan
git gc --agressive
dengan repositori yang tidak disinkronkan dengan remote jika Anda tidak memiliki cadangan.Operasi ini membuat ulang delta dari awal dan dapat menyebabkan hilangnya data jika terganggu dengan baik.
Untuk komputer 8GB saya, gc agresif kehabisan memori pada repositori 1Gb dengan 10k komit kecil. Ketika OOM killer menghentikan proses git - itu meninggalkan saya dengan repositori yang hampir kosong, hanya pohon yang berfungsi dan beberapa delta yang bertahan.
Tentu saja, itu bukan satu-satunya salinan repositori jadi saya hanya membuatnya ulang dan menarik dari jarak jauh (pengambilan tidak berfungsi pada repo yang rusak dan menemui jalan buntu pada langkah 'menyelesaikan delta' beberapa kali saya mencoba melakukannya), tetapi jika repo Anda adalah repo lokal pengembang tunggal tanpa remote sama sekali - buat cadangannya terlebih dahulu.
sumber
Catatan: berhati-hatilah dalam menggunakan
git gc --aggressive
, seperti yang dijelaskan oleh Git 2.22 (Q2 2019).Lihat komit 0044f77 , komit daecbf2 , komit 7.384.504 , komit 22d4e3b , komit 080a448 , komit 54d56f5 , komit d257e0f , komit b6a8d09 (7 April 2019), dan komit fc559fb , komit cf9cd77 , komit b11e856 (22 Mar 2019) oleh Ævar Arnfjord Bjarmason (
avar
) .(Digabung oleh Junio C Hamano -
gitster
- di commit ac70c53 , 25 Apr 2019)Artinya, dokumentasi git-gc sekarang menyertakan :
Dan ( lakukan 080a448 ):
sumber