Heronovo IT doupě

Jak promazat git repositář a uvolnit tak místo na disku

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.