English ▾ Themen ▾ Neueste Version ▾ bundle-uri zuletzt aktualisiert in 2.50.0

Git-Bundles sind Dateien, die eine Packdatei zusammen mit einigen zusätzlichen Metadaten speichern, einschließlich einer Reihe von Refs und einer (möglicherweise leeren) Menge notwendiger Commits. Weitere Informationen finden Sie unter git-bundle[1] und gitformat-bundle[5].

Bundle-URIs sind Speicherorte, von denen Git ein oder mehrere Bundles herunterladen kann, um die Objektdatenbank vor dem Abrufen der verbleibenden Objekte von einem Remote vorab zu füllen.

Ein Ziel ist es, Klon- und Fetch-Vorgänge für Benutzer mit schlechter Netzwerkverbindung zum Ursprungsserver zu beschleunigen. Ein weiterer Vorteil ist, dass Power-User wie CI-Build-Farmen lokale Ressourcen für den Großteil der Git-Daten nutzen und dadurch die Last auf dem Ursprungsserver reduzieren können.

Um die Bundle-URI-Funktion zu aktivieren, können Benutzer einen Bundle-URI über Kommandozeilenoptionen angeben oder der Ursprungsserver kann einen oder mehrere URIs über eine Protokoll v2-Funktion bewerben.

Designziele

Der Bundle-URI-Standard zielt darauf ab, flexibel genug zu sein, um mehrere Workloads zu erfüllen. Der Bundle-Provider und der Git-Client haben mehrere Wahlmöglichkeiten, wie sie Bundle-URIs erstellen und konsumieren.

  • Bundles können beliebige Namen haben, die der Server wünscht. Dieser Name könnte sich auf unveränderliche Daten beziehen, indem ein Hash des Bundle-Inhalts verwendet wird. Dies bedeutet jedoch, dass nach jeder Aktualisierung des Inhalts eine neue URI benötigt wird. Dies ist möglicherweise akzeptabel, wenn der Server die URI bewirbt (und der Server über neu generierte Bundles informiert ist), wäre jedoch für Benutzer, die die Kommandozeilenoption verwenden, nicht ergonomisch.

  • Die Bundles könnten speziell für das Bootstrapping vollständiger Klone organisiert sein, könnten aber auch mit der Absicht organisiert sein, inkrementelle Fetches zu bootstrappen. Der Bundle-Provider muss sich für eines von mehreren Organisationsschemata entscheiden, um die Client-Downloads während inkrementeller Fetches zu minimieren, aber der Git-Client kann auch wählen, ob Bundles für eine dieser Operationen verwendet werden sollen.

  • Der Bundle-Provider kann wählen, ob er vollständige Klone, partielle Klone oder beides unterstützt. Der Client kann erkennen, welche Bundles für den Filter des partiellen Klons des Repositorys geeignet sind, falls vorhanden.

  • Der Bundle-Provider kann ein einzelnes Bundle (nur für Klone) oder eine Liste von Bundles verwenden. Bei Verwendung einer Bundle-Liste kann der Provider angeben, ob der Client für einen vollständigen Klon *alle* Bundle-URIs benötigt oder ob *irgendeine* der Bundle-URIs ausreicht. Dies ermöglicht es dem Bundle-Provider, verschiedene URIs für verschiedene Geografien zu verwenden.

  • Der Bundle-Provider kann die Bundles mithilfe von Heuristiken, wie z. B. Erstellungstoken, organisieren, um dem Client zu helfen, den Download unnötiger Bundles zu vermeiden. Wenn der Bundle-Provider diese Heuristiken nicht bereitstellt, kann der Client Optimierungen verwenden, um die heruntergeladene Datenmenge zu minimieren.

  • Der Bundle-Provider muss nicht mit dem Git-Server verbunden sein. Der Client kann den Bundle-Provider nutzen, ohne dass dieser vom Git-Server beworben wird.

  • Der Client kann Bundle-Provider entdecken, die vom Git-Server beworben werden. Dies kann während git clone, während git fetch, beides oder keines davon geschehen. Der Benutzer kann wählen, welche Kombination für ihn am besten geeignet ist.

  • Der Client kann jederzeit manuell einen Bundle-Provider konfigurieren. Der Client kann auch jederzeit manuell einen Bundle-Provider als Kommandozeilenoption für git clone angeben.

