web-dev-qa-db-fra.com

Les fichiers Pack de GIT sont-ils deltas plutôt que des instantanés?

L'une des différences essentielles entre Git et la plupart des autres systèmes de contrôle de la version est que les autres ont tendance à stocker comme une série de DELTAS - des modifications apportées entre un commit et la suivante. Cela semble logique, car c'est la plus petite quantité possible d'informations à stocker sur un commit. Mais plus l'historique de validation est long, plus il faut calcul pour comparer les gammes de révisions.

En revanche, git stocke un instantané complet de l'ensemble du projet dans chaque révision . La raison pour laquelle cela ne rend pas la taille de la répétition augmente considérablement avec chaque commit est que chaque fichier du projet est stocké sous forme de fichier dans le sous-répertoire GIT, nommé pour le hachage de son contenu. Donc, si le contenu n'a pas changé, le hachage n'a pas changé, et le commit ne fait que pointer sur le même dossier. Et il y a aussi d'autres optimisations.

Tout cela a fait du sens pour moi jusqu'à ce que je sois trébuché ces informations sur les fichiers de pack , dans lesquelles GIT met les données périodiquement pour économiser de l'espace:

Afin de sauvegarder cet espace, GIT utilise le fichier d'emballage. Il s'agit d'un format où GIT permettra uniquement de sauvegarder la pièce qui a changé dans le deuxième fichier, avec un pointeur vers le fichier qu'il est similaire à.

N'est-ce pas essentiellement de retourner à stocker Deltas? Sinon, comment est-ce différent? Comment cela évite-t-il de soumettre l'obtention des mêmes problèmes que les autres systèmes de contrôle de la version ont?

Par exemple, Subversion utilise des deltas et le roulant 50 versions signifie 50 diffèrent 50 diffs, tandis qu'avec GIT, vous pouvez simplement saisir l'instantané approprié. Sauf si git stocke également 50 diffs dans les packfiles ... y a-t-il un mécanisme qui dit "après un petit nombre de Deltas, nous stockerons un tout nouveau instantané" afin que nous n'empilions pas trop grand changeant? Sinon, comment pourrait-il éviter les inconvénients des Deltas?

66
Nathan Long

Sommaire:
[.____] Les fichiers Pack de GIT sont soigneusement construits pour utiliser efficacement des caches de disque et fournir des modèles d'accès "Nice" pour des commandes courantes et pour la lecture d'objets récemment référencés.


