Il problema dei file di grandi dimensioni in Git
Tradizionalmente, alcune aziende e istituzioni sono state lontane da Git a causa dell'inefficienza nella gestione di file binari di grandi dimensioni. Gli sviluppatori di videogiochi e le società di media hanno a che fare con trame complesse, video full-motion e file audio di alta qualità. Gli istituti di ricerca devono tenere traccia di grandi set di dati che possono essere gigabyte o terabyte. Git ha difficoltà a mantenere questi file di grandi dimensioni.
Per capire il problema, dobbiamo dare un'occhiata a come Git tiene traccia dei file. Ogni volta che c'è un commit, Git crea un nodo oggetto con un puntatore al suo genitore o più genitori. Il modello di dati Git è noto come grafo aciclico diretto (DAG). Il modello DAG garantisce che la relazione genitore-figlio non possa mai formare cicli.
Possiamo ispezionare il funzionamento interno del modello DAG. Ecco un esempio di tre commit in un repository:
$ git log --oneline2beb263 Commit C: aggiunta immagine1.jpeg
866178e Commit B: aggiungi b.TXT
d48dd8b Commit A: aggiungi a.TXT
In Commit A e B, abbiamo aggiunto il file di testo a.txt e b.TXT. Quindi in Commit C, abbiamo aggiunto un file immagine chiamato image1.jpeg. Possiamo visualizzare il DAG come segue:
Commit C Commit B Commit A2beb263 --> 866178e --> d48dd8b
Se controlliamo l'ultimo commit con il seguente comando:
$ git cat-file -p 2beb263albero 7cc17ba5b041fb227b9ab5534d81bd836183a4e3
genitore 866178e37df64d9f19fa77c00d5ba9d3d4fc68f5
autore Zak H
committente Zak H
Commit C: immagine aggiunta1.jpeg
Possiamo vedere che Commit C (2beb263) ha Commit B (866178e) come genitore. Ora se ispezioniamo l'oggetto albero di Commit C (7cc17ba), possiamo vedere i blob (oggetti binari di grandi dimensioni):
$ git cat-file -p 7cc17ba100644 chiazza e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a.TXT
100644 chiazza e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 b.TXT
100644 blob a44a66f9e06a8faf324d3ff3e11c9fa6966bfb56 image1.jpeg
Possiamo controllare la dimensione del blob di immagine:
$ git cat-file -s a44a66f9e871680
Git tiene traccia dei cambiamenti in questa struttura ad albero. Facciamo una modifica all'immagine1.jpeg e controlla la cronologia:
$ git log --oneline2e257db Commit D: immagine modificata1.jpeg
2beb263 Commit C: aggiunta immagine1.jpeg
866178e Commit B: aggiungi b.TXT
d48dd8b Commit A: aggiungi a.TXT
Se controlliamo l'oggetto Commit D (2e257db):
$ git cat-file -p 2e257dbalbero 2405fad67610acf0f57b87af36f535c1f4f9ed0d
genitore 2beb263523725e1e8f9d96083140a4a5cd30b651
autore Zak H
committente Zak H
Commit D: immagine modificata1.jpeg
E l'albero (2405fad) al suo interno:
$ git cat-file -p 2405fad100644 chiazza e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 a.TXT
100644 chiazza e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 b.TXT
100644 blob cb4a0b67280a92412a81c60df36a15150e713095 image1.jpeg
Si noti che l'hash SHA-1 per image1.jpeg è cambiato. Significa che ha creato un nuovo blob per image1.jpeg. Possiamo controllare le dimensioni del nuovo blob:
$ git cat-file -s cb4a0b61063696
Ecco un modo per visualizzare la struttura DAG sopra:
Commit D Commit C Commit B Commit A| | | |
2e257db --> 2beb263 --> 866178e --> d48dd8b
| | | |
Albero4 Albero3 Albero2 Albero1
| | | |
BLOB BLOB BLOB BLOB
Ogni oggetto commit mantiene il proprio albero. I blob sono mantenuti all'interno di quell'albero. Git ottimizza lo spazio assicurandosi che memorizzi solo le differenze e utilizzi la compressione per l'archiviazione. Ma per le modifiche ai file binari, Git deve memorizzare interi file nei BLOB perché è difficile determinare le differenze. Inoltre, i file immagine, video e audio sono già compressi. Di conseguenza, per ogni istanza di un file binario modificato, l'albero finisce con un grande blob.
Pensiamo a un esempio in cui apportiamo più modifiche a un file immagine di 100 MB.
Commit C --> Commit B --> Commit A| | |
Albero3 Albero2 Albero1
| | |
Blob3 Blob2 Blob1
300 MB 200 MB 100 MB
Ogni volta che cambiamo il file, Git deve creare un blob da 100 MB. Quindi solo dopo 3 commit, il repository Git è di 300 MB. Puoi vedere che la dimensione del repository Git può esplodere rapidamente. Poiché Git è un controllo di versione distribuito, scaricherai l'intero repository nella tua istanza locale e lavorerai molto con i rami. Quindi i grandi blob diventano un collo di bottiglia delle prestazioni.
Git LFS risolve il problema sostituendo i BLOB con file puntatori leggeri (PF) e creando un meccanismo per archiviare i BLOB altrove.
Commit C --> Commit B --> Commit A| | |
Albero3 Albero2 Albero1
| | |
PF3 PF2 PF1
Localmente Git archivia i blob nella cache Git LFS e in remoto li memorizzerà nell'archivio Git LFS su GitHub o BitBucket.
PF1 --> Blob1PF2 --> Blob2
PF3 --> Blob3
Ora, quando hai a che fare con il repository Git, i file PF leggeri verranno utilizzati per le operazioni di routine. I blob verranno recuperati solo quando necessario. Ad esempio, se controlli Commit C, Git LFS cercherà il puntatore PF3 e scaricherà Blob3. Quindi il repository di lavoro sarà più snello e le prestazioni saranno migliori. Non devi preoccuparti dei file del puntatore. Git LFS li gestirà dietro le quinte.
Installazione ed esecuzione di Git LFS
Ci sono stati precedenti tentativi di risolvere il problema dei file di grandi dimensioni di Gitit. Ma Git LFS ha avuto successo perché è facile da usare. Devi solo installare LFS e dirgli quali file tenere traccia.
Puoi installare Git LFS usando i seguenti comandi:
$ sudo apt-get install software-properties-common$ curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
$ sudo apt-get install git-lfs
$ git lfs install
Una volta installato Git LFS, puoi tenere traccia dei file che desideri:
$ git lfs track "*.jpeg"Monitoraggio "*.jpeg"
L'output mostra che Git LFS sta monitorando i file JPEG. Quando inizi a tracciare con LFS, troverai un .gitattributes file che avrà una voce che mostra i file tracciati. Il .il file gitattributes usa la stessa notazione di .gitignore file. Ecco come il contenuto di .gitattributes guarda:
$ cat .gitattributi*.jpeg filter=lfs diff=lfs merge=lfs -text
Puoi anche trovare quali file vengono tracciati usando il seguente comando:
$ git lfs trackElenco dei pattern tracciati
*.jpeg (.gitattributi)
Se vuoi interrompere il monitoraggio di un file, puoi utilizzare il seguente comando:
$ git lfs untrack "*.jpeg"Annullamento tracciamento "*.jpeg"
Per le operazioni generali di Git, non devi preoccuparti di LFS. Si occuperà automaticamente di tutte le attività di backend. Dopo aver configurato Git LFS, puoi lavorare sul repository come qualsiasi altro progetto.
Ulteriori studi
Per argomenti più avanzati, consulta le seguenti risorse:
- Spostare il repository Git LFS tra host
- Eliminazione dei file Git LFS locali
- Rimozione di file Git LFS remoti dal server
- Sito web Git LFS
- Documentazione Git LFS
Riferimenti:
- git-lfs.github.com: repository GitHub
- github.com/git-lfs/git-lfs/tree/master/docs: Documentazione GitHub per Git LFS
- atlante.com/git/tutorials/git-lfs: Tutorial Atlassian
- Youtube.com: Cos'è Git LFS?
- Youtube.com: Monitoraggio di file enormi con Git LFS di Tim Pettersen, Atlassian
- Youtube.com: Gestire file enormi sullo spazio di archiviazione giusto con Git LFS, YouTube
- Youtube.com: Git Large File Storage - Come lavorare con file di grandi dimensioni, YouTube
- Askubuntu.com/questions/799341: come-installare-git-lfs-on-ubuntu-16-04
- github.com/git-lfs/git-lfs/blob/master/INSTALLAZIONE.md: Guida all'installazione