Jedes Repository ist anders und jeder Git-Server hat unterschiedliche Bedürfnisse. Hoffentlich ist die Bundle-URI-Funktion flexibel genug, um alle Bedürfnisse zu erfüllen. Wenn nicht, kann die Funktion über ihren Versionsmechanismus erweitert werden.

Serveranforderungen

Um eine serverseitige Implementierung von Bundle-Servern bereitzustellen, sind keine anderen Teile des Git-Protokolls erforderlich. Dies ermöglicht es Server-Betreuern, statische Inhaltslösungen wie CDNs zu verwenden, um die Bundle-Dateien zu bedienen.

Im aktuellen Umfang der Bundle-URI-Funktion werden alle URIs als HTTP(S)-URLs erwartet, von denen Inhalte mit einer GET-Anfrage an diese URL in eine lokale Datei heruntergeladen werden. Der Server könnte Authentifizierungsanforderungen für diese Anfragen enthalten, um den konfigurierten Anmeldeinformationshelfer für sicheren Zugriff auszulösen. (Zukünftige Erweiterungen könnten "file://" URIs oder SSH-URIs verwenden.)

Unter der Annahme einer 200 OK-Antwort des Servers wird der Inhalt der URL inspiziert. Zuerst versucht Git, die Datei als Bundle-Datei der Version 2 oder höher zu parsen. Wenn die Datei kein Bundle ist, wird die Datei als einfache Textdatei mithilfe des Git-Konfigurationsparsers geparst. Es wird erwartet, dass die Schlüssel-Wert-Paare in dieser Konfigurationsdatei eine Liste von Bundle-URIs beschreiben. Wenn keiner dieser Parse-Versuche erfolgreich ist, meldet Git dem Benutzer einen Fehler, dass die angegebene Bundle-URI fehlerhafte Daten enthält.

Alle anderen vom Server bereitgestellten Daten werden als fehlerhaft betrachtet.

Bundle-Listen

Der Git-Server kann Bundle-URIs mithilfe eines Satzes von key=value-Paaren bewerben. Eine Bundle-URI kann auch eine einfache Textdatei im Git-Konfigurationsformat enthalten, die dieselben key=value-Paare enthält. In beiden Fällen betrachten wir dies als eine *Bundle-Liste*. Die Paare geben Informationen über die Bundles an, die der Client verwenden kann, um zu entscheiden, welche Bundles heruntergeladen und welche ignoriert werden sollen.

Einige Schlüssel konzentrieren sich auf Eigenschaften der Liste selbst.

bundle.version

(Erforderlich) Dieser Wert gibt eine Versionsnummer für die Bundle-Liste an. Wenn eine zukünftige Git-Änderung eine Funktion ermöglicht, die es dem Git-Client erfordert, auf einen neuen Schlüssel in der Bundle-Listen-Datei zu reagieren, dann wird diese Version inkrementiert. Die einzige aktuelle Versionsnummer ist 1, und wenn ein anderer Wert angegeben wird, schlägt Git die Verwendung dieser Datei fehl.

bundle.mode

(Erforderlich) Dieser Wert hat einen von zwei Werten: all und any. Wenn all angegeben ist, sollte der Client erwarten, alle aufgeführten Bundle-URIs zu benötigen, die seinen Repository-Anforderungen entsprechen. Wenn any angegeben ist, sollte der Client erwarten, dass *irgendeine* der Bundle-URIs, die seinen Repository-Anforderungen entsprechen, ausreicht. Typischerweise wird die Option any verwendet, um eine Reihe verschiedener Bundle-Server an verschiedenen geografischen Standorten aufzulisten.

bundle.heuristic

Wenn dieser schlüsselwertige Zeichenkettenwert existiert, dann ist die Bundle-Liste für inkrementelle git fetch-Befehle optimiert. Die Heuristik signalisiert, dass für jedes Bundle zusätzliche Schlüssel verfügbar sind, die dabei helfen zu bestimmen, welche Teilmenge von Bundles der Client herunterladen soll. Die einzige derzeit geplante Heuristik ist creationToken.

Die restlichen Schlüssel enthalten ein <id>-Segment, das ein vom Server designierter Name für jedes verfügbare Bundle ist. Das <id> muss nur alphanumerische Zeichen und - enthalten.

