Comment faire un commit sans la commande 'git commit'
- fabricefontenoy
- Dec 16, 2022
- 4 min read
Updated: Oct 5, 2023

Aujourd'hui, je vais vous expliquer un truc inutile sur git, enfin presque....
Je vais vous expliquer comment faire un commit sans utiliser la commande git commit !
"Mais à quoi cela va bien pouvoir me servir ????"
En pratique, à rien !
Mais c'est un bon exercice pour comprendre comment git fonctionne under the hood comme disent les anglo-saxons.
Et cherry on the cake, on ne va même pas créer ou modifier de fichiers !
Bon alors par quoi on commence ?
D'abord, il faut savoir ce qu'est un objet de type blob dans git.
Un blob correspond au stockage atomique de git, c'est à dire la plus petite quantité de stockage. Il ne contient que du contenu, pas d'information sur le chemin ou encore les droits d'accès.
Pour créer un tel blob on utilise la commande hash-object. Cette commande est une commande bas-niveau (plumbing commande) et peut être utilisée comma ça :
$ echo "Ceci est un exemple de contenu de blob" | git hash-object -w --stdin
5d43a4733c3620d1c03140d04592a7e6c8be7fb0
Cette commande compresse le contenu avec la librairie zlib et construit un hash code (qu'on appelle aussi "SHA-one" de part l'algo de hachage utilisé). Ce contenu compressé est alors stocké dans le répertoire .gît/objects.

💡 vous ne remarquez pas un point commun entre le SHA-1 et le chemin du fichier créé dans le répertoire.git/objects ???
Si on veut voir le contenu d'un objet git, on peut utiliser la commande bas-niveau cat-file :
$ git cat-file -p 5d43a4733c3620d1c03140d04592a7e6c8be7fb0
Ceci est un exemple de contenu de blob
Une fois que l'on a créé le blob, il nous faut créer un autre type d'objet git, un tree. Ce type d'objet nous sert notamment à associer un chemin et des droits d'accès au contenu que l'on vient de créer.
Un tree est une liste de SHA-1 correspondant soit à un blob soit à un tree. Chaque ligne d'un tree contient également le nom du fichier ou du répertoire correspondant, le type d'objet (blob ou tree) et les droits d'accès correspondants
On peut par exemple récupérer le tree correspondant au commit sur lequel on est :
$ git cat-file -p HEAD^{tree}
100644 blob 3e757656cf36eca53338e520d134963a44f793f8 new.txt
100644 blob 9da053fde36de95d90b9662d80a4be8e55e57560 test.txt
040000 tree 8c3c7fbcd903744b20fd7567a1fcefa99133b5bc test
Pour la création d'un objet tree, git récupère l'état de l'index et crée l'ensemble des objets tree correspondant à cet index
Pour ajouter le blob que l'on a créé à la première étape à l'index, on utilise la commande suivante :
$ git update-index --add --cacheinfo 100644 5d43a4733c3620d1c03140d04592a7e6c8be7fb0 mon_blob.txt
Même si on n'a pas créer de fichier pour créer un blob, pour mettre à jour l'index avec ce blob, il nous faut lui spécifier un chemin.
Si à cet instant, on regarde notre statut git, on obtient ça :
Sur la branche master
Modifications qui seront validées :
(utilisez "git restore --staged <fichier>..." pour désindexer)
nouveau fichier : mon_blob.txt
Modifications qui ne seront pas validées :
(utilisez "git add/rm <fichier>..." pour mettre à jour ce qui sera validé)
(utilisez "git restore <fichier>..." pour annuler les modifications dans le répertoire de travail)
supprimé : mon_blob.txt
Ce qui est tout à fait normal puisqu'on a ajouté le blob à l'index mais on n'a créé aucun fichier. Donc git pense qu'on a supprimé le fichier après l'avoir ajouté à l'index.
Une fois l'index mis à jour, on construit un tree via la commande :
$ git write-tree
e5a2ee13e8696b9a2698d0bb0800b1cb06014c05
$ git cat-file -p e5a2ee13e8696b9a2698d0bb0800b1cb06014c05
100644 blob 5d43a4733c3620d1c03140d04592a7e6c8be7fb0 mon_blob.txt
100644 blob 3e757656cf36eca53338e520d134963a44f793f8 new.txt
100644 blob 9da053fde36de95d90b9662d80a4be8e55e57560 test.txt
040000 tree 8c3c7fbcd903744b20fd7567a1fcefa99133b5bc test
Maintenant que ce tree est créé, on va pouvoir créer un commit à l'aide de la plumbing commande commit-tree.
$ git commit-tree e5a2ee13e8696b9a2698d0bb0800b1cb06014c05 -p HEAD \
-m "My first commit done manually"
0569c1a3e5fc5c7459a83ef73b1108ca134646be
Cette commande crée un nouveau type d'objet git : le commit
Comme les autres objets git, on peut voir à quoi il ressemble grâce à la commande cat-file :
$ git cat-file -p 0569c1a3e5fc5c7459a83ef73b1108ca134646be
tree e5a2ee13e8696b9a2698d0bb0800b1cb06014c05
parent 5b94c98de3d5be53585001c51342679032fd5f4c
author Fabrice Fontenoy <fabrice.fontenoy@true-lines.com> 1671187056 +0100
committer Fabrice Fontenoy <fabrice.fontenoy@true-lines.com> 1671187056 +0100
My first commit done manually
On voit ainsi qu'un objet commit est composé :
d'un objet tree (qui représente le snapshot de l'ensemble des fichiers du commit)
d'un (ou plusieurs) commit(s) parent(s)
d'un author
d'une date
et d'un message de commit
À la suite de cette commande, le commit est créé et rattaché au commit parent, le HEAD.
$ git log --oneline --graph --all --decorate 0569c1a3e5fc5c7459a83ef73b1108ca134646be
* 0569c1a My first commit done manually
* 5b94c98 (HEAD -> master) Second commit
* 4f44992 First commit
Il nous reste plus qu'une seule étape : mettre à jour la branche master pour pointer sur ce nouveau commit.
$ git update-ref refs/heads/master 0569c1a3e5fc5c7459a83ef73b1108ca134646be
$ git log --oneline --graph --all --decorate
* 0569c1a (HEAD -> master) My first commit done manually
* 5b94c98 Second commit
* 4f44992 First commit
$ cat .git/refs/heads/master
0569c1a3e5fc5c7459a83ef73b1108ca134646be
Pour faire simple, la commande update-ref met à jour le fichier .git/refs/heads/master qui contient le SHA-1 du commit vers lequel pointe la branche master avec le SHA-1 de notre nouveau commit.
Et voilà, votre commit est créé et la branche master pointe dessus ! Si vous regarder votre répertoire, le fichier mon_blob.txt n'existe pas et le statut de git contient la suppression de ce fichier (pour les mêmes raisons que précédent). Mais si vous changez de branche et revenez sur master ou si vous poussez ce commit et que quelqu'un le récupère, alors le fichier mon_blob.txt sera alors créé.
Ce n'était pas si compliqué en fin de compte ! 😉
Comments