Basi

Git LFS: come conservare i file di grandi dimensioni in un repository Git

Aggiornato: · Skillaria.Top

Git LFS (Large File Storage) è un'estensione di Git che conserva i file binari di grandi dimensioni su un server separato e inserisce nel repository solo piccoli file puntatore. Il clone diventa veloce, la cronologia non si gonfia e il lavoro con i file resta quello abituale: git add, commit e push.

Che cos'è Git LFS e a cosa serve

Git LFS (Large File Storage) è l'estensione ufficiale di Git per conservare file di grandi dimensioni: video, mockup in PSD, dataset, modelli di reti neurali, asset per i giochi. Al posto del file vero e proprio, nel commit finisce un puntatore di testo di circa 130 byte, mentre il contenuto va in un archivio LFS separato sul server. Durante il checkout l'estensione reinserisce il file reale nella cartella di lavoro, quindi per voi tutto appare come un normale Git.

Il problema che Git LFS risolve sta nel funzionamento di Git stesso. Ogni versione di ogni file resta per sempre nella cronologia, e al clone viene scaricata l'intera storia. Se avete sostituito dieci volte un video da 200 MB, il repository pesa già circa 2 GB, e ogni nuovo sviluppatore scarica tutte e dieci le versioni anche se gli serve solo l'ultima. La compressione e le differenze (delta) che funzionano bene per il testo sono quasi inutili sui file binari.

Con LFS, al clone si scaricano solo le versioni dei file grandi relative al commit corrente. Le versioni precedenti restano sul server e vengono recuperate quando passate a un commit vecchio.

Come funziona Git LFS

Il meccanismo si basa sui filtri di Git, clean e smudge. Quando eseguite git add su un file tracciato da LFS, scatta il filtro clean: salva il contenuto nella cache locale .git/lfs/objects e passa all'indice solo il puntatore. Al checkout il filtro smudge fa il contrario: trova l'oggetto tramite il suo hash nella cache (o lo scarica dal server) e scrive il file vero.

Un puntatore ha questo aspetto:

version https://git-lfs.github.com/spec/v1
oid sha256:4d7a214614ab2935c943f9e0ff69d22eadbb8f32b1258daaa5e2ca24d17e2393
size 209715200

Sono tre righe: la versione della specifica, l'SHA-256 del contenuto e la dimensione in byte. È questo che finisce nella cronologia Git, ed è per questo che la storia resta leggera. Al git push entra in gioco l'hook pre-push: prima si caricano via API LFS i nuovi oggetti, poi con il protocollo normale si inviano i commit.

Quali file affidare a LFS lo decide il file .gitattributes nella radice del repository. Viene committato insieme al codice, quindi le regole sono le stesse per tutto il team.

Come installare Git LFS

In Git per Windows l'estensione è già inclusa nel programma di installazione. Su macOS e Linux si installa come pacchetto:

# macOS (Homebrew)
brew install git-lfs

# Debian / Ubuntu
sudo apt install git-lfs

# Fedora
sudo dnf install git-lfs

Dopo l'installazione eseguite una volta, per il vostro utente:

git lfs install

Il comando registra i filtri LFS nel file globale ~/.gitconfig e installa gli hook nel repository corrente, se vi trovate dentro uno. Per verificare che sia tutto a posto usate git lfs version, mentre git lfs env mostra la configurazione dettagliata (indirizzo del server, percorsi della cache).

Come iniziare a tracciare i file grandi

Lo scenario tipico per un progetto nuovo:

git lfs track "*.psd"
git lfs track "*.mp4"
git lfs track "models/**"

git add .gitattributes
git add design/banner.psd
git commit -m "Aggiungere il mockup del banner tramite LFS"
git push origin main

Le virgolette attorno al modello sono obbligatorie: senza di esse la shell espande *.psd nell'elenco dei file della cartella corrente e la regola risulterebbe sbagliata. Dopo git lfs track compare in .gitattributes una riga come questa:

*.psd filter=lfs diff=lfs merge=lfs -text

L'attributo -text disattiva la conversione dei fine riga, che rovinerebbe un file binario. L'ordine conta: prima la regola track, poi il git add del file. Se il file era già stato aggiunto in modo normale prima della regola, è rimasto nella cronologia come blob ordinario.

Come verificare che un file sia davvero in LFS

git lfs ls-files
4d7a214614 * design/banner.psd
9c1e0b7a3f * video/intro.mp4

git lfs status