Le format de fichier Pack de GIT est assez flexible (voir Documentation/technique/pack-format.txt ou le fichier packfile dans le livre de la communauté GIT ). Les fichiers du pack stockent des objets de deux manières principales: "Undeltifiés" (prenez les données d'objet brutes et déformez-la-compressez) ou "Deltified" (former un delta contre un autre objet puis défléchir les données Delta résultantes). Les objets stockés dans un pack peuvent être dans n'importe quel ordre (ils ne doivent pas (nécessairement être triés par type d'objet, nom d'objet ou tout autre attribut) et des objets délivrés peuvent être effectués contre tout autre objet approprié du même type.

Git's (((( objets-objets Commande utilise plusieurs heuristiques pour fournir une excellente localité de référence pour commandes communes. Ces heuristiques contrôlent à la fois la sélection d'objets de base pour des objets délivrés et l'ordre des objets. Chaque mécanisme est surtout indépendant, mais ils partagent certains objectifs.

Git forme de longues chaînes d'objets compressés Delta, mais les heuristiques essaient de s'assurer que seuls des objets "anciens" sont aux extrémités des chaînes longues. Le cache de base delta (qui est la taille est contrôlée par la variable de configuration core.deltaBaseCacheLimit) Est automatiquement utilisé et peut réduire considérablement le nombre de " reconstructions " nécessaires pour les commandes qui ont besoin de lire un grand nombre d'objets (par exemple git log -p).

Compression Delta Heuristic

Un référentiel git typique stocke un très grand nombre d'objets, de sorte qu'il ne peut donc pas les comparer raisonnablement pour trouver les paires (et les chaînes) qui produiront les plus petites représentations du delta.

La sélection de la sélection de la base Delta est basée sur l'idée que les bonnes bases Delta seront trouvées parmi des objets présentant des noms de fichiers et des tailles similaires. Chaque type d'objet est traité séparément (c'est-à-dire un objet d'un type ne sera jamais utilisé comme base delta pour un objet d'un autre type).

Aux fins de la sélection de base Delta, les objets sont triés (principalement) par nom de fichier, puis la taille. Une fenêtre dans cette liste de tri est utilisée pour limiter le nombre d'objets considérés comme des bases de delta potentielles. Si un "assez bon"1 La représentation Delta n'est pas trouvée pour un objet parmi les objets dans sa fenêtre, l'objet ne sera pas compressé de Delta.

La taille de la fenêtre est contrôlée par l'option --window= De git pack-objects, Ou la variable de configuration pack.window. La profondeur maximale d'une chaîne delta est contrôlée par le --depth= Option git pack-objects, Ou la variable de configuration pack.depth. Le --aggressive Option git gc Élargit grandement la taille de la fenêtre et la profondeur maximale pour tenter de créer un fichier plus petit paquet.

Le nom de fichier touffes sorte ensemble les objets pour les entrées avec des noms identiques (ou au moins fins similaires (par exemple .c)). Le tri de la taille est de plus grand au plus petit, de sorte que les Deltas qui éliminent les données sont préférables aux Deltas qui ajoutent des données (puisque les deltas de suppression ont des représentations plus courtes) et que les objets plus volumineux (généralement plus récents) ont tendance à être représentés avec une compression simple.

1 Ce qui se qualifie comme "suffisamment bon" dépend de la taille de l'objet en question et de sa base delta potentielle ainsi que de la profondeur de sa chaîne delta qui en résulte.

Objet commande Heuristic

Les objets sont stockés dans les fichiers de pack dans une commande "la plus récemment référencée". Les objets nécessaires pour reconstruire l'histoire la plus récente sont placés plus tôt dans le peloton et ils seront proches. Cela fonctionne généralement bien pour les caches du disque OS.

Tous les objets de validation sont triés par la date de validation (la plus récente d'abord) et stockées ensemble. Ce placement et de commande permet d'optimiser le disque les accès nécessaires pour parcourir le graphique de l'histoire et extraire des informations de base commettras (par exemple git log).

Les objets d'arbre et de blob sont stockés à partir de l'arbre à partir de la première commission stockée (la plus récente). Chaque arbre est traité de manière approfondie, stockant tous les objets qui n'ont pas déjà été stockés. Cela met tous les arbres et blobs nécessaires pour reconstruire le plus récent engagement ensemble au même endroit. Tous les arbres et blobs qui n'ont pas encore été sauvés mais qui sont nécessaires pour les commits ultérieurs sont stockés ensuite, dans l'ordre de validation trié.

La commande finale de l'objet est légèrement affectée par la sélection de base Delta dans laquelle si un objet est sélectionné pour la représentation Delta et son objet de base n'a pas encore été stocké, son objet de base est alors stocké immédiatement avant l'objet délié lui-même. Cela empêche la perte de cache de disque probable due à l'accès non linéaire requis pour lire un objet de base qui aurait "naturellement" été stocké plus tard dans le fichier PACK.

68
Chris Johnsen

L'utilisation du stockage Delta dans le fichier Pack n'est qu'un détail de mise en œuvre. À ce niveau, Git ne sait pas pourquoi ou comment quelque chose a changé d'une révision à la suivante, mais elle sait simplement que Blob B est assez similaire à Blob A, à l'exception de ces changements C. Donc, il ne stockera que Blob A et change C (Si elle choisit de le faire - il pourrait également choisir de stocker Blob A et Blob B).

Lors de la récupération d'objets dans le fichier Pack, le stockage Delta n'est pas exposé à l'appelant. L'appelant voit toujours des blobs complets. Ainsi, Git fonctionne de la même manière qu'il a toujours sans l'optimisation du stockage Delta.

7
Greg Hewgill

Comme je l'ai mentionné dans " Quels sont les packs minces de GIT? "

Git ne délive que dans des emballages

J'ai détaillé l'encodage Delta utilisé pour les fichiers de pack dans " est l'algorithme DIGNTA DIFRY DIFLORITHM (Delta Stock)? ".
Voir aussi " quand et comment git utilise-t-il Deltas pour le stockage? ".

Notez que le core.deltaBaseCacheLimit Config, qui contrôle la taille par défaut du fichier pack sera bientôt heurté de 16 Mo à 96 Mo, pour GIT 2.0.x/2.1 (T3 2014).

Voir commit 4874f54 par David Kastrup (mai 2014):

Bump core.deltabasecachelimit à 96m

La valeur par défaut de 16 m provoque une traversée grave pour les grandes chaînes de Delta combinées à des fichiers volumineux.

Voici quelques points de repère (variante PU de git blame):

time git blame -C src/xdisp.c >/dev/null

pour un référentiel d'emacs remballés avec git gc --aggressive (v1.9, entraînant une taille de fenêtre de 250) située sur un lecteur SSD.
[.____] Le fichier en question comporte environ 30000 lignes, 1 Mo de taille et une histoire avec environ 2500 commits.

16m (previous default):
  real  3m33.936s
  user  2m15.396s
  sys   1m17.352s

96m:
  real  2m5.668s
  user  1m50.784s
  sys   0m14.288s
4
VonC