Parlez du principe de stockage Git et de l'implémentation associée

Le contenu suivant est reproduit à partir de https://www.toutiao.com/i6938300453767676455/

Gène clignotant 2021-03-11 15:53:07

Parlez du principe de stockage Git et de l'implémentation associée

 

[Note de l'éditeur] Git est actuellement le système de contrôle de version le plus populaire. Du développement local au déploiement en production, nous utilisons Git pour notre contrôle de version tous les jours. En plus des commandes quotidiennes, si vous souhaitez avoir une compréhension plus approfondie de Git. puis étudier les principes de stockage sous-jacents de Git sera très utile pour comprendre Git et son utilisation. Même si vous n'êtes pas un développeur Git, il est recommandé de comprendre les principes sous-jacents de Git. Vous aurez une toute nouvelle puissance de Git. Comprenez, et sera plus pratique dans le processus d'utilisation quotidien de Git.

Cet article s'adresse aux lecteurs qui ont une certaine compréhension de Git. Il n'introduira pas le rôle et l'utilisation spécifiques de Git, ni n'introduira les différences avec d'autres systèmes de contrôle de version tels que Subversion. Il introduit principalement Git. L'essence de et les principes associés de son implémentation de stockage sont conçus pour aider les utilisateurs de Git à avoir une compréhension plus claire de son implémentation interne lors de l'utilisation de Git pour le contrôle de version.

Quelle est l'essence de Git

Git est essentiellement une base de données clé-valeur adressée au contenu. Nous pouvons insérer n'importe quel type de contenu dans le référentiel Git, et Git nous renverra une valeur de clé unique. Nous pouvons utiliser cette clé pour récupérer la valeur que nous avons insérée à ce moment-là. Nous pouvez l'essayer via la commande sous-jacente git hash-object command:

➜  Zoker git:(master) ✗ cat testfile

Hello Git

➜  Zoker git:(master) ✗ git hash-object testfile -w

9f4d96d5b00d98959ea9960f069585ce42b1349a

Vous pouvez voir qu'il existe un fichier nommé testfile dans notre répertoire. Le contenu est Hello Git! Nous utilisons la commande git hash-object pour écrire le contenu de ce fichier dans le référentiel Git. L'option -w indique à Git d'écrire ce contenu dans le répertoire de base de données d'objets Git. git / objects, et Git a renvoyé une valeur SHA, cette valeur SHA est la valeur clé du fichier que nous récupérerons plus tard:

➜  Zoker git:(master) ✗ git cat-file -p 9f4d96d5b00d98959ea9960f069585ce42b1349a

Hello Git

Nous avons utilisé la commande git cat-file pour récupérer le contenu qui vient d'être enregistré dans le référentiel Git. Bien que ce ne soit pas aussi intuitif que la commande Redis get set, il s'agit bien d'une base de données KV, n'est-ce pas?

Les données que nous venons d'essayer d'insérer sont un objet de type blob de base. Git a également d'autres types d'objet tels que tree et commit. Ces différents types d'objets ont des relations d'association spécifiques et ils associent logiquement différents objets. Ce n'est que lorsque nous nous levons que nous pouvons contrôler et découvrez différentes versions. Nous développerons ces différents types d'objets plus tard. Comprenons d'abord la structure de répertoires de Git et voyons comment les données sont stockées dans Git.

Structure de répertoires Git

Grâce à l'introduction dans la section précédente, nous savons que Git est essentiellement une base de données KV, et nous avons également mentionné que le contenu est écrit dans le répertoire d'objets .git / objects, alors où se trouve ce répertoire? Comment Git stocke-t-il ces données? Dans cette section, nous nous concentrons sur la structure du répertoire de stockage Git et comprenons comment Git stocke différents types de données.

Pour une introduction plus détaillée, veuillez vous référer à:
https://github.com/git/git/blo ... t.txt

Grâce à git init, nous pouvons initialiser un entrepôt Git vide dans le répertoire courant. Git générera automatiquement un répertoire .git. Ce répertoire .git est le centre de stockage de toutes les métadonnées Git suivantes. Jetons un coup d'œil à sa structure de répertoire:

➜  Zoker git init

Initialized empty Git repository in /Users/zoker/tmp/Zoker/.git/

➜  Zoker git:(master) ✗ tree .git

.git

├── HEAD              // 是一个符号引用,指明当前工作目录的版本引用信息,我们平时执行 checkout 命令时就会改变 HEAD 的内容

├── config             // 配置当前存储库的一些信息,如:Proxy、用户信息、引用等,此处的配置项相对于全局配置权重更高

├── description      // 仓库描述信息

├── hooks             // 钩子目录,执行 Git 相关命令后的回调脚本,默认会有一些模板

│   ├── update.sample

│   ├── pre-receive.sample

│   └── ...

├── info                // 存储一些额外的仓库信息如 refs、exclude、attributes 等

│   └── exclude

├── objects           // 元数据存储中心

│   ├── info

│   └── pack

└── refs               // 存放引用信息,也就是分支、标签

├── heads

└── tags

L'entrepôt Git généré par l'initialisation par défaut ne contient que ces fichiers. De plus, il existe d'autres types de fichiers et de répertoires tels que les journaux de modules compressés-refs, etc. Ces fichiers ont des utilisations spécifiques et ne sont qu'après des opérations ou des configurations spécifiques. Apparaîtront , ici nous nous concentrons uniquement sur la mise en œuvre du stockage de base, le rôle de ces fichiers ou répertoires supplémentaires et les scénarios d'utilisation peuvent alors parcourir les documents par eux-mêmes, ici ne présenter que certains des fichiers de base.

répertoire hooks

Le répertoire hooks stocke principalement les hooks Git. Les hooks Git peuvent être déclenchés après ou avant que de nombreux événements se produisent, ce qui peut nous fournir un moyen très flexible de les utiliser. Par défaut, ils ont tous le suffixe .sample. Vous devez les supprimer. ce suffixe et donnez les autorisations exécutables pour prendre effet. Voici quelques hooks couramment utilisés et leurs utilisations courantes:

Crochet client:

  • pré-engagement: déclenché avant la soumission, par exemple pour vérifier si les informations soumises sont normalisées, si le test est terminé et si le format du code répond aux exigences
  • post-commit: au contraire, cela se déclenche une fois la soumission complète terminée et peut être utilisé pour envoyer des notifications

Crochet de serveur:

  • pré-réception: le script qui est appelé en premier lorsque le serveur reçoit la demande push, et peut détecter si ces références poussées répondent aux exigences
  • mise à jour: similaire à la pré-réception, mais la pré-réception ne s'exécutera qu'une seule fois et la mise à jour s'exécutera une fois pour chaque branche poussée
  • post-réception: déclenché une fois que tout le processus push est terminé, peut être utilisé pour envoyer des notifications, déclencher le système de construction, etc.

répertoire d'objets

Comme nous l'avons mentionné dans la section précédente, Git stocke tous les fichiers objets de génération de contenu reçus dans ce répertoire. Nous avons généré un objet via git hash-object et l'avons écrit dans l'entrepôt Git. La valeur clé de cet objet est
9f4d96d5b00d98959ea9960f069585ce42b1349a, ceci Lorsque nous regardons au niveau de la structure du répertoire des objets:

➜  Zoker git:(master) ✗ git hash-object testfile -w

9f4d96d5b00d98959ea9960f069585ce42b1349a

➜  Zoker git:(master) ✗ tree .git/objects

.git/objects

├── 9f

│   └── 4d96d5b00d98959ea9960f069585ce42b1349a

├── info

└── pack

Vous pouvez voir que le répertoire des objets a un nouveau contenu. Il contient un dossier 9f supplémentaire et des fichiers. Ce fichier est le fichier objet inséré dans le référentiel Git. Git prend les deux premières lettres de sa valeur de clé comme dossier, et stocke les lettres suivantes comme nom de fichier du fichier objet. Les objets stockés ici (c'est-à-dire objets / [0-9a-f] [0-9a-f]) sont généralement appelés objets libres ou objets décompressés. objet.

En plus du dossier de stockage d'objets, les étudiants attentifs devraient avoir remarqué l'existence du dossier objects / pack, qui correspond aux fichiers packagés. Afin d'économiser de l'espace et d'améliorer l'efficacité, lorsqu'il y a trop de fichiers objets en vrac ou lors de l'exécution manuelle la commande git gc, ou pendant le processus de transfert de push et pulling, Git regroupera ces fichiers objets en vrac dans des fichiers pack pour améliorer l'efficacité. Voici ces fichiers compressés:

➜  objects git:(master) git gc

...

Compressing objects: 100% (75/75), done.

...

➜  objects git:(master) tree

.

├─ pack

├── pack-fe24a22b0313342a6732cff4759bedb25c2ea55d.idx

└── pack-fe24a22b0313342a6732cff4759bedb25c2ea55d.pack

└── ...

Vous pouvez voir qu'il n'y a pas d'objets libres dans le répertoire des objets. Au lieu de cela, il y a deux fichiers dans le répertoire du pack. L'un est le fichier du pack et l'autre est le fichier idx qui indexe le contenu du pack. Il est pratique de rechercher si un L'objet est dans ce Dans le package de pack correspondant.

Il convient de noter que si la GC est effectuée dans un entrepôt d'un objet blob que nous avons créé manuellement à l'instant, cela ne produira aucun effet, car pour le moment, tout l'entrepôt Git n'a aucune référence à cet objet. Nous disons que cet objet est libre. Introduisons le répertoire où la référence est stockée.

répertoire refs

Le répertoire refs stocke nos références. La référence peut être considérée comme un alias vers un numéro de version. Il stocke en fait la valeur SHA d'un certain Commit. L'entrepôt que nous avons utilisé pour les tests ci-dessus n'a pas de commit, il n'y a donc qu'un seul Empty structure de répertoires.

└── refs

├── heads

└── tags

Nous trouvons au hasard un référentiel contenant des commits pour afficher son maître de branche par défaut.

➜  .git git:(master) cat refs/heads/master

87e917616712189ecac8c4890fe7d2dc2d554ac6

Vous pouvez voir que la référence principale ne stocke qu'une valeur SHA de validation. L'avantage bien sûr est que nous n'avons pas besoin de nous souvenir de la longue chaîne de valeurs SHA. Nous n'avons besoin que de l'alias principal pour obtenir cette version. Le même répertoire de balises stocke nos balises Contrairement aux branches, les valeurs de référence enregistrées des balises ne changent généralement pas, mais les branches peuvent changer avec notre version. En outre, vous pouvez également voir des répertoires tels que refs / remotes refs / fetch, qui stockent des références à des espaces de noms spécifiques.

Il existe une autre situation, qui est le mécanisme GC que nous avons mentionné ci-dessus. Si un entrepôt exécute GC, non seulement les objets en vrac dans le répertoire des objets seront empaquetés, mais les références sous refs seront également empaquetées, mais elles sont stockées dans l'entrepôt nu. Le répertoire racine de .git / emballé-refs

➜  .git git:(master) cat packed-refs

# pack-refs with: peeled fully-peeled sorted

87e917616712189ecac8c4890fe7d2dc2d554ac6 refs/heads/master

Lorsque nous avons besoin d'accéder au maître de branche, Git recherchera d'abord dans refs / heads. S'il ne le trouve pas, il ira dans .git / packing-refs pour rechercher. Le regroupement de toutes les références dans un seul fichier améliorera sans aucun doute beaucoup de efficacité. Il convient de noter que si nous mettons à jour certains commits dans la branche master à ce moment, Git ne modifiera pas directement le fichier .git / emballé-refs pour le moment, il recréera directement une référence maître sous refs / heads /, Contient le Valeur SHA du dernier commit.Selon le mécanisme Git que nous venons d'introduire, Git cherchera d'abord dans refs / heads /, puis ira dans .git / packing-refs s'il ne peut pas être trouvé.

Alors à quoi fait référence la valeur SHA du Commit stocké dans la référence? Nous pouvons utiliser la commande cat-file pour afficher le contenu de l'objet blob à afficher:

➜  .git git:(master) git cat-file -p 87e917616712189ecac8c4890fe7d2dc2d554ac6

tree aab1a9217aa6896ef46d3e1a90bc64e8178e1662 // 指向的 tree 对象

parent 7d000309cb780fa27898b4d103afcfa95a8c04db // 父提交

author Zoker <[email protected]> 1607958804 +0800 // 作者信息

committer Zoker <[email protected]> 1607958804 +0800 // 提交者信息



test ssh // 提交信息

C'est un objet de type commit, les principaux attributs sont l'objet d'arborescence vers lequel il pointe, son commit parent (s'il s'agit du premier commit, alors 0000000 ...), les informations d'auteur et de commit.

Alors, quel est l'objet de validation? Quel est l'objet d'arborescence vers lequel il pointe? Quelle est la différence avec l'objet blob que nous avons créé manuellement auparavant? Ensuite, parlons des objets de stockage Git.

Objets de stockage Git

Dans le monde Git, il existe quatre types d'objets de stockage: file (blob), tree (tree), commit (commit), tag (tag), ici nous discutons principalement des trois premiers types, car ces trois sont les plus basiques de Git métadonnées, et l'objet tag est juste une balise qui contient des informations d'attribut supplémentaires, c'est-à-dire une balise annotée, donc je n'en introduirai pas trop ici.

Introduction aux balises légères et annotées:
https://git-scm.com/book/zh/v2 ...% 25BE

Objet Blob

Lors de l'introduction de l'essence de Git, afin de démontrer que Git est une base de données KV basée sur l'adressage de contenu, nous avons inséré le contenu d'un fichier dans le référentiel Git:

➜  Zoker git:(master) ✗ cat testfile

Hello Git

➜  Zoker git:(master) ✗ git hash-object testfile -w

9f4d96d5b00d98959ea9960f069585ce42b1349a

L'
objet Git dont la clé est 9f4d96d5b00d98959ea9960f069585ce42b1349a est en fait un objet Blob, qui stocke la valeur du fichier testfile. Nous pouvons utiliser la commande cat-file pour afficher:

➜  Zoker git:(master) ✗ git cat-file -p 9f4d96d5b00d98959ea9960f069585ce42b1349a

Hello Git

Chaque fois que nous modifions un fichier, Git enregistrera un instantané complet du fichier au lieu d'enregistrer les différences, donc si nous modifions le contenu du fichier testfile et le sauvegardons à nouveau dans le référentiel Git, Git le générera en fonction de la dernière version actuelle. content Sa Clé, il faut noter que lorsque le contenu ne change pas, sa valeur Clé est fixe.Après tout, comme nous l'avons déjà dit, Git est une base de données KV basée sur l'adressage de contenu.

De plus, l'objet Blob stocke ici le contenu texte, il peut également s'agir de contenu binaire, mais il n'est pas recommandé d'utiliser Git pour gérer la version du fichier binaire. Le problème le plus courant rencontré par notre plate-forme Gitee dans le processus d'exploitation quotidien est que l'entrepôt utilisateur est trop grand. Cette situation est généralement causée par l'utilisateur soumettant un fichier binaire volumineux, car chaque changement de fichier est enregistré comme un instantané, donc ce binaire file Si les changements sont fréquents, l'espace qu'il occupe est doublé. Et pour les blobs de contenu texte, Git enregistrera uniquement les différences de fichiers entre les deux soumissions pendant le processus GC, ce qui peut économiser de l'espace, mais pour les blobs de contenu binaire, il ne peut pas être traité comme des blobs de contenu texte. contenu binaire dans le référentiel Git. Vous pouvez utiliser LFS pour le stocker. Si vous avez déjà un grand nombre de fichiers binaires, vous pouvez utiliser filter-branch pour perdre du poids. Les nouveaux collègues vous apprécieront certainement lorsqu'ils cloneront l'entrepôt pour la première fois.

L'utilisation de LFS:
https://gitee.com/help/articles/4235, l'amincissement du grand entrepôt: https://gitee.com/help/articles/4232, la branche-filtre: https: // github .com / git / git / blo ... h.txt

Pensez-vous que quelque chose ne va pas lorsque vous arrivez ici? C'est vrai, cet objet Blob ne stocke que le contenu de ce fichier, mais n'enregistre pas le nom du fichier, alors comment savoir à quel fichier ce contenu appartient? La réponse est un autre objet important de Git: l'objet Tree.

Objet d'arbre

Dans Git, la fonction principale de l'objet Tree est d'organiser plusieurs objets Blobs ou enfants Tree ensemble, et tout le contenu est stocké par des objets de type Tree et Blob. Un objet Tree contient une ou plusieurs Tree Entry (enregistrements d'objet d'arborescence), et chaque enregistrement d'objet d'arborescence contient un pointeur vers la valeur BLob ou sous-Tree SHA, ainsi que leurs noms de fichiers correspondants et d'autres informations, qui peuvent être comprises en fait Afin d'indexer la relation entre l'inode et le bloc dans le système de fichiers, si un objet Tree est affiché, comme indiqué ci-dessous:

Parlez du principe de stockage Git et de l'implémentation associée

 

La structure de répertoires correspondant à cet objet Tree est la suivante:

.

├── LICENSE

├── readme.md

└── src

├── libssl.so

└── logo.png

De cette façon, nous pouvons stocker le contenu de notre entrepôt d'une manière structurée comme la manière d'organiser les répertoires sous Linux, considérer Tree comme une structure de répertoires et Blob comme un contenu de fichier spécifique.

Alors, comment créer un objet Tree? Dans Git, l'objet Tree correspondant est créé en fonction de l'état de la zone intermédiaire. La zone intermédiaire ici est en fait la zone intermédiaire (mise en scène) que nous comprenons dans le processus quotidien d'utilisation de Git. Généralement, nous utilisons la commande git add pour add Certains fichiers sont ajoutés à la zone de préparation pour être soumis. Dans un entrepôt vide sans aucune soumission, le statut de cette zone de préparation correspond aux fichiers que vous avez ajoutés via git add, tels que:

➜  Zoker git:(master) ✗ git status

On branch master



No commits yet



Changes to be committed:

(use "git rm --cached <file>..." to unstage)

new file:   LICENSE

new file:   readme.md



Untracked files:

(use "git add <file>..." to include in what will be committed)

src/

L'état actuel de la zone de préparation ici est qu'il y a deux fichiers dans le répertoire racine. L'état de la zone de préparation est enregistré dans le fichier .git / index. Utilisons la commande file pour voir de quoi il s'agit:

➜  Zoker git:(master) ✗ file .git/index

.git/index: Git index, version 2, 2 entries

Vous pouvez trouver qu'il y a deux entrées dans le fichier d'index, c'est-à-dire les deux fichiers LICENSE et readme.md dans le répertoire racine. Pour un entrepôt qui a été soumis, s'il n'y a pas de contenu dans la zone de stockage temporaire, cet index représente la version actuelle de l'état de l'arborescence de répertoires. Si les fichiers sont modifiés ou supprimés et que la zone de stockage temporaire est ajoutée, l'index sera change, le pointeur du fichier associé pointe sur la valeur SHA du nouvel objet Blob du fichier.

Donc, si nous voulons créer un objet Tree, nous devons mettre quelque chose dans la zone de préparation.En plus d'utiliser git add, nous pouvons également utiliser la commande sous-jacente update-index pour créer une zone de préparation. Ensuite, nous créons un objet d'arborescence basé sur le fichier testfile qui a été créé ci-dessus. La première consiste à ajouter le fichier testfile à la zone de stockage temporaire:

➜  Zoker git:(master) ✗ git update-index --add testfile // 与 git add testfile 一样

➜  Zoker git:(master) ✗ git status

On branch master



No commits yet



Changes to be committed:

(use "git rm --cached <file>..." to unstage)

new file:   testfile

Dans ce processus, Git insère principalement le contenu du fichier de test dans l'entrepôt Git sous la forme d'un Blob, puis enregistre la valeur SHA du Blob retourné dans l'index, indiquant à la zone de stockage temporaire quel contenu du fichier est actuellement.

➜  Zoker git:(master) ✗ tree .git/objects

.git/objects

├── 9f

│   └── 4d96d5b00d98959ea9960f069585ce42b1349a

├── info

└── pack



3 directories, 1 file

➜  Zoker git:(master) ✗ git cat-file -p 9f4d96d5b00d98959ea9960f069585ce42b1349a

Hello Git

Lorsque Git exécute la commande update-index, il stocke le contenu du fichier spécifié en tant qu'objet Blob et l'enregistre dans l'état du fichier d'index. Puisque nous avons déjà inséré le contenu de ce fichier via la commande git hash-object, et que nous pouvons constater que, parce que le contenu est inchangé, la valeur SHA de l'objet Blob généré est également la même, si nous l'avons déjà inséré comme nous Les commandes suivantes sont équivalentes:

git update-index --add --cacheinfo 9f4d96d5b00d98959ea9960f069585ce42b1349a testfile

Cette commande place en fait l'objet Blob précédemment généré dans la zone de stockage temporaire et spécifie son nom de fichier comme testfile. Étant donné que notre zone de préparation a déjà un fichier testfile, nous pouvons utiliser la commande git write-tree pour créer un objet Tree en fonction de l'état actuel de la zone de préparation:

➜  Zoker git:(master) ✗ git write-tree

aa406ee8804971cf8edfd8c89ff431b0462e250c

➜  Zoker git:(master) ✗ tree .git/objects

.git/objects

├── 9f

│   └── 4d96d5b00d98959ea9960f069585ce42b1349a

├── aa

│   └── 406ee8804971cf8edfd8c89ff431b0462e250c

├── info

└── pack

Après avoir exécuté la commande, Git générera un
objet Tree avec une valeur SHA de aa406ee8804971cf8edfd8c89ff431b0462e250c en fonction de l'état de la zone de transit actuelle , et stockera cet objet Tree dans le répertoire .git / objects comme un objet Blob.

➜  Zoker git:(master) ✗ git cat-file -p aa406ee8804971cf8edfd8c89ff431b0462e250c

100644 blob 9f4d96d5b00d98959ea9960f069585ce42b1349a    testfile

Utilisez la commande cat-file pour afficher cet objet Tree, vous pouvez voir qu'il n'y a qu'un seul fichier sous cet objet, nommé testfile.

Parlez du principe de stockage Git et de l'implémentation associée

 

Nous continuons à créer le deuxième objet Tree. Nous avons besoin du fichier testfile modifié sous le deuxième objet Tree, du nouveau fichier testfile2 et du premier objet Tree comme répertoire dupliqué du deuxième objet Tree. Tout d'abord, nous ajoutons d'abord le fichier de test modifié et le fichier testfile2 nouvellement ajouté à la zone de stockage temporaire:

➜  Zoker git:(master) ✗ git update-index testfile

➜  Zoker git:(master) ✗ git update-index --add testfile2

➜  Zoker git:(master) ✗ git status

On branch master



No commits yet



Changes to be committed:

(use "git rm --cached <file>..." to unstage)

new file:   testfile

new file:   testfile2

Ensuite, nous devons accrocher le premier objet Tree au répertoire dupliqué, nous pouvons utiliser la commande read-tree pour réaliser:

➜  Zoker git:(master) ✗ git read-tree --prefix=duplicate aa406ee8804971cf8edfd8c89ff431b0462e250c 

➜  Zoker git:(master) ✗ git status

On branch master



No commits yet



Changes to be committed:

(use "git rm --cached <file>..." to unstage)

new file:   duplicate/testfile

new file:   testfile

new file:   testfile2

Ensuite, nous exécutons write-tree et visualisons le deuxième objet Tree via cat-file:

➜  Zoker git:(master) ✗ git write-tree

64d62cef754e6cc995ed8d34f0d0e233e1dfd5d1

➜  Zoker git:(master) ✗ git cat-file -p 64d62cef754e6cc995ed8d34f0d0e233e1dfd5d1

040000 tree aa406ee8804971cf8edfd8c89ff431b0462e250c    duplicate

100644 blob 106287c47fd25ad9a0874670a0d5c6eacf1bfe4e    testfile

100644 blob 098ffe6f84559f4899edf119c25d276dc70607cf    testfile2

Avec succès, nous avons non seulement modifié le contenu du fichier de testfile, mais également ajouté un nouveau fichier testfile2, et également traité le premier objet Tree comme le répertoire dupliqué du deuxième objet Tree. À ce stade, l'objet Tree ressemble à ceci:

Parlez du principe de stockage Git et de l'implémentation associée

 

Jusqu'à présent, nous savons comment créer manuellement un objet Tree, mais que faire si j'ai besoin de clichés de ces deux arbres différents plus tard? Vous ne vous souvenez pas des valeurs SHA de ces trois objets Tree? C'est vrai, il faut beaucoup d'efforts pour s'en souvenir. La clé est que nous ne savons pas qui a créé cet instantané, à quelle heure et pour quoi, et l'objet Commit (objet commit) peut nous aider à résoudre ce problème.

Objet de validation

L'objet Commit consiste principalement à enregistrer des informations supplémentaires sur l'instantané et à maintenir la relation linéaire entre les instantanés. Nous pouvons créer un commit via la commande git commit-tree. Cette commande signifie littéralement qu'il s'agit d'une commande utilisée pour soumettre un objet Tree en tant qu'objet Commit:

➜  Zoker git:(master) ✗ git commit-tree -h

usage: git commit-tree [(-p <parent>)...] [-S[<keyid>]] [(-m <message>)...] [(-F <file>)...] <tree>



-p <parent>           id of a parent commit object

-m <message>          commit message

-F <file>             read commit log message from file

-S, --gpg-sign[=<key-id>]

                      GPG sign commit

Les deux paramètres clés sont -p et -m. -P spécifie la soumission parente de cette soumission. S'il s'agit de la première soumission initiale, elle peut être ignorée ici; -m spécifie les informations de cette soumission, principalement utilisées pour décrire le raison de la soumission. Utilisons le premier objet Tree comme notre commit initial:

➜  Zoker git:(master) ✗ git commit-tree -m "init commit" aa406ee8804971cf8edfd8c89ff431b0462e250c

17ae181bd6c3e703df7851c0f7ea01d9e33a675b

Utilisez cat-file pour afficher cette soumission:

tree aa406ee8804971cf8edfd8c89ff431b0462e250c

author Zoker <[email protected]> 1613225370 +0800

committer Zoker <[email protected]> 1613225370 +0800



init commit

Le contenu stocké par Commit est un objet Tree et enregistre le validateur, l'heure de validation et les informations de validation. Nous nous référons au deuxième objet Tree basé sur ce Commit:

➜  Zoker git:(master) ✗ git commit-tree -p 17ae181bd -m "add dir" 64d62cef754e6cc995ed8d34f0d0e233e1dfd5d1

de96a74725dd72c10693c4896cb74e8967859e58

➜  Zoker git:(master) ✗ git cat-file -p de96a74725dd72c10693c4896cb74e8967859e58

tree 64d62cef754e6cc995ed8d34f0d0e233e1dfd5d1

parent 17ae181bd6c3e703df7851c0f7ea01d9e33a675b

author Zoker <[email protected]> 1613225850 +0800

committer Zoker <[email protected]> 1613225850 +0800



add dir

Nous pouvons utiliser git log pour afficher ces deux commits, ajoutez ici le paramètre --stat pour afficher l'enregistrement de changement de fichier:

commit de96a74725dd72c10693c4896cb74e8967859e58

Author: Zoker <[email protected]>

Date:   Sun Feb 13 22:17:30 2021 +0800



add dir



duplicate/testfile | 1 +

testfile           | 2 +-

testfile2          | 1 +

3 files changed, 3 insertions(+), 1 deletion(-)



commit 17ae181bd6c3e703df7851c0f7ea01d9e33a675b

Author: Zoker <[email protected]>

Date:   Sun Feb 13 22:09:30 2021 +0800



init commit



testfile | 1 +

1 file changed, 1 insertion(+)

À ce stade, la structure de l'objet entier est la suivante:

Parlez du principe de stockage Git et de l'implémentation associée

 

Exercice: utiliser des commandes de bas niveau pour créer un commit

N'utilisez que les commandes de bas niveau telles que l'arbre d'écriture de hash-object write-tree read-tree commit-tree que nous avons mentionné ci-dessus pour créer un commit, et pensez au processus équivalent à git add git commit.

Méthode de stockage d'objets

Grâce à l'introduction précédente, nous savons que Git résume les données dans différents types d'objets et calcule une valeur SHA en fonction du contenu à utiliser comme adressage. Alors, comment est-elle calculée? En prenant l'objet Blob comme exemple, Git effectue principalement les étapes suivantes:

  • Identifiez le type de l'objet, créez les informations d'en-tête, utilisez le type + octets de contenu + octets nuls comme informations d'en-tête, telles que l'objet blob 151 \ u0000
  • Assemblez les informations d'en-tête avec le contenu et calculez la somme de contrôle SHA-1
  • Compresser le contenu via zlib
  • Mettre son contenu dans le répertoire des objets correspondant par valeur SHA

Ces choses sont effectuées dans tout le processus. L'objet Tree et l'objet Commit sont similaires, sauf que le type de tête est différent. Je n'entrerai pas dans les détails ici. "Pro Git 2" explique comment utiliser Ruby pour obtenir la même chose dans le chapitre sur les principes internes de Git Logic, ceux qui sont intéressés peuvent le lire par eux-mêmes.

Principe interne de Git:
https://git-scm.com/book/zh/v2 ...% 25A1

Références Git

Nous pouvons afficher les informations pertinentes de la première version via git log --stat 17ae181b ci-dessus, et obtenir le contenu de cet instantané via cette chaîne de valeurs SHA, mais cela reste très gênant, car nous devons nous rappeler que la chaîne est sans signification Pour le moment, la référence Git est pratique. Dans le chapitre sur la structure des répertoires Git, nous avons introduit le répertoire refs. Nous savons que la valeur clé de l'objet Commit est stockée dans la référence, qui est la valeur SHA de l'objet De cette façon, nous donnerons à notre version actuelle un nom significatif, et généralement nous utiliserons master comme référence de branche par défaut:

➜  Zoker git:(master) ✗ echo "17ae181bd6c3e703df7851c0f7ea01d9e33a675b" >> .git/refs/heads/master

➜  Zoker git:(master) ✗ tree .git/refs

.git/refs

├── heads

│   └── master

└── tags

À ce stade, la valeur SHA de notre premier Commit est stockée dans le master, et nous pouvons utiliser master pour remplacer la chaîne sans signification de 17ae181b.

➜  Zoker git:(master) ✗ git cat-file -p master

tree aa406ee8804971cf8edfd8c89ff431b0462e250c

author Zoker <[email protected]> 1613916447 +0800

committer Zoker <[email protected]> 1613916447 +0800



init commit

Cependant, ce n'est pas notre dernière version. Notre dernière version est la deuxième soumission
de96a74725dd72c10693c4896cb74e8967859e58. De même, nous pouvons changer le contenu de refs / heads / master à la valeur SHA de cette soumission, mais ici nous utilisons une commande de bas niveau. Carry dehors.

➜  Zoker git:(master) ✗ git update-ref refs/heads/master de96a74725dd72c10693c4896cb74e8967859e58

➜  Zoker git:(master) ✗ cat .git/refs/heads/master

de96a74725dd72c10693c4896cb74e8967859e58

Pour le moment, le chef de branche pointe vers notre dernière version.

Parlez du principe de stockage Git et de l'implémentation associée

 

Pour résumer

Ce qui précède traite principalement des principes de stockage de base et de certaines implémentations de Git, ainsi que de certains tels que l'empaquetage de Pack, le mécanisme de négociation de transmission et le format de stockage. En raison des limites d'espace, nous n'en parlerons pas. Nous en discuterons plus tard sur la base de certains scénarios.

Auteur: Zoker

https://zoker.io/blog/talk-about-git-internals

Je suppose que tu aimes

Origine blog.csdn.net/pyf09/article/details/115095221
conseillé
Classement