Jetzt befindet sich dieselbe "riesige" Datei in beiden Forks des Entwicklers auf dem Server. Es erstellt nicht automatisch einen festen Link
Tatsächlich könnte dieses Problem mit Git 2.20 aufgrund von Delta-Inseln verschwinden , eine neue Art der Delta-Berechnung, sodass ein Objekt, das in einem Fork existiert, nicht zu einem Delta gegen ein anderes Objekt gemacht wird, das nicht in demselben Fork-Repository erscheint .
Siehe commit fe0ac2f, commit 108f530, commit f64ba53 (16. August 2018) von Christian Couder (chriscool
).
Unterstützt von:Jeff King (peff
) und Duy Nguyen (pclouds
).
Siehe Commit 9eb0986, Commit 16d75fa, Commit 28b8a73, Commit c8d521f (16. August 2018) von Jeff King (peff
). ).
Unterstützt von:Jeff King (peff
) und Duy Nguyen (pclouds
).
Fügen Sie delta-islands.{c,h}
hinzu
Hosting-Provider, die es Benutzern erlauben, bestehende Repositories zu "forken", möchten, dass diese Forks so viel Speicherplatz wie möglich gemeinsam nutzen.
Alternativen sind eine bestehende Lösung, um alle Objekte aus allen Forks in einem einzigen zentralen Repository zu halten, aber dies kann einige Nachteile haben.
Insbesondere beim Packen des zentralen Repositorys werden Deltas zwischen Objekten aus verschiedenen Forks erstellt.
Dies kann das Klonen oder Abrufen eines Forks viel langsamer und viel CPU-intensiver machen, da Git möglicherweise neue Deltas für viele Objekte berechnen muss, um zu vermeiden, dass Objekte von einem anderen Fork gesendet werden.
Da die Ineffizienz hauptsächlich entsteht, wenn ein Objekt gegen ein anderes Objekt, das nicht in derselben Verzweigung existiert, deltifiziert wird, unterteilen wir Objekte in Mengen, die in derselben Verzweigung vorkommen, und definieren „Delta-Inseln“.
Beim Finden einer Delta-Basis erlauben wir nicht, dass ein Objekt außerhalb derselben Insel als seine Basis betrachtet wird.
Also sind "Delta-Inseln" eine Möglichkeit, Objekte aus verschiedenen Forks im selben Repository und Packfile zu speichern, ohne dass es Deltas zwischen Objekten aus verschiedenen Forks gibt.
Dieser Patch implementiert den Delta-Inseln-Mechanismus in „delta-islands.{c,h}
", macht aber noch keinen Gebrauch davon.
Ein paar neue Felder wurden in 'struct object_entry
hinzugefügt ' in "pack-objects.h
" obwohl.
Siehe Documentation/git-pack-objects.txt
:Insel Delta:
DELTA-INSELN
Wenn möglich, pack-objects
versucht, vorhandene On-Disk-Deltas wiederzuverwenden, um nicht im laufenden Betrieb nach neuen suchen zu müssen. Dies ist eine wichtige Optimierung für das Bereitstellen von Abrufen, da der Server das Aufblasen der meisten Objekte überhaupt vermeiden und die Bytes einfach direkt von der Festplatte senden kann.
Diese Optimierung kann nicht funktionieren, wenn ein Objekt als Delta gegen eine Basis gespeichert wird, die der Empfänger nicht hat (und die wir nicht bereits senden). In diesem Fall "bricht" der Server das Delta und muss ein neues finden, was hohe CPU-Kosten verursacht. Daher ist es für die Leistung wichtig, dass der Satz von Objekten in On-Disk-Delta-Beziehungen mit dem übereinstimmen, was ein Client abrufen würde.
In einem normalen Repository funktioniert dies automatisch.
Die Objekte sind meistens über die Zweige und Tags erreichbar, und das ist es, was Clients abrufen. Alle Deltas, die wir auf dem Server finden, liegen wahrscheinlich zwischen Objekten, die der Client hat oder haben wird.
Aber in einigen Repository-Setups haben Sie möglicherweise mehrere verwandte, aber separate Gruppen von Ref-Tipps, wobei Clients dazu neigen, diese Gruppen unabhängig voneinander abzurufen.
Stellen Sie sich zum Beispiel vor, Sie hosten mehrere "Forks" eines Repositorys in einem einzigen gemeinsam genutzten Objektspeicher und lassen Clients diese als separate Repositories über GIT_NAMESPACE oder separate Repositories mithilfe des Alternativmechanismus anzeigen.
Ein naives Umpacken kann feststellen, dass das optimale Delta für ein Objekt gegen eine Basis ist, die nur in einer anderen Gabel gefunden wird.
Aber wenn ein Client abruft, wird er das Basisobjekt nicht haben und wir müssen spontan ein neues Delta finden.
Eine ähnliche Situation kann auftreten, wenn Sie viele Referenzen außerhalb von refs/heads/
haben und refs/tags/
die auf verwandte Objekte verweisen (z. B. refs/pull
oder refs/changes
von einigen Hosting-Providern verwendet). Standardmäßig rufen Clients nur Köpfe und Tags ab, und Deltas zu Objekten, die nur in diesen anderen Gruppen gefunden werden, können nicht unverändert gesendet werden.
Delta-Inseln lösen dieses Problem, indem sie es Ihnen ermöglichen, Ihre Refs in verschiedene "Inseln" zu gruppieren .
Pack-Objects berechnet, welche Objekte von welchen Inseln aus erreichbar sind, und weigert sich, ein Delta von einem Objekt A
zu erstellen gegen eine Base, die nicht in allen A
vorhanden ist 's Inseln. Dies führt zu etwas größeren Paketen (weil wir einige Delta-Möglichkeiten verpassen), garantiert aber, dass ein Abruf einer Insel Deltas nicht im laufenden Betrieb neu berechnen muss, da Inselgrenzen überschritten werden.
Ein Nebeneffekt:Einige Befehle waren ausführlicher. Git 2.23 (Q3 2019) behebt dies.
Siehe Commit bdbdf42 (20. Juni 2019) von Jeff King (peff
). ).
delta-islands
:respektieren Sie progress
Flagge
Der Delta-Inselcode gibt immer "Marked %d islands
aus ", auch wenn der Fortschritt mit --no-progress
unterdrückt wurde oder durch Senden von stderr an ein Nicht-TTY.
Übergeben wir eine progress
boolesch zu load_delta_islands()
.
Das Gleiche machen wir bereits für die Fortschrittsanzeige in resolve_tree_islands()
.
Ich habe mich dazu entschieden:
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)
Alle Forks haben einen Eintrag in ihrer objects/info/alternates-Datei, der einen relativen Pfad zum Datenbank-Repository der Objekte angibt.
Es ist wichtig, die Objektdatenbank zu einem Repository zu machen, weil wir Objekte und Referenzen verschiedener Benutzer speichern können, die ein Repository mit demselben Namen haben.
Schritte:
git init --bare shared-object-database.git
-
Ich führe die folgenden Codezeilen entweder jedes Mal aus, wenn ein Push zu einem Fork erfolgt (über Post-Receve) oder indem ich einen Cronjob ausführe
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# um sicher zu sein, füge ich die "fetten" Objekte jedes Mal zu alternativen hinzu)fertig
Dann werden beim nächsten "git gc" alle Objekte in bereits bestehenden Forks abwechselnd gelöscht.
git repack -adl
ist auch eine Option!
Auf diese Weise sparen wir Platz, sodass zwei Benutzer, die dieselben Daten auf ihre jeweiligen Forks auf dem Server schieben, die Objekte gemeinsam nutzen.
Wir müssen den gc.pruneExpire
setzen variabel bis never
in der Shared-Object-Datenbank. Nur zur Sicherheit!
Um Objekte gelegentlich zu bereinigen, fügen Sie alle Forks als Remotes zu „shared“, „fetch“ und „prune“ hinzu! Git erledigt den Rest!
(Ich habe endlich eine Lösung gefunden, die für mich funktioniert! (Nicht in der Produktion getestet! :p Danke für diesen Beitrag.)