Ora lo stesso file "enorme" risiede in entrambi i fork dello sviluppatore sul server. Non crea automaticamente un collegamento reale
In realtà, con Git 2.20, questo problema potrebbe scomparire, a causa delle isole delta , un nuovo modo di eseguire il calcolo del delta in modo che un oggetto che esiste in un fork non venga trasformato in un delta rispetto a un altro oggetto che non appare nello stesso repository fork .
Vedere commit fe0ac2f, commit 108f530, commit f64ba53 (16 agosto 2018) di Christian Couder (chriscool
).
Aiutato da:Jeff King (peff
) e Duy Nguyen (pclouds
).
Vedere commit 9eb0986, commit 16d75fa, commit 28b8a73, commit c8d521f (16 agosto 2018) di Jeff King (peff
).
Aiutato da:Jeff King (peff
) e Duy Nguyen (pclouds
).
Aggiungi
delta-islands.{c,h}
I provider di hosting che consentono agli utenti di eseguire il "fork" dei repository esistenti vogliono che tali fork condividano quanto più spazio possibile su disco.
Le alternative sono una soluzione esistente per conservare tutti gli oggetti di tutti i fork in un repository centrale univoco, ma questo può avere alcuni inconvenienti.
Specialmente quando si impacchetta il repository centrale, verranno creati dei delta tra oggetti di fork diversi.Ciò può rendere la clonazione o il recupero di un fork molto più lento e molto più impegnativo per la CPU poiché Git potrebbe dover calcolare nuovi delta per molti oggetti per evitare di inviare oggetti da un diverso fork.
Poiché l'inefficienza si verifica principalmente quando un oggetto viene eliminato rispetto a un altro oggetto che non esiste nello stesso fork, suddividiamo gli oggetti in insiemi che compaiono nello stesso fork e definiamo "isole delta".
Quando si trova la base delta, non permettiamo che un oggetto al di fuori della stessa isola venga considerato come sua base.Quindi "isole delta" è un modo per archiviare oggetti da fork diversi nello stesso repository e file di pacchetto senza avere delta tra oggetti da fork diversi.
Questa patch implementa il meccanismo delle isole delta in "
delta-islands.{c,h}
", ma non ne fa ancora uso.Alcuni nuovi campi sono stati aggiunti in '
struct object_entry
' in "pack-objects.h
" però.
Vedi Documentation/git-pack-objects.txt
:Isola Delta:
ISOLE DELTA
Quando possibile,
pack-objects
cerca di riutilizzare i delta su disco esistenti per evitare di doverne cercare di nuovi al volo. Questa è un'ottimizzazione importante per servire i recuperi, perché significa che il server può evitare di gonfiare la maggior parte degli oggetti e inviare semplicemente i byte direttamente dal disco.Questa ottimizzazione non può funzionare quando un oggetto viene archiviato come delta rispetto a una base che il destinatario non ha (e che non stiamo già inviando). In tal caso il server "rompe" il delta e deve trovarne uno nuovo, che ha un alto costo della CPU. Pertanto è importante per le prestazioni che l'insieme di oggetti nelle relazioni delta su disco corrisponda a ciò che un client recupererebbe.
In un normale repository, questo tende a funzionare automaticamente.
Gli oggetti sono per lo più raggiungibili dai rami e dai tag, ed è quello che i client recuperano. È probabile che qualsiasi delta che troviamo sul server sia tra gli oggetti che il client ha o avrà.Ma in alcune configurazioni del repository, potresti avere diversi gruppi correlati ma separati di ref tips, con i client che tendono a recuperare quei gruppi in modo indipendente.
Ad esempio, immagina di ospitare diversi "fork" di un repository in un singolo archivio di oggetti condivisi e di consentire ai client di visualizzarli come repository separati tramite GIT_NAMESPACE o repository separati utilizzando il meccanismo alternativo.
Un ingenuo repack potrebbe scoprire che il delta ottimale per un oggetto è rispetto a una base che si trova solo in un altro fork.
Ma quando un client recupera, non avrà l'oggetto di base e dovremo trovare un nuovo delta al volo.Una situazione simile può verificarsi se hai molti riferimenti al di fuori di
refs/heads/
erefs/tags/
che puntano a oggetti correlati (ad esempio,refs/pull
orefs/changes
utilizzato da alcuni provider di hosting). Per impostazione predefinita, i client recuperano solo head e tag e i delta rispetto agli oggetti trovati solo in quegli altri gruppi non possono essere inviati così come sono.Le isole delta risolvono questo problema consentendoti di raggruppare i tuoi riferimenti in "isole" distinte .
Pack-objects calcola quali oggetti sono raggiungibili da quali isole e si rifiuta di creare un delta da un oggetto
A
contro una base che non è presente in tutto ilA
le isole. Ciò si traduce in pacchetti leggermente più grandi (perché perdiamo alcune opportunità di delta), ma garantisce che il recupero di un'isola non dovrà ricalcolare i delta al volo a causa dell'attraversamento dei confini dell'isola.
Un effetto collaterale però:alcuni comandi erano più prolissi. Git 2.23 (Q3 2019) risolve questo problema.
Vedi commit bdbdf42 (20 giugno 2019) di Jeff King (peff
).
delta-islands
:rispettaprogress
bandieraIl codice dell'isola delta stampa sempre "
Marked %d islands
", anche se il progresso è stato soppresso con--no-progress
o inviando stderr a un non-tty.Passiamo un
progress
booleano aload_delta_islands()
.
Facciamo già la stessa cosa per la barra di avanzamento inresolve_tree_islands()
.
Ho deciso di fare questo:
shared-objects-database.git/
foo.git/
objects/info/alternate (will have ../../shared-objects-database.git/objects)
bar.git/
objects/info/alternate (will have ../../shared-objects-database.git/objects)
baz.git/
objects/info/alternate (will have ../../shared-objects-database.git/objects)
Tutti i fork avranno una voce nel loro file objects/info/alternates che fornisce un percorso relativo al repository del database degli oggetti.
È importante rendere il database degli oggetti un repository, perché possiamo salvare oggetti e riferimenti di utenti diversi che hanno un repository con lo stesso nome.
Passaggi:
git init --bare shared-object-database.git
-
Eseguo le seguenti righe di codice ogni volta che c'è un push a qualsiasi fork (tramite post-recieve) o eseguendo un cronjob
for r in list-of-forks do
(cd "$r" &&git push ../shared-objects-database.git "refs/:refs/remotes/$r/ " &&echo ../../shared-objects-database.git/objects>objects/info/alternates# da salvare aggiungo gli oggetti "grassi" alle alternative ogni volta)fatto
Quindi nel prossimo "git gc" tutti gli oggetti in fork che già esistono in alternanza verranno cancellati.
git repack -adl
è anche un'opzione!
In questo modo risparmiamo spazio in modo che due utenti che spingono gli stessi dati sui rispettivi fork sul server condividano gli oggetti.
Dobbiamo impostare gc.pruneExpire
variabile fino a never
nel database degli oggetti condivisi. Solo per sicurezza!
Per sfoltire occasionalmente gli oggetti, aggiungi tutti i fork come remoti a shared, fetch e prune! Git farà il resto!
(Finalmente ho trovato una soluzione che funziona per me! (Non testata in produzione! :p Grazie a questo post.)