git lfs ls-files mostra i file del commit corrente conservati in LFS. L'asterisco significa che il contenuto è stato scaricato, il trattino che nella copia di lavoro c'è solo il puntatore. L'elenco dei modelli di tracciamento lo stampa git lfs track senza argomenti, mentre una regola si rimuove con git lfs untrack "*.psd".

Clonare e ricevere i file

Un normale git clone funziona con LFS in modo trasparente: se l'estensione è installata, i file grandi vengono scaricati automaticamente. Se però al collega manca LFS, nella copia di lavoro vedrà puntatori di testo al posto delle immagini — è il sintomo più comune di «al posto del PSD c'è un testo». Si risolve installando l'estensione e poi eseguendo:

git lfs install
git lfs pull

git lfs pull scarica gli oggetti del commit corrente e li inserisce nella cartella di lavoro. Esiste anche git lfs fetch, che si limita a scaricare nella cache senza toccare i file. Con il flag --all carica gli oggetti di tutti i riferimenti, utile per un backup completo o per il trasferimento su un altro server.

Come clonare senza i file grandi

In CI, o quando serve solo il codice, scaricare gigabyte di asset non ha senso. Una variabile d'ambiente disattiva il filtro smudge:

GIT_LFS_SKIP_SMUDGE=1 git clone https://example.com/team/game.git
cd game
git lfs pull --include="textures/ui/**"

Il repository viene clonato con i puntatori, poi scaricate in modo selettivo i file che vi servono con --include (esiste anche --exclude). Così le build nelle pipeline diventano sensibilmente più rapide.

Come spostare nel Git LFS i file già presenti

Situazione frequente: il repository è già gonfio e i file grandi sono nella cronologia. Il comando git lfs track non agisce sul passato, vale solo per i nuovi commit. Per riscrivere la storia si usa git lfs migrate.

Prima valutate che cosa occupa lo spazio:

git lfs migrate info --everything --top=10

Poi spostate i tipi che vi interessano in tutti i rami:

git lfs migrate import --include="*.psd,*.mp4" --everything
git push --force --all
git push --force --tags

La migrazione riscrive ogni commit in cui comparivano quei file, quindi cambiano tutti gli hash. È la stessa situazione del rebase di rami già pubblicati: bisogna avvisare tutti i partecipanti, che dopo il push forzato dovranno clonare di nuovo il repository o azzerare i propri rami. Prima della migrazione fate una copia di sicurezza (git clone --mirror).

Se riscrivere la storia non è possibile, c'è una via più morbida: git lfs migrate import --no-rewrite percorso/del/file. Crea un nuovo commit che da quel momento sposta i file in LFS. Le vecchie versioni restano nella cronologia, ma la crescita del repository si ferma.

Blocco dei file: protezione dai conflitti sui binari

Due grafici modificano lo stesso PSD: Git non riesce a unire le loro modifiche e uno dei due lavori andrebbe perso. Per questi casi LFS offre i lock. Si contrassegna il tipo di file come bloccabile:

git lfs track "*.psd" --lockable

In .gitattributes compare l'attributo lockable, e i file di questo tipo nella copia di lavoro diventano di sola lettura finché non li bloccate:

git lfs lock design/banner.psd
git lfs locks
design/banner.psd	anna	ID:123

# dopo il push delle modifiche
git lfs unlock design/banner.psd

Finché il file è bloccato, il push di modifiche da parte di un'altra persona viene rifiutato. I lock sono gestiti dal server, quindi funzionano sui principali hosting Git, ma su un server autogestito potrebbero non essere disponibili. L'amministratore può rimuovere il lock di un altro con git lfs unlock --force.

Dove vivono gli oggetti LFS e quanto costano

Gli oggetti LFS risiedono su un server che supporta l'API LFS. La implementano i principali hosting Git, le soluzioni self-hosted e alcuni server dedicati. Gli hosting cloud applicano limiti di spazio e di traffico LFS, che variano tra servizi e piani: verificate le condizioni attuali della vostra piattaforma prima di caricarvi dataset da centinaia di gigabyte.

Ricordate che il traffico si conta a ogni download: una CI che clona ad ogni commit il repository con i file LFS può esaurire il limite più in fretta delle persone. Conservate .git/lfs tra una build e l'altra oppure usate GIT_LFS_SKIP_SMUDGE.

Anche la cache locale cresce. Il comando git lfs prune elimina gli oggetti vecchi che sono già sul server e non servono ai commit correnti o recenti.

Quando Git LFS è adatto e quando no