bundle.<id>.uri

(Erforderlich) Dieser Zeichenkettenwert ist die URI zum Herunterladen des Bundles <id>. Wenn die URI mit einem Protokoll beginnt (http:// oder https://), dann ist die URI absolut. Andernfalls wird die URI relativ zur URI interpretiert, die für die Bundle-Liste verwendet wird. Wenn die URI mit / beginnt, dann ist dieser relative Pfad relativ zum Domainnamen, der für die Bundle-Liste verwendet wird. (Diese Verwendung relativer Pfade soll die Verteilung eines Bundles über eine große Anzahl von Servern oder CDNs mit unterschiedlichen Domainnamen erleichtern.)

bundle.<id>.filter

Dieser Zeichenkettenwert repräsentiert einen Objektfilter, der auch im Header dieses Bundles erscheinen sollte. Der Server verwendet diesen Wert, um verschiedene Arten von Bundles zu unterscheiden, von denen der Client diejenigen auswählen kann, die seinen Objektfiltern entsprechen.

bundle.<id>.creationToken

Dieser Wert ist eine nicht-negative 64-Bit-Ganzzahl, die zum Sortieren der Bundle-Liste verwendet wird. Dies wird zum Herunterladen einer Teilmenge von Bundles während eines Fetches verwendet, wenn bundle.heuristic=creationToken.

bundle.<id>.location

Dieser Zeichenkettenwert bewirbt einen realen Standort, von dem die Bundle-URI bedient wird. Dies kann verwendet werden, um dem Benutzer eine Option für die zu verwendende Bundle-URI anzuzeigen oder einfach als informativer Hinweis, welche Bundle-URI von Git ausgewählt wurde. Dies ist nur dann wertvoll, wenn bundle.mode auf any gesetzt ist.

Hier ist eine Beispiel-Bundle-Liste im Git-Konfigurationsformat

[bundle]
	version = 1
	mode = all
	heuristic = creationToken
[bundle "2022-02-09-1644442601-daily"]
	uri = https://bundles.example.com/git/git/2022-02-09-1644442601-daily.bundle
	creationToken = 1644442601
[bundle "2022-02-02-1643842562"]
	uri = https://bundles.example.com/git/git/2022-02-02-1643842562.bundle
	creationToken = 1643842562
[bundle "2022-02-09-1644442631-daily-blobless"]
	uri = 2022-02-09-1644442631-daily-blobless.bundle
	creationToken = 1644442631
	filter = blob:none
[bundle "2022-02-02-1643842568-blobless"]
	uri = /git/git/2022-02-02-1643842568-blobless.bundle
	creationToken = 1643842568
	filter = blob:none

Dieses Beispiel verwendet bundle.mode=all sowie die Heuristik bundle.<id>.creationToken. Es verwendet auch die Optionen bundle.<id>.filter, um zwei parallele Bundle-Sätze bereitzustellen: einen für vollständige Klone und einen für blobless partielle Klone.

Angenommen, diese Bundle-Liste wurde unter der URI https://bundles.example.com/git/git/ gefunden, dann haben die beiden blobless Bundles die folgenden vollständig expandierten URIs

  • https://bundles.example.com/git/git/2022-02-09-1644442631-daily-blobless.bundle

  • https://bundles.example.com/git/git/2022-02-02-1643842568-blobless.bundle

Bundle-URIs bewerben

Wenn ein Benutzer eine Bundle-URI für das zu klonende Repository kennt, kann er diese URI manuell über eine Kommandozeilenoption angeben. Ein Git-Host möchte jedoch möglicherweise Bundle-URIs während des Klonvorgangs bewerben, um Benutzern zu helfen, die die Funktion nicht kennen.

Das Einzige, was für diese Funktion erforderlich ist, ist, dass der Server eine oder mehrere Bundle-URIs bewerben kann. Diese Werbung erfolgt in Form einer neuen Protokoll v2-Funktion, die speziell für die Erkennung von Bundle-URIs vorgesehen ist.

Der Client könnte eine beliebige Bundle-URI als Option wählen *oder* die URI mit der besten Leistung durch einige explorative Prüfungen auswählen. Es liegt am Bundle-Provider zu entscheiden, ob mehrere URIs besser sind als eine einzelne URI, die über serverseitige Infrastruktur geodistributed ist.

Klonen mit Bundle-URIs

Der Hauptbedarf für Bundle-URIs ist die Beschleunigung von Klonvorgängen. Der Git-Client interagiert gemäß dem folgenden Ablauf mit Bundle-URIs

  1. Der Benutzer gibt eine Bundle-URI mit der Kommandozeilenoption --bundle-uri an *oder* der Client entdeckt eine vom Git-Server beworbene Bundle-Liste.

  2. Wenn die heruntergeladenen Daten von einer Bundle-URI ein Bundle sind, prüft der Client die Bundle-Header, um sicherzustellen, dass die erforderlichen Commit-OIDs im Client-Repository vorhanden sind. Wenn einige fehlen, verzögert der Client das Entpacken, bis andere Bundles entpackt wurden und diese OIDs vorhanden sind. Wenn alle erforderlichen OIDs vorhanden sind, entpackt der Client diese Daten mithilfe einer Refspec. Die verwendete Refspec ist +refs/*:refs/bundles/*. Diese Refs werden gespeichert, damit spätere git fetch-Verhandlungen jede gebündelte Ref als have kommunizieren können, wodurch die Größe des Fetches über das Git-Protokoll reduziert wird. Um das Beschneiden von Refs aus diesem Ref-Namespace zu ermöglichen, kann Git einen nummerierten Namespace einführen (z. B. refs/bundles/<i>/*), sodass veraltete Bundle-Refs gelöscht werden können.

  3. Wenn die Datei stattdessen eine Bundle-Liste ist, prüft der Client bundle.mode, um zu sehen, ob die Liste im all- oder any-Format vorliegt.

    1. Wenn bundle.mode=all ist, dann berücksichtigt der Client alle Bundle-URIs. Die Liste wird basierend auf den Übereinstimmungen der bundle.<id>.filter-Optionen mit dem partiellen Klon-Filter des Client-Repositorys reduziert. Dann werden alle Bundle-URIs angefordert. Wenn die Heuristik bundle.<id>.creationToken bereitgestellt wird, dann werden die Bundles in absteigender Reihenfolge des Erstellungstokens heruntergeladen, wobei gestoppt wird, wenn ein Bundle alle erforderlichen OIDs enthält. Die Bundles können dann in aufsteigender Reihenfolge des Erstellungstokens entpackt werden. Der Client speichert das letzte Erstellungstoken als Heuristik, um zukünftige Downloads zu vermeiden, wenn die Bundle-Liste keine Bundles mit größeren Erstellungstoken bewirbt.

    2. Wenn bundle.mode=any ist, dann kann der Client eine beliebige der Bundle-URIs zur Inspektion auswählen. Der Client kann auf verschiedene Weise zwischen diesen URIs wählen. Der Client kann auf eine andere URI zurückfallen, wenn die erste Wahl kein Ergebnis liefert.

Beachten Sie, dass während eines Klons erwartet wird, dass alle Bundles benötigt werden, und Heuristiken wie bundle.<uri>.creationToken verwendet werden können, um Bundles chronologisch oder parallel herunterzuladen.

Wenn eine gegebene Bundle-URI eine Bundle-Liste mit einem bundle.heuristic-Wert ist, dann kann der Client diese URI als seine gewählte Bundle-URI speichern. Der Client kann dann während späterer git fetch-Aufrufe direkt auf diese URI zugreifen.

Beim Herunterladen von Bundle-URIs kann der Client den Anfangsinhalt inspizieren, bevor er sich zum Herunterladen des gesamten Inhalts verpflichtet. Dies kann genügend Informationen liefern, um festzustellen, ob die URI eine Bundle-Liste oder ein Bundle ist. Im Falle eines Bundles kann der Client den Bundle-Header inspizieren, um festzustellen, dass alle beworbenen Spitzen bereits im Client-Repository vorhanden sind, und den restlichen Download abbrechen.

Fetchen mit Bundle-URIs

Wenn der Client neue Daten abruft, kann er entscheiden, zuerst von Bundle-Servern abzurufen, bevor er vom Ursprungsserver abruft. Dies kann über eine Kommandozeilenoption erfolgen, ist aber wahrscheinlich nützlicher über einen Konfigurationswert, wie den während des Klons angegebenen.

Der Fetch-Vorgang folgt demselben Verfahren, um Bundles aus einer Bundle-Liste herunterzuladen (obwohl wir hier *keine* parallelen Downloads wünschen). Wir erwarten, dass der Prozess endet, wenn alle erforderlichen Commit-OIDs in einem Thin-Bundle bereits in der Objektdatenbank vorhanden sind.

Wenn die creationToken-Heuristik verwendet wird, kann der Client das Herunterladen von Bundles vermeiden, wenn ihre Erstellungstoken nicht größer als das gespeicherte Erstellungstoken sind. Nach dem Abrufen neuer Bundles aktualisiert Git dieses lokale Erstellungstoken.

Wenn der Bundle-Provider keine Heuristik bereitstellt, dann sollte der Client versuchen, die Bundle-Header zu inspizieren, bevor er die vollständigen Bundle-Daten herunterlädt, falls die Bundle-Spitzen bereits im Client-Repository vorhanden sind.

Fehlerfälle

Wenn der Git-Client beim Herunterladen von Informationen gemäß einer Bundle-URI oder der dort gefundenen Bundle-Liste unerwartetes entdeckt, kann Git diese Daten ignorieren und so fortfahren, als wäre ihm keine Bundle-URI übergeben worden. Der entfernte Git-Server ist die ultimative Quelle der Wahrheit, nicht die Bundle-URI.

Hier sind einige Beispiel-Fehlerfälle

  • Der Client kann keine Verbindung zum Server unter der angegebenen URI herstellen oder eine Verbindung geht verloren, ohne dass eine Wiederherstellung möglich ist.

  • Der Client empfängt eine Antwort auf der 400-Ebene (wie 404 Not Found oder 401 Not Authorized). Der Client sollte den Anmeldeinformationshelfer verwenden, um Anmeldeinformationen für die URI zu finden und bereitzustellen, aber die Semantik der anderen HTTP-Protokolle von Git in Bezug auf die Behandlung spezifischer 400-Fehler beibehalten.

  • Der Server meldet eine andere Fehlerantwort.

  • Der Client empfängt Daten, die weder als Bundle noch als Bundle-Liste geparst werden können.

  • Ein Bundle enthält einen Filter, der nicht den Erwartungen entspricht.

  • Der Client kann die Bundles nicht entpacken, da die erforderlichen Commit-OIDs nicht in der Objektdatenbank vorhanden sind und keine weiteren Bundles heruntergeladen werden können.

Es gibt auch Situationen, die als verschwenderisch angesehen werden können, aber keine Fehlerbedingungen sind

  • Die heruntergeladenen Bundles enthalten mehr Informationen als für die Klon- oder Fetch-Anforderung angefordert. Ein Hauptbeispiel ist, wenn der Benutzer einen Klon mit --single-branch anfordert, aber Bundles herunterlädt, die jeden erreichbaren Commit von allen refs/heads/*-Referenzen speichern. Dies kann anfangs verschwenderisch sein, aber vielleicht werden diese Objekte durch eine spätere Ref-Aktualisierung, die für den Client wichtig ist, erreichbar.

  • Ein Bundle-Download während eines git fetch enthält Objekte, die sich bereits in der Objektdatenbank befinden. Dies ist wahrscheinlich unvermeidlich, wenn wir Bundles für Fetches verwenden, da der Client nach dem Ausführen seines "Aufhol"-Fetches zum Remote-Server fast immer leicht vor den Bundle-Servern liegt. Diese zusätzliche Arbeit ist am verschwenderischsten, wenn der Client viel häufiger abruft, als der Server Bundles berechnet, z. B. wenn der Client stündliche Prefetches mit Hintergrundwartung verwendet, der Server jedoch wöchentlich Bundles berechnet. Aus diesem Grund sollte der Client keine Bundle-URIs für Fetch verwenden, es sei denn, der Server hat dies explizit über einen bundle.heuristic-Wert empfohlen.

Beispielorganisation eines Bundle-Providers

Die Bundle-URI-Funktion ist absichtlich flexibel gestaltet, um verschiedene Arten der Organisation von Objektdaten durch einen Bundle-Provider zu ermöglichen. Es kann jedoch hilfreich sein, ein vollständiges Organisationsmodell hier zu beschreiben, damit Provider von dieser Basis ausgehen können.

Dieses Beispiel-Organisationsmodell ist eine vereinfachte Version dessen, was von den GVFS-Cache-Servern verwendet wird (siehe Abschnitt am Ende dieses Dokuments), die sich bei der Beschleunigung von Klon- und Fetch-Vorgängen für sehr große Repositories als vorteilhaft erwiesen haben, wenn auch unter Verwendung zusätzlicher Software außerhalb von Git.

Der Bundle-Provider stellt Server an mehreren geografischen Standorten bereit. Jeder Server verwaltet seine eigene Bundle-Menge. Der Server kann eine Reihe von Git-Repositories verwalten, stellt aber für jedes eine Bundle-Liste basierend auf einem Muster bereit. Wenn beispielsweise ein Repository unter https://<domain>/<org>/<repo> gespiegelt wird, könnte der Bundle-Server seine Bundle-Liste unter https://<server-url>/<domain>/<org>/<repo> verfügbar haben. Der Origin-Git-Server kann all diese Server unter dem "any"-Modus auflisten

[bundle]
	version = 1
	mode = any
[bundle "eastus"]
	uri = https://eastus.example.com/<domain>/<org>/<repo>
[bundle "europe"]
	uri = https://europe.example.com/<domain>/<org>/<repo>
[bundle "apac"]
	uri = https://apac.example.com/<domain>/<org>/<repo>

Diese "Liste von Listen" ist statisch und ändert sich nur, wenn ein Bundle-Server hinzugefügt oder entfernt wird.

Jeder Bundle-Server verwaltet seine eigene Menge an Bundles. Die anfängliche Bundle-Liste enthält nur ein einzelnes Bundle, das alle Objekte enthält, die durch das Klonen des Repositorys vom Origin-Server erhalten wurden. Die Liste verwendet die Heuristik creationToken, und ein creationToken wird für das Bundle basierend auf dem Zeitstempel des Servers erstellt.

Der Bundle-Server führt regelmäßig geplante Aktualisierungen für die Bundle-Liste durch, z. B. einmal täglich. Während dieser Aufgabe ruft der Server die neuesten Inhalte vom Origin-Server ab und generiert ein Bundle, das die von den neuesten Origin-Refs erreichbaren, aber in einem zuvor berechneten Bundle nicht enthaltenen Objekte enthält. Dieses Bundle wird der Liste hinzugefügt, wobei darauf geachtet wird, dass das creationToken strikt größer als das vorherige maximale creationToken ist.

Wenn die Bundle-Liste zu groß wird, z. B. mehr als 30 Bundles, dann werden die ältesten "N minus 30" Bundles zu einem einzigen Bundle zusammengefasst. Das creationToken dieses Bundles entspricht dem maximalen creationToken der zusammengeführten Bundles.

Eine Beispiel-Bundle-Liste ist hier aufgeführt, obwohl sie nur zwei tägliche Bundles und keine vollständige Liste von 30 enthält.

[bundle]
	version = 1
	mode = all
	heuristic = creationToken
[bundle "2022-02-13-1644770820-daily"]
	uri = https://eastus.example.com/<domain>/<org>/<repo>/2022-02-09-1644770820-daily.bundle
	creationToken = 1644770820
[bundle "2022-02-09-1644442601-daily"]
	uri = https://eastus.example.com/<domain>/<org>/<repo>/2022-02-09-1644442601-daily.bundle
	creationToken = 1644442601
[bundle "2022-02-02-1643842562"]
	uri = https://eastus.example.com/<domain>/<org>/<repo>/2022-02-02-1643842562.bundle
	creationToken = 1643842562

Um die Speicherung und Bereitstellung von Objektdaten in alle Ewigkeit zu vermeiden, obwohl sie im Origin-Server nicht mehr erreichbar sind, kann diese Bundle-Zusammenführung sorgfältiger sein. Anstatt eine absolute Vereinigung der alten Bundles zu nehmen, kann das Bundle erstellt werden, indem die neueren Bundles betrachtet und sichergestellt wird, dass ihre notwendigen Commits alle in diesem zusammengeführten Bundle (oder in einem anderen der neueren Bundles) verfügbar sind. Dies ermöglicht die "Ablaufzeit" von Objektdaten, die in diesem Zeitraum nicht von neuen Commits verwendet werden. Diese Daten könnten durch einen späteren Push wieder eingeführt werden.

Die Absicht dieser Datenorganisation verfolgt zwei Hauptziele. Erstens werden anfängliche Klonvorgänge des Repositorys schneller, indem vorab berechnete Objektdaten von einer näheren Quelle heruntergeladen werden. Zweitens können git fetch-Befehle schneller sein, insbesondere wenn der Client seit einigen Tagen nicht mehr abgerufen hat. Wenn ein Client jedoch 30 Tage lang nicht abruft, würde die Bundle-Listenorganisation eine große Menge an Objektdaten neu herunterladen.

Eine Möglichkeit, diese Organisation für Benutzer, die häufig abrufen, nützlicher zu machen, ist eine häufigere Bundle-Erstellung. Zum Beispiel könnten Bundles jede Stunde erstellt und dann einmal täglich diese "stündlichen" Bundles zu einem "täglichen" Bundle zusammengefasst werden. Die täglichen Bundles werden nach 30 Tagen in das älteste Bundle zusammengefasst.

Es wird empfohlen, diese Bundle-Strategie mit dem Filter blob:none zu wiederholen, wenn Clients dieses Repositorys erwarten, blobless partielle Klone zu verwenden. Diese Liste von blobless Bundles verbleibt in derselben Liste wie die vollständigen Bundles, verwendet aber den Schlüssel bundle.<id>.filter, um die beiden Gruppen zu trennen. Für sehr große Repositories möchte der Bundle-Provider möglicherweise *nur* blobless Bundles bereitstellen.

Implementierungsplan

Dieses Design-Dokument wird eigenständig als aspiratives Dokument eingereicht, mit dem Ziel, alle erwähnten Client-Funktionen im Laufe mehrerer Patchserien zu implementieren. Hier ist ein möglicher Überblick für die Einreichung dieser Funktionen

  1. Bundle-URIs in git clone mit einer Option --bundle-uri integrieren. Dies wird einen neuen Modus git fetch --bundle-uri für die Implementierung unter git clone beinhalten. Die erste Version hier erwartet ein einzelnes Bundle an der angegebenen URI.

  2. Die Fähigkeit, eine Bundle-Liste aus einer Bundle-URI zu parsen, implementieren und die Logik von git fetch --bundle-uri aktualisieren, um die bundle.mode-Optionen korrekt zu unterscheiden. Insbesondere wird die Funktion so gestaltet, dass das Parsen des Konfigurationsformats eine Liste von Schlüssel-Wert-Paaren an die Bundle-Listen-Logik speist.

  3. Erstellen Sie den Protokoll v2-Befehl bundle-uri, damit Git-Server Bundle-URIs mithilfe von Schlüssel-Wert-Paaren bewerben können. In die bestehende Schlüssel-Wert-Eingabe für die Bundle-Listen-Logik integrieren. Erlauben Sie git clone, diese Bundle-URIs zu entdecken und das Client-Repository aus den Bundle-Daten zu bootstrappen. (Diese Wahl ist ein Opt-in über eine Konfigurationsoption und eine Kommandozeilenoption.)

  4. Ermöglichen Sie dem Client, den Konfigurationsschlüssel bundle.heuristic und die Heuristik bundle.<id>.creationToken zu verstehen. Wenn git clone eine Bundle-URI mit bundle.heuristic entdeckt, konfiguriert es das Client-Repository so, dass es diese Bundle-URI während späterer git fetch <remote>-Befehle prüft.

  5. Ermöglichen Sie Clients, Bundle-URIs während git fetch zu entdecken und eine Bundle-URI für spätere Fetches zu konfigurieren, wenn bundle.heuristic gesetzt ist.

  6. Implementieren Sie die Heuristik "Header inspizieren", um Daten-Downloads zu reduzieren, wenn die Heuristik bundle.<id>.creationToken nicht verfügbar ist.

Da diese Funktionen überprüft werden, kann dieser Plan aktualisiert werden. Wir erwarten auch, dass neue Designs entdeckt und implementiert werden, wenn sich diese Funktion weiterentwickelt und in realen Szenarien eingesetzt wird.

Das Git-Protokoll verfügt bereits über eine Funktion, bei der der Git-Server eine Reihe von URLs zusammen mit der Packfile-Antwort auflisten kann, wenn eine Client-Anfrage bedient wird. Der Client wird dann erwartet, die Packfiles an diesen Orten herunterzuladen, um ein vollständiges Verständnis der Antwort zu erhalten.

Dieser Mechanismus wird vom Gerrit-Server (implementiert mit JGit) verwendet und war wirksam bei der Reduzierung der CPU-Last und der Verbesserung der Benutzerleistung für Klone.

Ein wesentlicher Nachteil dieses Mechanismus ist, dass der Origin-Server *genau* wissen muss, was in diesen Packfiles enthalten ist, und die Packfiles müssen dem Benutzer für einige Zeit nach der Antwort des Servers zur Verfügung stehen. Diese Kopplung zwischen dem Origin und den Packfile-Daten ist schwer zu verwalten.

Darüber hinaus ist diese Implementierung extrem schwierig mit Fetches zum Laufen zu bringen.

Das GVFS-Protokoll [2] ist eine Reihe von HTTP-Endpunkten, die unabhängig vom Git-Projekt entwickelt wurden, bevor Git's partielles Klonen erstellt wurde. Eine Funktion dieses Protokolls ist die Idee eines "Cache-Servers", der mit Build-Maschinen oder Entwicklerbüros ko-lokalisiert sein kann, um Git-Daten zu übertragen, ohne den zentralen Server zu überlasten.

Der Endpunkt, für den VFS for Git berühmt ist, ist der Endpunkt GET /gvfs/objects/{oid}, der das Herunterladen eines Objekts bei Bedarf ermöglicht. Dies ist ein kritischer Teil der Dateisystemvirtualisierung dieses Produkts.

Eine subtilere Anforderung ist jedoch der Endpunkt GET /gvfs/prefetch?lastPackTimestamp=<t>. Unter Angabe eines optionalen Zeitstempels antwortet der Cache-Server mit einer Liste von vorab berechneten Packfiles, die die Commits und Trees enthalten, die in diesen Zeitintervallen eingeführt wurden.

Der Cache-Server berechnet diese "Prefetch"-Packfiles nach folgender Strategie

  1. Jede Stunde wird ein "stündliches" Pack mit einem gegebenen Zeitstempel generiert.

  2. Jede Nacht werden die vorherigen 24 stündlichen Packs zu einem "täglichen" Pack zusammengefasst.

  3. Jede Nacht werden alle Prefetch-Packs, die älter als 30 Tage sind, zu einem Pack zusammengefasst.

Wenn ein Benutzer gvfs clone oder scalar clone gegen ein Repo mit Cache-Servern ausführt, fordert der Client alle Prefetch-Packfiles an, was höchstens 24 + 30 + 1 Packfiles sind, die nur Commits und Trees herunterladen. Der Client folgt dann mit einer Anfrage an den Origin-Server für die Referenzen und versucht, diese Tip-Referenz auszuchecken. (Es gibt einen zusätzlichen Endpunkt, der hilft, alle erreichbaren Trees von einem gegebenen Commit zu erhalten, falls dieser Commit noch nicht in einem Prefetch-Packfile enthalten war.)

Während eines git fetch fordert ein Hook den Prefetch-Endpunkt unter Verwendung des aktuellsten Zeitstempels eines zuvor heruntergeladenen Prefetch-Packfiles an. Nur die Liste der Packfiles mit späteren Zeitstempeln wird heruntergeladen. Die meisten Benutzer rufen stündlich ab und erhalten daher höchstens ein stündliches Prefetch-Pack. Benutzer, deren Maschinen ausgeschaltet waren oder die aus anderen Gründen seit über 30 Tagen nicht abgerufen haben, könnten alle Prefetch-Packfiles neu herunterladen. Dies ist selten.

Es ist wichtig zu beachten, dass die Clients immer den Origin-Server für die Refs-Werbung kontaktieren, sodass die Refs häufig "vor" den vorgeabgerufenen Pack-Daten liegen. Die fehlenden Objekte werden bei Bedarf über die GET gvfs/objects/{oid}-Anfragen heruntergeladen, wenn sie von einem Befehl wie git checkout oder git log benötigt werden. Einige Git-Optimierungen deaktivieren Prüfungen, die dazu führen würden, dass diese On-Demand-Downloads zu aggressiv wären.