Annuler en toute sécurité
- Leçon 11
- 45 min
- Module 4 : Résoudre et récupérer
Leçon 11 sur 15 · L'essentiel de Git et du développement en équipeAnnuler en toute sécurité
1. Comprendre un dépôt
2. Travailler avec les branches et les dépôts distants
3. Collaborer par la revue de code
4. Résoudre et récupérer
5. Mises en production et correctifs urgents
Ce que vous saurez faire
Annulez une erreur sans nuire au travail de votre équipe. Après cette leçon, vous pourrez choisir la bonne commande pour chaque cas : une modification, une modification préparée, un commit local ou un commit déjà partagé.
Avant de commencerCe qu’il faut savoir et avoir sous la main
Ce que vous devez savoir
- Comment résoudre un conflit et terminer une fusion, dans Les conflits, étape par étape : résoudre, tester et créer un commit.
- Dans ce module, vous créez des commits (instantanés enregistrés), fusionnez et annulez des commits sur
mainpour garder les commandes courtes. En équipe, vous faites chaque changement sur une branche. Vous la fusionnez par une demande de tirage (pull request), comme dans Les étapes d’une demande de tirage.
Ce qu’il vous faut sur votre ordinateur
- Le laboratoire
~/projects/c14-labdans l’étatm04, avec votre fusion envoyée. Vous l’avez envoyée à la fin de Les conflits, étape par étape : résoudre, tester et créer un commit. - Dans
~/projects/c14-lab/ticket-notes, exécutezgit pull. La sortie doit indiquerAlready up to date.(déjà à jour) ouFast-forward(avance rapide). - Si
git pullindiqueNot possible to fast-forward(avance rapide impossible), votre fusion de la dernière leçon n’est pas terminée. Faites d’abord l’exemple détaillé de Les conflits, étape par étape, puis envoyez la fusion. - Pour repartir d’un état connu, exécutez
sh nextia-learning-labs/C14/setup.sh m04 --resetdans~/projects. Refaites ensuite l’exemple détaillé de Les conflits, étape par étape, jusqu’au derniergit push. - Vos propres commits, comme les commits de fusion, ont des empreintes différentes de celles de cette leçon. Les empreintes des commits de Sam provenant du script de préparation sont identiques.
Trois façons d’annuler
Section intitulée « Trois façons d’annuler »Git propose trois commandes qui « annulent ». Elles agissent à différents endroits. Une seule convient au travail que votre équipe possède déjà.
- Restore modifie les fichiers dans votre arbre de travail ou votre zone de préparation. Cette commande ne touche aucun commit. Utilisez-la pour les modifications que vous n’avez pas encore enregistrées dans un commit.
- Revert crée un nouveau commit qui fait l’inverse d’un ancien commit. Si l’ancien commit ajoutait une ligne, le commit d’annulation la supprime. L’ancien commit reste dans l’historique. Utilisez cette commande pour les commits que d’autres personnes possèdent déjà.
- Reset déplace votre branche actuelle vers un autre commit. Les commits après ce point ne sont plus sur la branche. Utilisez cette commande seulement pour les commits que personne d’autre ne possède.
| Commande | Ce qu’elle modifie | Sans risque pour les commits envoyés? |
|---|---|---|
git restore --staged <file> |
La zone de préparation. Votre modification reste dans le fichier. | Ne sert pas aux commits |
git restore <file> |
Le fichier dans l’arbre de travail. Votre modification est perdue. | Ne sert pas aux commits |
git revert <hash> |
Ajoute un nouveau commit à la branche. | Oui |
git reset <hash> |
Recule l’étiquette de la branche. | Non |
Pourquoi reset présente-t-il un risque pour les commits envoyés? Vos collègues possèdent déjà ces commits. Si vous reculez main, puis forcez l’envoi, les commits disparaissent du dépôt distant. La prochaine récupération de vos collègues échoue ou ramène les commits. Tout ce qui repose sur eux cesse de fonctionner. C’est une réécriture de l’historique partagé. Faites-le seulement si toute l’équipe donne d’abord son accord. Ne le faites jamais sur une branche partagée comme main pour corriger rapidement un problème. Une annulation avec revert ajoute à l’historique sans rien supprimer. Tout le monde peut donc la récupérer normalement.
Description textuelle du diagramme
- La modification est-elle enregistrée dans un commit? Sinon, passez à la question 2. Si oui, passez à la question 3.
- La modification est-elle préparée? Si oui, exécutez
git restore --staged <file>: elle quitte la zone de préparation et reste dans votre fichier. Sinon, exécutezgit restore <file>: la modification est supprimée, sans possibilité d’annulation. - Le commit est-il envoyé, ou quelqu’un d’autre le possède-t-il? Si oui, exécutez
git revert <hash>: un nouveau commit l’annule. Sinon, passez à la question 4. - Voulez-vous garder les modifications dans vos fichiers? Si oui, exécutez
git reset --soft HEAD~1: le commit disparaît, mais ses modifications restent préparées. Sinon, exécutezgit reset --hard HEAD~1: le commit et ses modifications disparaissent.
Annuler une modification non enregistrée dans un commit
Section intitulée « Annuler une modification non enregistrée dans un commit »Amira ajoute une ligne de test à tickets.txt et la prépare par erreur. git status indique la commande qui la retire de la zone de préparation :
On branch mainYour branch is up to date with 'origin/main'.
Changes to be committed: (use "git restore --staged <file>..." to unstage) modified: tickets.txtgit restore --staged tickets.txtgit status --short M tickets.txtLe M est passé à la deuxième colonne. La modification n’est plus préparée, mais elle reste dans le fichier. Amira ne veut pas garder cette ligne.
git restore tickets.txtgit status --shortLa deuxième commande n’affiche rien : l’arbre de travail est propre et la ligne de test a disparu.
Exemple détaillé : annuler le commit défectueux de Sam
Section intitulée « Exemple détaillé : annuler le commit défectueux de Sam »Trouver le commit
Section intitulée « Trouver le commit »Amira consulte contacts.txt. L’équipe réseau est absente :
Accounts team: ext. 4300Help desk: ext. 4100Elle liste les commits qui ont modifié ce fichier. Un -- avant un nom de fichier signifie « seulement les commits qui ont modifié ce fichier » :
git log --oneline -- contacts.txtf3bc1c5 Sort contacts by name55b7943 Add contactsLe message dit « sort » (trier), mais un message n’est pas la modification. Elle vérifie ce que le commit a réellement fait :
git show f3bc1c5commit f3bc1c576e109cc78d291f676c393381d5177526Author: Sam Okafor <sam@example.com>Date: Tue Oct 6 09:08:00 2026 -0400
Sort contacts by name
diff --git a/contacts.txt b/contacts.txtindex 0ce0116..209c541 100644--- a/contacts.txt+++ b/contacts.txt@@ -1,3 +1,2 @@Help desk: ext. 4100Network team: ext. 4410 Accounts team: ext. 4300Help desk: ext. 4100Sam a trié la liste. Il a aussi supprimé Network team: ext. 4410 (équipe réseau : poste 4410) par erreur. Sam a envoyé ce commit, puis le commit Add ticket 104 (ajouter le billet 104). Les deux commits sont dans le dépôt distant. La fusion d’Amira, faite à la dernière leçon, repose sur eux. Elle ne doit donc pas les supprimer de l’historique. Elle annule le commit défectueux avec revert.
L’annuler avec revert
Section intitulée « L’annuler avec revert »git revert applique la modification inverse dans un nouveau commit. --no-edit conserve le message écrit par Git :
git revert --no-edit f3bc1c5[main 6643efd] Revert "Sort contacts by name" Date: Mon Oct 5 22:05:28 2026 -0400 1 file changed, 2 insertions(+), 1 deletion(-)Elle examine le nouveau commit :
git log -1commit 6643efd8cee1fce74247da2fd0441d3117d7b7bcAuthor: Amira Khan <amira@example.com>Date: Mon Oct 5 22:05:28 2026 -0400
Revert "Sort contacts by name"
This reverts commit f3bc1c576e109cc78d291f676c393381d5177526.Le message indique l’empreinte complète du commit qu’il annule. Toute personne qui lit l’historique plus tard peut retrouver les deux commits.
Vérifier que le travail ultérieur est conservé
Section intitulée « Vérifier que le travail ultérieur est conservé »Une annulation avec revert annule un seul commit. Amira vérifie les deux fichiers :
cat contacts.txtgrep "Ticket 104" tickets.txtsh check.shHelp desk: ext. 4100Network team: ext. 4410Accounts team: ext. 4300Ticket 104: laptop will not charge. Replaced the power adapter.PASS: 4 ticket lines checkedgrep affiche les lignes d’un fichier qui contiennent le texte. L’équipe réseau est de retour. Le commit ultérieur de Sam, Add ticket 104, et la fusion d’Amira sont toujours présents. L’annulation est un nouveau commit ordinaire. Un envoi normal fonctionne donc :
git pushTo /Users/amira/projects/c14-lab/team-remote.git b850b9e..6643efd main -> mainLe tri était utile. Amira informe donc Sam de l’annulation. Sam peut trier de nouveau la liste dans un nouveau commit, cette fois avec les trois équipes.
Reset : seulement pour les commits que personne d’autre ne possède
Section intitulée « Reset : seulement pour les commits que personne d’autre ne possède »Reset déplace l’étiquette de votre branche vers un autre commit. Cette commande a trois modes. Chaque mode déplace la branche. Ils traitent différemment les modifications des commits qui quittent la branche :
| Mode | La branche | La zone de préparation | Vos fichiers |
|---|---|---|---|
git reset --soft HEAD~1 |
Recule d’un commit | Garde les modifications préparées | Gardent les modifications |
git reset HEAD~1 (--mixed, le mode par défaut) |
Recule d’un commit | Les modifications ne sont pas préparées | Gardent les modifications |
git reset --hard HEAD~1 |
Recule d’un commit | Correspond au commit | Les modifications sont supprimées |
HEAD~1 signifie « un commit avant HEAD ». HEAD~2 signifie deux commits avant.
Pour essayer reset sans risque, utilisez un clone jetable : une copie distincte du dépôt que vous supprimez après l’exercice. Rien de ce que vous y faites ne modifie votre ticket-notes. N’envoyez rien depuis ce clone.
Amira crée le clone à côté des autres et y ajoute un commit :
cd ~/projects/c14-labgit clone team-remote.git scratchcd scratchCloning into 'scratch'...done.Elle ajoute la ligne Ticket 105: monitor flickers. Replaced the cable. (billet 105 : l’écran clignote. Câble remplacé.) à tickets.txt. Elle l’enregistre dans un commit avec git commit -am "Add ticket 105". Le commit existe seulement dans scratch :
5dd5cac (HEAD -> main) Add ticket 1056643efd (origin/main, origin/HEAD) Revert "Sort contacts by name"Soft : le commit disparaît, mais sa modification reste préparée. Utilisez ce mode pour modifier le dernier commit avant de l’envoyer.
git reset --soft HEAD~1git status --shortM tickets.txtElle crée de nouveau un commit avec le même message, puis essaie le mode par défaut.
Mixed : le commit disparaît, mais sa modification reste dans le fichier, sans être préparée.
git commit -m "Add ticket 105"git reset HEAD~1Unstaged changes after reset:M tickets.txtHard : elle crée encore un commit, puis supprime le commit et sa modification.
git commit -am "Add ticket 105"git reset --hard HEAD~1HEAD is now at 6643efd Revert "Sort contacts by name"git status --short n’affiche rien. La ligne du billet 105 a disparu du fichier. Dans Récupérer son travail, vous apprendrez à récupérer un commit comme celui-ci.
Exercice guidé : annuler un commit, puis réinitialiser dans un clone
Section intitulée « Exercice guidé : annuler un commit, puis réinitialiser dans un clone »-
Allez dans votre clone et vérifiez qu’il est à jour :
Fenêtre de terminal cd ~/projects/c14-lab/ticket-notesgit pull -
Ajoutez la ligne
Test line. Delete me.(ligne de test à supprimer) à la fin detickets.txt, puis enregistrez. Ajoutez ensuite le fichier à la zone de préparation :Fenêtre de terminal git add tickets.txt -
Retirez-le de la zone de préparation, puis vérifiez :
Fenêtre de terminal git restore --staged tickets.txtgit status --shortLa sortie est
M tickets.txt: la modification est dans le fichier, mais pas dans la zone de préparation. -
Exécutez
git diff tickets.txt. Vérifiez que la ligne de test est la seule modification. Supprimez-la ensuite :Fenêtre de terminal git restore tickets.txtgit status --shortgit status --shortn’affiche rien. -
Trouvez le commit (enregistrement des modifications) qui a supprimé l’équipe Network :
Fenêtre de terminal git log --oneline -- contacts.txtgit show f3bc1c5La différence montre
-Network team: ext. 4410(suppression de l’équipe Network, poste 4410). -
Annulez ce commit :
Fenêtre de terminal git revert --no-edit f3bc1c5La sortie commence par
[mainet montreRevert "Sort contacts by name"(annuler le tri des contacts par nom). -
Vérifiez le résultat :
Fenêtre de terminal cat contacts.txtgrep "Ticket 104" tickets.txtsh check.shcontacts.txtcontient trois équipes. La ligne du billet 104 est toujours là. Le test affichePASS(réussite). -
Exécutez
git log -1. Le message contientThis reverts commit f3bc1c576e109cc78d291f676c393381d5177526.(ceci annule le commit indiqué). -
Envoyez les commits au dépôt distant :
Fenêtre de terminal git pushLa sortie montre
main -> main. -
Créez un clone temporaire :
Fenêtre de terminal cd ~/projects/c14-labgit clone team-remote.git scratchcd scratch -
Dans
scratch, ajoutez une ligne pour le billet 105 danstickets.txt. Enregistrez, puis créez un commit :Fenêtre de terminal git commit -am "Add ticket 105" -
Exécutez
git reset --soft HEAD~1, puisgit status --short. La sortie estM tickets.txt: la modification est dans la zone de préparation. -
Créez à nouveau un commit avec
git commit -m "Add ticket 105". Exécutez ensuitegit reset HEAD~1, puisgit status --short. La sortie estM tickets.txt: la modification n’est pas dans la zone de préparation. -
Vérifiez avec
pwdque vous êtes dansscratch. Créez ensuite un nouveau commit et réinitialisez avec--hard:Fenêtre de terminal git commit -am "Add ticket 105"git reset --hard HEAD~1git status --shortgit status --shortn’affiche rien. La ligne du billet 105 a disparu. -
Supprimez le clone temporaire. La prochaine leçon en crée un nouveau.
rm -rfsupprime un dossier sans possibilité d’annulation. Vérifiez donc son nom avant d’appuyer sur Enter (Entrée) :Fenêtre de terminal cd ~/projects/c14-labrm -rf scratch
À vous de jouer : annuler un commit et garder le suivant
Section intitulée « À vous de jouer : annuler un commit et garder le suivant »Sam fait une autre erreur, puis fait du bon travail après. Jouez les deux rôles.
- Dans
sam-notes, exécutezgit pull. Danscontacts.txt, remplacezAccounts team: ext. 4300(équipe Accounts, poste 4300) parAccounts team: ext. 4030(équipe Accounts, poste 4030). Créez un commit avec le messageUpdate the accounts team extension(mettre à jour le poste de l’équipe Accounts). - Toujours dans le rôle de Sam, ajoutez la ligne
Ticket 105: new starter has no email account. Created the account.(billet 105 : une nouvelle personne n’a pas de compte courriel; compte créé) àtickets.txt. Créez un commit avec le messageAdd ticket 105(ajouter le billet 105). Envoyez les deux commits au dépôt distant. - Dans
ticket-notes, récupérez les commits du dépôt distant. Le bon poste est 4300. Annulez la modification incorrecte de Sam et gardez son billet 105. Envoyez le résultat au dépôt distant.
Notez les commandes que vous avez utilisées. Expliquez pourquoi vous n’avez pas utilisé git reset.
Afficher une réponse modèle
cd ~/projects/c14-lab/ticket-notesgit pullgit log --oneline -3f30d4c7 Add ticket 105815c329 Update the accounts team extension6643efd Revert "Sort contacts by name"Vos empreintes sont différentes. Vérifiez la modification avant de l’annuler. git show 815c329 montre -Accounts team: ext. 4300 et +Accounts team: ext. 4030 (remplacement du poste 4300 par 4030). Ensuite :
git revert --no-edit 815c329cat contacts.txttail -1 tickets.txtsh check.shgit push[main 2bf80ca] Revert "Update the accounts team extension"Help desk: ext. 4100Network team: ext. 4410Accounts team: ext. 4300Ticket 105: new starter has no email account. Created the account.PASS: 5 ticket lines checkedtail -1 affiche la dernière ligne d’un fichier. Le poste est de nouveau 4300, et le billet 105 de Sam est toujours là.
Pourquoi ne pas réinitialiser? Les deux commits de Sam sont sur le dépôt distant. Pour supprimer 815c329 par réinitialisation, vous devez ramener main avant ce commit. Cela supprime aussi Add ticket 105. Le dépôt distant rejette ensuite votre envoi, car votre branche main est en retard. L’annulation supprime seulement les effets du commit incorrect, et tout le monde peut la récupérer.
Erreur courante
Réinitialiser un commit déjà envoyé, puis voir l'envoi rejeté
Symptôme : vous avez utilisé une réinitialisation pour supprimer un commit déjà envoyé au dépôt distant. Ici, Amira essaie de supprimer f3bc1c5 dans un clone temporaire avec git reset --hard f3bc1c5~1 :
HEAD is now at e058b3f Add ticket 103grep "Ticket 104" tickets.txt n’affiche rien. Le commit suivant de Sam et la fusion ont aussi disparu de main. Ensuite, git status et git push affichent :
Your branch is behind 'origin/main' by 5 commits, and can be fast-forwarded. (use "git pull" to update your local branch) ! [rejected] main -> main (non-fast-forward)error: failed to push some refs to '/Users/amira/projects/c14-lab/team-remote.git'hint: Updates were rejected because the tip of your current branch is behindhint: its remote counterpart. ...Le nombre de commits peut être différent dans votre dépôt.
Cause : la réinitialisation a ramené votre branche main en arrière. Elle a supprimé le commit incorrect et tous les commits suivants. Le dépôt distant contient toujours ces commits, donc votre branche main est en retard. Git rejette l’envoi, car il supprimerait les commits de votre équipe du dépôt distant.
Solution : ne forcez pas l’envoi. Récupérez les commits partagés, puis annulez le commit incorrect.
-
Exécutez
git pull. C’est une avance rapide :mainavance jusqu’au même commit queorigin/main.Sortie (premières lignes) Updating e058b3f..dbad696Fast-forward -
Exécutez
git log --oneline -5et cherchez un commitRevert(annulation). Dans cet exercice,maincontient déjà votre annulation de l’exemple détaillé. Arrêtez-vous donc ici et supprimez le clone temporaire. -
Dans un vrai dépôt, exécutez
git revert --no-edit <hash>dans votre propre clone, pas dans un clone temporaire. Exécutez ensuitesh check.shetgit push.
Un envoi forcé, git push --force, remplacerait la branche distante main par la vôtre, et les commits de Sam disparaîtraient. Ne forcez jamais un envoi vers une branche partagée pour corriger une erreur. Si votre équipe doit vraiment réécrire l’historique partagé, entendez-vous d’abord ensemble.
Vérifiez votre compréhension
Prédisez : Amira annule un commit qui a ajouté la ligne « Billet 110: ... ». À quoi ressemble l'historique après l'annulation, et contient-il encore l'ancien commit?
Afficher la réponse
L’historique contient un commit de plus au sommet : Revert "...", avec This reverts commit <hash>. (ceci annule le commit indiqué) dans son message. Ce nouveau commit supprime la ligne. L’ancien commit reste dans l’historique avec sa ligne, donc git show <old hash> l’affiche toujours. L’annulation ajoute des éléments à l’historique. Elle n’en supprime jamais.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Vérifiez votre compréhension
Vérification pratique : pour chaque situation, nommez la commande. (a) Vous avez ajouté un fichier à la zone de préparation par erreur. (b) Vous avez modifié un fichier et voulez retrouver la dernière version enregistrée dans un commit. (c) Un commit incorrect est sur le dépôt distant. (d) Votre dernier commit n'a pas été envoyé, et vous voulez le modifier.
Afficher la réponse
- (a)
git restore --staged <file>. La modification reste dans le fichier. - (b)
git restore <file>. Lisez d’abordgit diff <file>: la modification ne pourra pas être récupérée. - (c)
git revert <hash>, puis testez et envoyez au dépôt distant. Les commits suivants des autres personnes restent. - (d)
git reset --soft HEAD~1. Les modifications restent dans la zone de préparation. Corrigez-les, puis créez un nouveau commit.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Récapitulatif
- Restore (restaurer) agit sur les fichiers dont les modifications ne sont pas enregistrées dans un commit.
--stagedles retire de la zone de préparation; sans cette option, la modification est supprimée. - Revert crée un nouveau commit qui annule un ancien commit. C’est la façon sûre d’annuler un commit que l’équipe possède déjà. Les commits suivants restent.
- Reset (réinitialiser) ramène votre branche en arrière. Utilisez-le seulement pour les commits que personne d’autre ne possède.
--softet le mode par défaut gardent vos modifications.--hardles supprime. - Ne réécrivez pas l’historique partagé pour corriger une erreur. Si une réinitialisation fait échouer un envoi, récupérez les commits, puis annulez le commit incorrect.
- Essayez d’abord les commandes destructives dans un clone temporaire.
Leçon suivante : Récupérer son travail