Des identités définies par les contenus

Git est ce qu'on appelle un système de fichiers adressables par contenu. Ça veut dire que c'est le contenu qui définit l'identité d'un objet.

Git utilise à cet effet une fonction de hachage nommé s-h-a-1 (prononce "chawouane", pour Secured Hash Algorithm) qui va produire une clé unique de 160 bits, soit 40 caractères hexadécimaux, pour représenter un contenu donné. Note que SHA-1 n'est plus considéré comme sécurisé depuis 2005 et que Git est en train de migrer vers SHA-2.

Cette clé est également appelée "empreinte numérique" ou "somme de contrôle".

Dans le dépôt Git, les noms des fichiers pour les 4 types d'objets utilisent directement la clé.

Identité d'un blob

Pour un blob, l’identité est basée sur le contenu du fichier lui-même.

Prenons l'exemple d'un fichier dans mon répertoire courant de travail.
Lorsque je l’ajoute à ma base données Git, j’obtiens un blob dont le nom est l'identité résultante du hachage du contenu, donc des lignes du fichier. 

Si ensuite je prends ces mêmes lignes de contenu, et que je les copie à l'identique dans un autre fichier dans un sous-répertoire du projet par exemple, puis que j’ajoute ce même fichier à la base de données Git, Git exploitera alors le blob déjà en place puisque le contenu est strictement identique pour les deux fichiers.

Si par contre je venais à modifier le contenu de l'un des fichiers et que je l'ajoutais à nouveau à la base de données Git, j'obtiendrais alors un nouveau blob pour ce fichier, l'empreinte étant différente et inconnue jusqu'ici.

Identité d'un tree

On part de cet exemple pour comprendre la construction de l’identité d’un objet tree. On va dire que nos fichiers déjà créés sont les fichiers A et B et qu’il ont déjà été ajoutés à l’index.

Si je réalise le commit, Git va alors créer et ajouter les objets trees à la base de données.

Je constate que 2 objets trees on été créé pour représenter respectivement le répertoire racine du projet et le sous-répertoire.
Si j’analyse l'objet tree du répertoire racine, je constate qu'il contient une référence vers le tree du sous-répertoire et une référence vers le blob du fichier A. Il ne traite donc que de ce qu'il contient directement, et ce sont ces objets qui définissent son identité.
Ainsi, lorsque j’analyse le tree du sous-répertoire, je constate bien qu'il contient uniquement une référence vers le blob du fichier B.

Identité d'un commit

Mon schéma précédent n'était pas tout à fait complet. En effet, la création d'un commit entraîne sa représentation dans la base de données Git.

Si je regarde ce que contient cet objet commit dans le détail, j’y vois l’objet tree représentant le niveau racine du projet, d'éventuels commits parents, puis le reste des méta-données, à savoir l'auteur du commit, son commiteur, les horodatages, et enfin le message saisi par l'utilisateur.

Une fois de plus, c'est l'ensemble des ces éléments qui viennent définir l'identité du commit. Par conséquent toute modification de date, message, tree etc. donnera lieu à un autre commit en remplacement.

Vu que le ou les commits parents figurent également dans le fichier, ils impactent l'empreinte et donc l'identité : c'est pourquoi on dit que le SHA-1 d'un commit représente non seulement son contenu mais tout son historique, et que « déplacer » un commit dans le graphe de l'historique en altère l'identité.

Les concepts clés de Git

Git peut sembler mystérieux, mais comprendre ses concepts fonda­mentaux rend son utilisation lumineuse !