Voici le dix-neuvième volet de la formation Git. Dans mon précédent article, nous avons vu en détail le rôle de la référence HEAD
. Aujourd’hui nous allons voir ensemble ce que vous pouvez faire si vous souhaitez supprimer ou autrement défaire un commit avec Git. Ce sera l’occasion de mettre en pratique ce que nous avons appris sur HEAD
.
Plutôt soft ou hard ?
Faisons une petite démonstration pratique avec le dépôt Git formation-git/atelier-18
. Effectuez une nouvelle copie de travail de ce dépôt :
$ cd ~/formation-git/ $ cp -R atelier-18/ atelier-26 $ cd atelier-26/
Affichons sommairement son historique :
$ git log --oneline cbeca14 (HEAD -> master) Ajout du fichier Cartes. 7def037 Ajout d'une destination. 9159976 Ajout du fichier Entretien. 4220c4c Ajout du fichier Roadtrip.
D’après les logs, le dernier commit a ajouté un fichier au dépôt. Voyons ce que cela a donné en détail :
$ git diff HEAD~1 HEAD 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
À ce stade, vous vous dites que réflexion faite, ce n’est pas la peine d’établir une liste de cartes routières, puisque vous disposez d’un GPS avec des cartes pour toute l’Europe. Le fichier Cartes.md
est donc inutile, tout comme le dernier commit qui l’a ajouté au dépôt. Est-ce qu’il n’y aurait pas moyen de supprimer ce dernier commit et le fichier qui va avec ?
Oui, avec la commande git reset
, qui permet de déplacer la référence HEAD
.
Un reset
peut fonctionner de trois manières :
- soft
- mixed
- hard
Voyons par la pratique ce que cela donne et commençons par la méthode douce :
$ git reset --soft HEAD~1
Examinons le résultat de cette opération :
$ git log --oneline 7def037 (HEAD -> master) Ajout d'une destination. 9159976 Ajout du fichier Entretien. 4220c4c Ajout du fichier Roadtrip. $ ls Cartes.md Entretien.md Roadtrip.md $ git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: Cartes.md
Voici en gros ce qui s’est passé :
- Le dernier commit a été supprimé.
- Plus exactement,
HEAD
a été déplacé versHEAD~1
. - Le fichier
Cartes.md
a été placé dans l’index. - On en trouve une copie dans le répertoire de travail.
Si jamais je change d’avis, je peux donc rétablir l’état de mon dépôt comme ceci :
$ git commit -m "Ajout du fichier Cartes." [master 591f650] Ajout du fichier Cartes. 1 file changed, 9 insertions(+) create mode 100644 Cartes.md $ git log --oneline 591f650 (HEAD -> master) Ajout du fichier Cartes. 7def037 Ajout d'une destination. 9159976 Ajout du fichier Entretien. 4220c4c Ajout du fichier Roadtrip.
Comment se passent les choses si j’effectue un reset
en mode mixed ? Essayons :
$ git reset --mixed HEAD~1 $ git log --oneline 7def037 (HEAD -> master) Ajout d'une destination. 9159976 Ajout du fichier Entretien. 4220c4c Ajout du fichier Roadtrip. $ ls Cartes.md Entretien.md Roadtrip.md $ git status On branch master Untracked files: (use "git add <file>..." to include in what will be committed) Cartes.md nothing added to commit but untracked files present (use "git add" to track)
- Le dernier commit a disparu.
- Cette fois-ci, le fichier
Cartes.md
n’a pas été copié dans l’index. - En revanche, il est toujours présent dans le répertoire de travail.
Si je veux annuler l’opération de suppression du commit, je peux toujours faire marche arrière comme ceci :
$ git add Cartes.md $ git commit -m "Ajout du fichier Cartes." [master 51ac9f6] Ajout du fichier Cartes. 1 file changed, 9 insertions(+) create mode 100644 Cartes.md $ git log --oneline 51ac9f6 (HEAD -> master) Ajout du fichier Cartes. 7def037 Ajout d'une destination. 9159976 Ajout du fichier Entretien. 4220c4c Ajout du fichier Roadtrip.
Il ne nous reste plus qu’à inspecter le fonctionnement du mode hard :
$ git reset --hard HEAD~1 HEAD is now at 7def037 Ajout d'une destination. $ git log --oneline 7def037 (HEAD -> master) Ajout d'une destination. 9159976 Ajout du fichier Entretien. 4220c4c Ajout du fichier Roadtrip. $ ls Entretien.md Roadtrip.md $ git status On branch master nothing to commit, working tree clean
- Le dernier commit a disparu des logs.
- Le fichier
Cartes.md
a également été envoyé au paradis des octets. On ne le trouve plus ni dans l’index, ni dans le répertoire de travail.
Deux remarques sur ces différentes façons d’effectuer un reset
:
- Le mode mixed est le mode utilisé par défaut :
git reset HEAD~1
équivaut àgit reset --mixed HEAD~1
. - Contrairement aux modes soft et mixed, le mode hard est un mode destructif.
Défaire un commit
Il existe une autre façon de revenir sur ses pas et détricoter ce qu’on vient de faire, c’est la commande git revert
. Là encore, un exemple pratique vous permettra de mieux comprendre. Effectuez une nouvelle copie de travail du dépôt Git formation-git/atelier-18
:
$ cd ~/formation-git/ $ cp -R atelier-18/ atelier-27 $ cd atelier-27/
C’est toujours le même dépôt que dans l’exemple ci-dessus :
$ git log --oneline cbeca14 (HEAD -> master) Ajout du fichier Cartes. 7def037 Ajout d'une destination. 9159976 Ajout du fichier Entretien. 4220c4c Ajout du fichier Roadtrip.
Tout à l’heure nous avons invoqué git diff
pour savoir en quoi consistait exactement ce dernier commit :
$ git diff HEAD~1 HEAD 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
Si je souhaite faire marche arrière, j’ai le choix :
- Je peux supprimer le commit grâce à
git reset
, comme nous venons de le voir. - Alternativement, je peux faire une sorte de « commit inversé » grâce à la commande
git revert
.
Voyons ce que cela donne dans la pratique :
$ git revert HEAD
Cette opération ouvre l’éditeur par défaut avec un message de commit :
Revert "Ajout du fichier Cartes." This reverts commit cbeca14d6f520ccf1ad9c15098d8a6dcbb66c112.
Je garde le message de commit tel quel et je l’enregistre :
Removing Cartes.md [master 301909d] Revert "Ajout du fichier Cartes." 1 file changed, 9 deletions(-) delete mode 100644 Cartes.md
L’opération s’est soldée par un nouveau commit :
$ git log --oneline 301909d (HEAD -> master) Revert "Ajout du fichier Cartes." cbeca14 Ajout du fichier Cartes. 7def037 Ajout d'une destination. 9159976 Ajout du fichier Entretien. 4220c4c Ajout du fichier Roadtrip.
Maintenant, si j’effectue un git diff
pour voir la différence entre les deux précédents commits, je m’aperçois qu’ils sont exactement opposés :
$ 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 $ git diff HEAD~1 HEAD diff --git a/Cartes.md b/Cartes.md deleted file mode 100644 index a6e35b6..0000000 --- a/Cartes.md +++ /dev/null @@ -1,9 +0,0 @@ -# Cartes routières - -- [ ] France - -- [ ] Italie - -- [ ] Suisse - -- [ ] Autriche
Notez la différence cruciale dans la syntaxe :
- Lorsque vous écrivez
git revert HEAD
, vous écrivez en argument l’ID du commit que vous souhaitez défaire. - Avec
git reset HEAD~1
, vous fournissez l’ID du commit vers lequel vous souhaitez revenir.
Vous voilà donc confronté à un choix : utiliser reset
ou revert
? À vous de voir si vous préférez réécrire l’histoire ou garder une trace de vos errances.
Éditer un message de commit
Il nous reste à voir un dernier cas de figure. Il peut arriver que l’on effectue un commit avec un message pas assez explicite ou autrement inapproprié. Et après coup on se dit qu’on aurait pu faire mieux. Dans ce cas, Git nous permet de rectifier le tir.
Revenez dans le dépôt Git ~/formation-git/atelier-26
et affichez les logs :
$ cd ../atelier-26 $ git log --oneline 7def037 (HEAD -> master) Ajout d'une destination. 9159976 Ajout du fichier Entretien. 4220c4c Ajout du fichier Roadtrip.
Le message de mon dernier commit dit « Ajout d’une destination ». Admettons que j’aurais préféré écrire « Ajout d’une étape ». Dans ce cas, je peux faire ceci :
$ git commit --amend -m "Ajout d'une étape." [master 2393db1] Ajout d'une étape. Date: Tue Jan 31 07:56:14 2023 +0100 1 file changed, 2 insertions(+)
Ici j’ai rectifié le tir avec un nouveau commit au contenu identique mais avec un message différent :
$ git log --oneline 2393db1 (HEAD -> master) Ajout d'une étape. 9159976 Ajout du fichier Entretien. 4220c4c Ajout du fichier Roadtrip.
Gardez à l’esprit que cette fonctionnalité est limitée au dernier commit en cours. Elle ne vous permettra pas d’éditer des messages de commits antérieurs.
Exercice
- Effectuez trois copies du dépôt Git
atelier-12
et nommez-les respectivementatelier-28
,atelier-29
etatelier-30
. - Inspectez sommairement le contenu et l’historique du dépôt
atelier-28
. - Essayez de savoir en quoi consistait le dernier commit sur la branche
hello-cow
. - Supprimez ce commit en mode soft.
- Changez d’avis et revenez en arrière.
- Supprimez le dernier commit en mode mixed.
- Changez d’avis et revenez en arrière.
- Supprimez le dernier commit en mode hard.
- Changez d’avis et… rendez-vous compte en grinçant des dents qu’il est trop tard pour changer d’avis.
- Placez-vous à la racine du dépôt Git dans le répertoire
atelier-29
. - Défaites le dernier commit de la branche
hello-cow
en gardant une trace de ce détricotage. - Affichez le détail des deux derniers commits et comparez-les.
- Placez-vous à la racine du dépôt Git dans le répertoire
atelier-30
. - Affichez les logs du dépôt.
- Remplacez le message du dernier
commit
sur la branchehello-cow
par « Afficher une vache fatiguée ».
Lire la suite : Cloner un dépôt
La rédaction de cette documentation demande du temps et des quantités significatives de café espresso. Vous appréciez ce blog ? Offrez un café au rédacteur en cliquant sur la tasse.
0 commentaire