Prise de tête avec HEAD
Dans le précédent atelier pratique, nous avons vu en détail le renommage des
branches. Aujourd'hui nous allons nous intéresser de plus près au rôle de ce
mystérieux HEAD que vous avez pu voir apparaître dans les logs.
Comprendre HEAD par la pratique
Lorsqu'on souhaite afficher la différence entre deux commits, on peut très bien utiliser la procédure suivante :
-
Afficher les logs avec
git loget les options qui vont bien. -
Repérer les identifiants respectifs des commits que l'on souhaite comparer.
-
Invoquer
git diffen effectuant deux opérations successives de copier/coller sur ces identifiants.
Une autre manière de faire - et qui est bien plus commode pour les commits
relativement récents - utilise la référence HEAD.
Prenons un dépôt Git simple avec un historique linéaire sans la moindre branche :
$ cd ~/formation-git/atelier-23/
$ git log --oneline
b71f6b2 (HEAD -> master) Renommage du fichier
cbeca14 Ajout du fichier Cartes
7def037 Ajout d'une destination
9159976 Ajout du fichier Entretien
4220c4c Ajout du fichier Roadtrip
Vous êtes ici
Vous connaissez tous le fameux petit symbole VOUS ÊTES ICI sur les plans
affichés dans le centre historique des villes et des grands centres
commerciaux ? Ou alors l'icône qui symbolise votre emplacement actuel
dans les applications de géolocalisation de votre smartphone ? Le
rôle de HEAD dans Git, c'est exactement cela : vous montrer votre
emplacement actuel dans l'historique.
Admettons que dans mon dépôt Git, je souhaite afficher la différence entre
l'avant-dernier et le dernier commit. Dans ce cas, j'effectue un
copier/coller des identifiants respectifs, et j'invoque git diff comme
ceci :
$ git diff cbeca14 b71f6b2
diff --git a/Entretien.md b/Maintenance.md
similarity index 100%
rename from Entretien.md
rename to Maintenance.md
Lequel d'abord ?
Notez bien que j'écris d'abord l'identifiant du commit parent.
Alternativement, je pourrais utiliser la syntaxe suivante :
$ git diff HEAD~1 HEAD
diff --git a/Entretien.md b/Maintenance.md
similarity index 100%
rename from Entretien.md
rename to Maintenance.md
-
HEADest la référence qui désigne le commit actuel. -
HEAD~1représente le premier parent du commit actuel.
Admettons maintenant que je veuille afficher la différence entre l'avant-dernier commit et son parent. En utilisant les identifiants respectifs, voilà ce que j'obtiendrais :
$ git diff 7def037 cbeca14
diff --git a/Cartes.md b/Cartes.md
new file mode 100644
index 0000000..a6e35b6
--- /dev/null
+++ b/Cartes.md
@@ -0,0 +1,9 @@
+# Cartes routières
+
+- [ ] France
+
+- [ ] Italie
+
+- [ ] Suisse
+
+- [ ] Autriche
Et en utilisant HEAD :
$ git diff HEAD~2 HEAD~1
diff --git a/Cartes.md b/Cartes.md
new file mode 100644
index 0000000..a6e35b6
--- /dev/null
+++ b/Cartes.md
@@ -0,0 +1,9 @@
+# Cartes routières
+
+- [ ] France
+
+- [ ] Italie
+
+- [ ] Suisse
+
+- [ ] Autriche
Vous l'aurez compris : lorsqu'on écrit HEAD~n, le nombre n après le
symbole tilde ~ symbolise le n-ième ancêtre du commit actuel.
Mais ce n'est pas tout. Rappelez-vous que lorsque nous fusionnons deux branches avec un merge commit, ce dernier se distingue par le fait qu'il a deux commits parents. Comment faire alors ?
Pour ne pas nous perdre dans les méandres soporifiques de la théorie, cherchons tout de suite un exemple pratique :
$ cd ~/formation-git/atelier-16
$ git log --oneline --graph --all
* 403fb57 (HEAD -> master) Merge branch 'hello-figlet'.
|\
| * d0c718c (hello-figlet) Message en lettres ASCII.
* | 36bfb46 (hello-cow) Message avec une vache qui parle.
|/
* 797fe52 Commit initial.
-
Concrètement, le commit actuel
403fb57est le produit de la fusion des deux commits parents36bfb46etd0c718c. -
Avec la référence
HEAD, nous pourrons désigner le premier parent (36bfb46) parHEAD^1et le deuxième parent (d0c718c) parHEAD^2.
Si j'essaie de mettre en pratique cette manière de faire, je devrais obtenir le même résultat pour les deux commandes suivantes :
Est-ce que je pourrais aller plus loin ? Oui, en combinant les deux écritures :
-
HEAD^1~1est le premier ancêtre du premier parent. -
HEAD^1~2est le deuxième ancêtre du premier parent. -
HEAD^2~1est le premier ancêtre du deuxième parent. -
HEAD^2~2est le deuxième ancêtre du deuxième parent. -
Etc.
Là aussi, je vais tester ce principe dans la pratique en vérifiant si j'obtiens un résultat identique pour les commandes suivantes :
Ou encore :
Différents chemins mènent à Saint-Bauzille-de-Putois
Vous l'aurez remarqué : dans notre exemple, le commit 797fe52 peut
être référence par HEAD^1~1 aussi bien que par HEAD^2~2.
À vous de jouer !
Rendez-vous dans le répertoire atelier-15/hello et affichez l'historique
complet du dépôt :
$ cd ~/formation-git/atelier-15/hello/
$ git log --oneline --graph --all
* b2139e1 (HEAD -> master) Merge branch 'hello-figlet'.
|\
| * 8db1b22 Premier jet avec des majuscules ASCII.
* | 5a7dd1d Merge branch 'hello-cow'.
|\ \
| * | 477d1a0 Implémentation d'une vache fatiguée.
| * | d268724 Premier jet de la vache qui dit bonjour.
| |/
* / 89211a3 Peaufinage du script initial.
|/
* bebe769 Commit initial.
La commande git rev-parse --short permet d'afficher l'identifiant
correspondant à la référence avec HEAD :
-
Essayez de référencer tous les commits du dépôt en utilisant l'écriture avec
HEAD. -
Trouvez les trois écritures possibles pour le commit initial
bebe769. -
Prenez un cachet d'aspirine.
La rédaction de cette documentation demande du temps et des quantités significatives de café espresso. Vous appréciez ce site ? Offrez un café au rédacteur en cliquant sur la tasse.


