Így találd meg és távolítsd el a nagy fájlokat a Git historyból

Kezdödik már unalmas lenni, hogy a Git repositoryd klónozása percekig tart? Minden egyes push vagy pull műveletnél úgy érzed, mintha az internet a ’90-es évekbeli betárcsázós modem sebességével működne? Nos, van egy rossz hírem: valószínűleg a Git historyd tele van olyan nagy fájlokkal, amiknek soha nem kellett volna oda kerülniük. Ezek a fájlok, legyenek bár ideiglenes fordítási eredmények, óriási adatbázis-mentések, filmek vagy nagy felbontású képek, jelentősen megnövelik a repository méretét, és lassítják a teljes fejlesztési folyamatot. De ne aggódj, van megoldás! Ebben a cikkben részletesen bemutatjuk, hogyan találhatod meg és távolíthatod el ezeket a kísérteteket a Git historyból, hogy repositoryd ismét karcsú és gyors legyen.

Miért Fontos a Git History Tisztántartása?

A Git egy fantasztikus verziókövető rendszer, de még a legjobb eszköz is hajlamos a „hízásra”, ha nem figyelünk rá. A túlzott méretű repository számos problémát okozhat:

  • Repository mérete és tárhely: Minél nagyobb a repository, annál több helyet foglal a lemezen, ami különösen problémás lehet nagy csapatok és sok projekt esetén.
  • Klónozási idő: Egy új fejlesztő belépésekor vagy egy új környezet beállításakor a repository klónozása az első lépés. Ha ez percekig, órákig tart, az komolyan rontja a termelékenységet. A lassú klónozási idő frusztráló és időpazarló.
  • Hálózati forgalom: Minden egyes klónozás, fetch vagy pull jelentős hálózati forgalmat generál. Nagy fájlok esetén ez gyorsan felmeríti a sávszélesség-használat kérdését, különösen távoli munkavégzés vagy lassabb internetkapcsolat esetén.
  • Git műveletek teljesítménye: A Git belső működése is lassabbá válhat. A git log, git blame, git checkout parancsok mind több időt vehetnek igénybe, ha a repository mérete indokolatlanul nagy.
  • Backupok és archiválás: A nagyobb repositoryk biztonsági mentése és archiválása is több időt és erőforrást igényel.

Ezek mind elegendő okot szolgáltatnak arra, hogy időről időre felülvizsgáljuk és tisztítsuk a Git historyt.

Hogyan Azonosítsuk a Nagy Fájlokat a Git Repositoryban?

Mielőtt bármit is törölnénk, először meg kell találnunk a bűnösöket. Szerencsére a Git és néhány kiegészítő eszköz segít ebben.

Git Parancsokkal

A Git beépített eszközei is képesek feltárni a legnagyobb fájlokat. A leggyakrabban használt és leghatékonyabb módszer a következő:

git rev-list --all --objects | 
git cat-file --batch-check="% (size) % (objectname) % (type) % (rest)" | 
sort -rh | head -n 10

Nézzük meg, mit is csinál ez a parancs:

  • git rev-list --all --objects: Ez listázza az összes objektumot (fájlokat, könyvtárakat, commitokat) a repository teljes történetében.
  • git cat-file --batch-check="% (size) % (objectname) % (type) % (rest)": Ez a parancs beolvassa az előző parancs kimenetét, és minden objektumhoz kiírja annak méretét, SHA-azonosítóját, típusát és nevét.
  • sort -rh: Rendezési parancs, ami a kimenetet méret szerint, fordított sorrendben rendezi (a legnagyobbakkal kezdve). A -h opció emberi olvasásra alkalmas formában jeleníti meg a méreteket (pl. 10M, 2G).
  • head -n 10: Csak az első 10 sort (azaz a 10 legnagyobb fájlt/objektumot) mutatja meg.

Ennek a parancsnak a kimenete valahogy így nézhet ki:

120.3M c427d0a2f4a56a6a9b3d2c1e8f7a6b5c4d3e2f10 blob  assets/large_video.mp4
 80.5M e538f1b3c2d1a0b9c8d7e6f5a4b3c2d1e0f9a8b7 blob  data/backup.zip
 55.2M f649g8h7i6j5k4l3m2n1o0p9q8r7s6t5u4v3w2x1 blob  src/images/high_res_background.png
...

