Krátký návod, jak uvolnit místo na disku promazáním git repositáře. Nebudu raději ani popisovat, jak se stalo, že jsem do repositáře potvrdil (a ještě to poslal do nadřízeného repositáře) 30GB složku, ani co obsahovala. Poučením pro příště je, že git add -A
je příliš mocná zbraň a to zejména v případě nenastaveného .gitignore
. V mém případě jsem tedy potřeboval z repositáře vymazat velká data s cílem uvolnit místo na disku; tento návod ale platí i pro jakoukoliv situaci, kdy z repositáře budete potřebovat trvale smazat jakákoliv citlivá data, jako jsou hesla, soukromé klíče apod.
Tento návod je v podstatě volným překladem návodu na githubu.
Pracujeme na serverovém repositáři. V hierarchii gitu je to matoucí pojem, je samozřejmně možné pracovat na jakémkoliv repositáři, jen je třeba pamatovat, že na konci procesu si všichni zúčastnění budou muset naklonovat své repositáře znovu právě z tohoto opraveného.
Před samotnou prací je vhodné si udělat zálohu původního repositáře, u mě zafungovalo obyčejné git clone --bare Puvodni.git Opraveny.git.
Díky tomu, že git clone
na stejném systému souborů data nekopíruje, ale dělá jen hardlinky, je tato operace velmi rychlá.
Pěkná ukázka dobrého návrhu datových struktur a jednoduché implementace copy on write na obecném systému souborů. Jednou zapsaný soubor (platí pro datové soubory objektů, pack apod. nikoliv pro všechny soubory v repositáři) se nikdy nemění (jen třeba smaže po
git gc
), takže je možné snadno vytvářet clony repositářů ve stovkách kusů pomocí hardlinků a šetřit tak zabrané místo na disku.
Klonování nenahrazuje řádnou zálohu, pokud tedy tento postup chcete aplikovat na svůj vlastní soukromý repositář bez dalších jeho klonů umístěných na jiných počítačích, je vhodné jej před touto operací zazálohovat.
Samotné promazání, cílem je smazat složku JMENO_SLOZKY, jejíž jméno bylo v mém případě naštěstí unikátní.
git filter-branch --index-filter \ 'git rm -rf --cached --ignore-unmatch JMENO_SLOZKY' \ --prune-empty --tag-name-filter cat -- --all
Při této operaci se přepisují revize, kde je daný soubor (složka) smazána a také všechny následující.
Samotné uvolnění místa na disku:
rm -rf .git/refs/original/ git reflog expire --expire=now --all git gc --aggressive --prune=now
Poslední příkaz trval v mém případě 72GB repositáře několik hodin. Po jeho dokončení se repositář smrsknul na 22GB, což dobře odpovídá uloženým datům i objemu smazané a 2x změněné 30GB složky.
Po tomto kroku už následuje klasické git clone
u všech klientů repositáře a také kontrola, zda v něm zůstala všechna potřebná data.
Jenom vysvětlující poznámku, protože se tomu stejně nejspíše nevyhnu :-D. Git používám pro svou běžnou práci a své pracovní dokumenty apod. Je to dobrý prostředek, jak si udržet pořádek a hlavně mít svá data na více počítačích synchronizovaná. Před čtyřmi lety jsem používal subversion http://www.heronovo.cz/poradek/, git je jen evoluce. Takže proto 22GB živých dat. Těch 30GB navíc byl samozřejmně omyl, proto jsem to chtěl smazat, jednalo se o disk virtuálního počítače).
Jak často děláš repack? Protože ten může docela trvat, s tak monstrózním repozitářem. Standardně to git dělá až po nějakém nastaveném prahu (počet souborů nebo dat – nevím přesně).
Dělám občas (většinou po záloze na externí disk) git gc. Nepamatuji si, ze by někdy klient čekal na vyřízení git repack (nebo gc) na nadřízeném repositáři.
$ time git gc
Counting objects: 155772, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (148940/148940), done.
Writing objects: 100% (155772/155772), done.
Total 155772 (delta 5882), reused 155772 (delta 5882)
Checking connectivity: 155772, done.
real 9m33.879s
user 2m12.836s
sys 0m41.455s
Pingback: BTRFS v praxi po 5 letech | Heronovo