SituazioneLFS è adatto?Commento
Asset di giochi, mockup, audio, videoSìIl caso classico: binari che cambiano spesso
Modelli ML e dataset di medie dimensioni accanto al codiceSì, tenendo d'occhio le quotePer dati molto grandi sono più adatti gli strumenti specializzati di versionamento dei dati
Artefatti di build compilatiNoIl posto giusto è un registro di artefatti o le release, non Git
Dipendenze (node_modules, vendor)NoLe installa il gestore di pacchetti: aggiungetele a .gitignore
File di testo di grandi dimensioni (dump SQL, CSV)DipendeGit gestisce bene il testo con i delta; LFS serve se i file sono enormi e nel diff non si leggono quasi
Segreti e chiavi privateMaiLFS non cifra i dati: non è un archivio di segreti

Errori tipici e come correggerli

Nella copia di lavoro c'è un puntatore di testo al posto del file

LFS non è installato, oppure il clone è stato fatto con GIT_LFS_SKIP_SMUDGE=1. Eseguite git lfs install e git lfs pull.

Un file è entrato nella cronologia senza passare da LFS

La regola track è stata aggiunta dopo il git add. Se il commit non è ancora stato inviato, rimuovete il file dall'indice (git rm --cached file), verificate che la regola sia in .gitattributes e aggiungetelo di nuovo. Se è già stato inviato, usate git lfs migrate import. Per trovare questi file aiuta git lfs fsck --pointers.

Il push viene rifiutato per la dimensione del file

Molti hosting limitano la dimensione di un singolo oggetto nel Git normale. Un messaggio come «this exceeds the file size limit» significa che il file andava affidato a LFS. Riscrivete l'ultimo commit o la storia, come descritto sopra: un semplice commit «rimuovi il file» non basta, perché il file resta nei commit precedenti.

Dopo git lfs migrate i colleghi hanno tutto in disordine

I loro rami locali si basano sugli hash vecchi. La soluzione più sicura è clonare di nuovo il repository; se hanno lavoro non ancora inviato, possono trasferirlo sui nuovi rami con cherry-pick.

Riepilogo dei comandi Git LFS

ComandoChe cosa fa
git lfs installConfigura filtri e hook
git lfs track "*.ext"Aggiunge il modello a .gitattributes
git lfs untrack "*.ext"Rimuove il modello
git lfs ls-filesFile in LFS per il commit corrente
git lfs pullScarica e inserisce gli oggetti
git lfs fetch --allScarica nella cache gli oggetti di tutti i riferimenti
git lfs migrate import --include="..." --everythingSposta nel LFS i file della cronologia
git lfs lock / unlock / locksGestione dei blocchi
git lfs pruneSvuota la cache locale dagli oggetti vecchi
git lfs envDiagnostica della configurazione

Git LFS sposta i file binari grandi fuori dalla cronologia e lascia nei commit puntatori leggeri. La regola principale è configurare git lfs track prima del primo commit di file grandi, committare .gitattributes e controllare le quote dell'hosting. Se i file sono già nella cronologia, aiuta git lfs migrate, ma significa riscrivere la storia con tutte le conseguenze. Il lavoro con la cronologia, il rebase e gli altri strumenti avanzati di Git lo analizziamo in pratica nel corso di Git.

Domande frequenti

Git LFS è gratuito?

L'estensione in sé è open source e gratuita. Si paga lo spazio e il traffico sull'hosting Git, se si superano i limiti gratuiti del proprio piano.

Da quale dimensione un file va considerato grande per LFS?

Non esiste un limite rigido; di solito in LFS si mettono i binari di qualche megabyte che cambiano spesso. I file di testo, anche grandi, Git li gestisce bene senza LFS.

Si può tornare da Git LFS a Git normale?

Sì, con il comando git lfs migrate export --include="*.psd" --everything, che riscrive la cronologia riportando i file nel Git normale. Poi bisogna rimuovere le regole da .gitattributes e fare un force push.

Funziona git diff sui file in LFS?

Git mostra la modifica del puntatore, non del contenuto, perché i file sono binari. Per immagini e documenti il confronto si fa con strumenti esterni.

Serve LFS a ogni membro del team?

Sì: senza l'estensione il collega vedrebbe puntatori al posto dei file e i suoi commit potrebbero aggiungere per errore file grandi fuori da LFS.

Impara l’argomento in video

Questo argomento è trattato in modo approfondito, con pratica, nel corso «Git da zero a sviluppatore sicuro».

Vai al corso