Ha a repository már tömörítve van (ami automatikusan megtörténik idővel a git gc futtatásakor), akkor az objektumok nem egyedi fájlokként, hanem „pack” fájlokban tárolódnak. Ebben az esetben a következő parancs is hasznos lehet:

git verify-pack -v .git/objects/pack/*.idx | sort -k 3nr | head -n 10

Ez a parancs közvetlenül a pack fájlokat vizsgálja, és kilistázza a bennük lévő legnagyobb objektumokat. A -k 3nr opció azt jelenti, hogy a harmadik oszlop (a fájlméret bájtban) alapján rendezzük numerikusan, fordított sorrendben.

Külső Eszközökkel

Léteznek grafikus és parancssori eszközök is, amelyek segítenek vizuálisan vagy részletesebben feltárni a repository méretét:

  • git-sizer: Egy Python script, ami elemzi a repositoryt és részletes jelentést ad a méretekről, a legnagyobb fájlokról és a potenciális problémákról. Telepíthető pip-pel: pip install git-sizer.
  • git-repo-size: Hasonló eszköz, amely szintén részletes méretanalízist biztosít.

Ezek az eszközök segítenek abban, hogy pontosan megértsd, mi teszi a repositoryt nagyméretűvé, és mely fájlokra érdemes fókuszálnod.

A Történelem Átírásának Kockázatai és Következményei

Mielőtt belevágnánk a fájlok törlésébe, elengedhetetlen, hogy megértsük a történelem átírásának súlyát és következményeit. A Git úgy lett tervezve, hogy a történelem elvileg megváltoztathatatlan legyen. Amikor törlünk egy fájlt a Git historyból, valójában nem töröljük a régi commitokat, hanem új commitokat hozunk létre, amelyek nem tartalmazzák az adott fájlt. Ez azt jelenti, hogy:

  • A commit SHA-azonosítók megváltoznak: Minden, amit módosítottunk a történelemben, egy új commit hash-t kap.
  • Mindenkinek szinkronizálnia kell: Ez a legkritikusabb pont egy megosztott repository esetén. Miután átírtuk a történelmet, MINDENKI MÁSNAK újra kell klónoznia a repositoryt, vagy alapos rebase/reset műveleteket kell végrehajtania, ami bonyolult és hibalehetőségeket rejt.
  • Adatvesztés kockázata: Helytelenül elvégzett művelet esetén elveszíthetjük a korábbi munkát. Ezért a biztonsági mentés létfontosságú!

Ezen okokból kifolyólag a történelem átírását csak a legvégső esetben, a legnagyobb körültekintéssel és előzetes kommunikációval szabad elvégezni. Ideális esetben a csapat többi tagja nem dolgozik a repositoryn, amíg ez a folyamat zajlik!

A Megoldás: Eszközök a Nagy Fájlok Eltávolítására

Most, hogy tudjuk, mit keresünk és megértjük a kockázatokat, nézzük meg, milyen eszközökkel tudjuk ténylegesen eltávolítani a nagy fájlokat a Git historyból.

1. A „DEPREKÁLT”, de Ismert: git filter-branch

Régebben a git filter-branch volt a Git hivatalos eszköze a történelem átírására. Bár képes elvégezni a feladatot, rendkívül lassú, bonyolult a használata, és sok buktatót rejt. A Git dokumentációja maga is lebeszél róla, és azt javasolja, hogy használjunk modernabb, hatékonyabb alternatívákat. Erősen javasoljuk, hogy NE használd ezt az eszközt, hacsak nincs rá különös okod! A továbbiakban a javasolt, modern eszközökre fókuszálunk.

2. A „MODERN” és Ajánlott: git filter-repo

A git filter-repo a git filter-branch utódja, és a Git fejlesztői közösség hivatalosan ezt ajánlja a történelem átírására. Sokkal gyorsabb, biztonságosabb, könnyebben használható és rugalmasabb.

Telepítés

A git filter-repo egy Python script, így pip-pel telepíthető:

pip install git-filter-repo

Győződj meg róla, hogy a Python és a pip megfelelően be van állítva a rendszereden.

Lépésről lépésre útmutató git filter-repo használatával

Ez a folyamat kritikus, ezért pontosan kövesd a lépéseket:

  1. Készíts biztonsági mentést! Ezt nem lehet elégszer hangsúlyozni. Készíts egy másolatot a repositoryról egy másik könyvtárba, vagy egyszerűen archiváld a .git mappát.
  2. Hozd létre a repository tiszta másolatát: A git filter-repo nem szereti, ha közvetlenül a klónozott repositoryn futtatják, mert az megőrzi a reflog-ot és egyéb referenciákat, amelyek megakadályozhatnák az objektumok tényleges törlését. Ideális esetben klónozz egy bare repositoryt a távoli repositoryról, vagy egy friss klónt, amiből eltávolítod a távoli kapcsolatot.
    • Ha a jelenlegi working directory-ban vagy:
      git clone --mirror /path/to/your/repo /path/to/your/repo_mirror.git
      cd /path/to/your/repo_mirror.git

      VAGY egy friss klónt:

      git clone --bare https://github.com/user/repo.git
      cd repo.git
    • Ha a már meglévő klónodon dolgoznál, győződj meg róla, hogy nincs benne semmi, amit nem akarsz véglegesen elveszíteni, majd futtasd:
      git remote rm origin

      Ezzel megszakítod a kapcsolatot a távoli repositoryval, így nem tudsz véletlenül rossz helyre push-olni.

  3. Futtasd a git filter-repo parancsot:

    Íme néhány gyakori példa:

    • Egy konkrét nagy fájl eltávolítása a teljes historyból:
      git filter-repo --path large_file.zip --invert-paths

      Ez a parancs eltávolítja a large_file.zip nevű fájlt minden commitból. A --invert-paths azt jelenti, hogy minden mást megtart, kivéve ezt a fájlt. Ha több fájlt szeretnél megadni, többször is használhatod a --path paramétert.

    • Minden .mp4 fájl eltávolítása a historyból:
      git filter-repo --path-glob '*.mp4' --invert-paths

      A --path-glob segítségével glob minták alapján adhatsz meg fájlokat.

    • Minden fájl eltávolítása, ami nagyobb, mint 10 MB (ez a leggyakoribb):
      git filter-repo --strip-blobs-bigger-than 10M

      Ez a parancs átfésüli a repository teljes historyját, és töröl minden olyan fájlt (blobt), ami nagyobb, mint 10 megabájt.

    • Egy könyvtár eltávolítása (pl. node_modules vagy .idea):
      git filter-repo --path .idea/ --invert-paths

      Vagy ha csak egy specific fájl, ami egy könyvtárban volt, pl assets/large_video.mp4:

      git filter-repo --path assets/large_video.mp4 --invert-paths
  4. Tisztítás és tömörítés: Miután a git filter-repo befejezte a munkáját, a Git objektumtár még mindig tartalmazhat referenciákat a régi, nagy fájlokra, amelyek nincsenek már elérhetőek a commit historyban. Ezeket el kell távolítani a repository fizikai méretének csökkentése érdekében:
    git reflog expire --expire=now --all
    git gc --prune=now --aggressive
    • git reflog expire --expire=now --all: Ez törli az összes reflog bejegyzést, ami referálhat a régi objektumokra.
    • git gc --prune=now --aggressive: Ez futtatja a Git szemétgyűjtőjét, eltávolítja a nem használt objektumokat, és tömöríti a repositoryt. A --aggressive opció alaposabb tisztítást végez, de tovább tarthat.
  5. Kényszerített push a távoli repositoryra: Most, hogy a lokális repositoryd tiszta és karcsú, vissza kell push-olnod a változásokat a távoli szerverre. Mivel a history átíródott, egy normál git push sikertelen lesz, mert a szerver nem tudja összevonni a helyi változásokat a távoliakkal. Emiatt kényszerített pushra van szükség:
    git push --force

    VAGY még jobb:

    git push --force-with-lease

    A --force-with-lease biztonságosabb, mert csak akkor engedélyezi a push-t, ha a távoli repository állapota megegyezik azzal, amit utoljára lehívtál. Ez megakadályozza, hogy véletlenül felülírd mások munkáját, ha ők időközben push-oltak a repositoryba.

  6. Kommunikáció a csapattal: EZ A LÉPÉS KRITIKUS! Tájékoztasd a csapat minden tagját, hogy a repository története átíródott, és mindenkinek újra kell klónoznia a repositoryt, vagy alaposabban frissíteni a saját helyi másolatát (pl. git reset --hard origin/main, majd git pull). A legjobb a repo újraklónozása!

3. Az „EGYSZERŰ” és Gyors: BFG Repo-Cleaner

A BFG Repo-Cleaner egy másik kiváló eszköz, amely kifejezetten a nagy fájlok és adatok eltávolítására lett tervezve a Git historyból. JVM-alapú, rendkívül gyors és egyszerű a használata.

Telepítés

Nincs szükség telepítésre a hagyományos értelemben. Csak töltsd le a JAR fájlt a hivatalos weboldalról (https://rtyley.github.io/bfg-repo-cleaner/).

Lépésről lépésre útmutató BFG Repo-Cleaner használatával

  1. Készíts biztonsági mentést! Ugyanaz, mint a git filter-repo esetén.
  2. Hozd létre a repository tiszta másolatát: A BFG-t is egy bare repositoryn javasolt futtatni:
    git clone --mirror https://github.com/user/repo.git
    cd repo.git
  3. Futtasd a BFG parancsot:

    Íme néhány gyakori példa:

    • Minden .mp4 fájl eltávolítása (és a cache-ből is):
      java -jar bfg.jar --delete-files *.mp4 my-repo.git
    • Egy konkrét nagy fájl eltávolítása:
      java -jar bfg.jar --delete-files large_file.zip my-repo.git
    • Minden fájl eltávolítása, ami nagyobb, mint 10 MB:
      java -jar bfg.jar --strip-blobs-bigger-than 10M my-repo.git
    • Egy könyvtár eltávolítása (pl. node_modules):
      java -jar bfg.jar --delete-folders node_modules my-repo.git
  4. Tisztítás és tömörítés: A BFG futtatása után lépj vissza a repository könyvtárába, majd futtasd a következőket:
    git reflog expire --expire=now --all
    git gc --prune=now --aggressive
  5. Kényszerített push a távoli repositoryra:
    git push --force

    Vagy a biztonságosabb:

    git push --force-with-lease
  6. Kommunikáció a csapattal: Ne feledd tájékoztatni mindenkit a változásokról!

Fontos Tanácsok és Legjobb Gyakorlatok

  • Mindig kommunikálj: Különösen csapatmunkánál elengedhetetlen, hogy mindenkit tájékoztass a repository történetének átírásáról. Egyeztess velük időpontot, amikor mindenki szüneteltetheti a munkát a repositoryn.
  • Készíts biztonsági mentést: Mielőtt bármibe belekezdenél, mindig készíts teljes biztonsági mentést a repositoryról.
  • Használj --force-with-lease-t a --force helyett: Ez egy sokkal biztonságosabb módja a kényszerített push-nak, mivel ellenőrzi, hogy a távoli repository nem változott-e az utolsó lehívásod óta.
  • Tisztítsd meg a cache-t: A git gc --prune=now --aggressive kulcsfontosságú lépés a fizikai méret csökkentéséhez.
  • A .gitignore fájl szerepe: A legjobb megelőzés, ha sosem engeded be a nagy és felesleges fájlokat a repositoryba. Használd a .gitignore fájlt a projekted gyökerében, hogy kizárd a fordítási eredményeket, log fájlokat, ideiglenes fájlokat, nagy médiafájlokat stb.
  • A jövőbeni megelőzés: Git LFS (Large File Storage): Ha gyakran kell nagy médiafájlokat (képeket, videókat, hangfájlokat) tárolnod a repositorydban, fontold meg a Git LFS használatát. Ez a bővítmény lehetővé teszi, hogy a Git csak egy kis mutatót tároljon a nagyméretű fájlok helyett, a tényleges fájlokat pedig egy különálló tárolóban helyezi el. Ez drasztikusan csökkenti a repository méretét és a klónozási időt.

Konklúzió

A Git history tisztítása, különösen a nagy fájlok eltávolítása, egy alapvető karbantartási feladat, amely jelentősen javíthatja a fejlesztési munkafolyamat sebességét és hatékonyságát. Bár a történelem átírása elsőre ijesztőnek tűnhet, a megfelelő eszközökkel (mint a git filter-repo vagy a BFG Repo-Cleaner) és a fenti óvintézkedések betartásával biztonságosan elvégezhető. Ne feledd a biztonsági mentést és a kommunikációt, és élvezd a karcsú, gyors Git repository előnyeit!

Végezetül, gondolj a jövőre: a .gitignore helyes használata és a Git LFS bevezetése segít megelőzni, hogy a repositoryd valaha is újra elhízzon. Egy tiszta repository, egy boldog fejlesztőcsapat!

Leave a Reply

Az e-mail címet nem tesszük közzé. A kötelező mezőket * karakterrel jelöltük