Annuler des modifications dans Git : Explications de Reset, Restore et Revert

Vous êtes perdu avec `git reset`, `git restore` et `git revert` ? Ce guide clarifie leurs différences et fournit des exemples pratiques. Apprenez à écarter les modifications en toute sécurité, à désindexer des fichiers et à réécrire ou annuler des commits dans votre historique Git. Maîtrisez ces commandes essentielles pour un contrôle de version efficace et une chronologie de projet plus nette.

50 vues

Annuler les changements dans Git : Explication de reset, restore et revert

Git est un système de contrôle de version puissant qui vous permet de suivre les modifications apportées à votre base de code. Cependant, des erreurs se produisent, et vous pourriez avoir besoin d'annuler des changements. Git fournit plusieurs commandes pour vous aider dans cette tâche, mais elles fonctionnent de manière très différente et affectent votre dépôt de manières distinctes. Comprendre les nuances entre git reset, git restore et git revert est crucial pour gérer efficacement l'historique de votre projet et corriger les erreurs sans conséquences imprévues.

Cet article va démystifier ces trois commandes, expliquant leur objectif, leur fonctionnement et quand utiliser chacune d'elles. Nous nous appuierons sur la documentation officielle de Git et les modèles d'utilisation courants pour fournir des explications claires et des exemples pratiques. À la fin de ce guide, vous serez équipé pour annuler les changements en toute confiance, gérer vos fichiers préparés (staged) et maintenir un historique de commits propre et cohérent.

Comprendre les Concepts Fondamentaux

Avant de plonger dans les commandes, il est important de saisir quelques concepts Git :

  • Répertoire de travail (Working Directory) : Les fichiers que vous êtes en train de modifier.
  • Zone de préparation (Staging Area / Index) : Une zone de stockage où vous préparez les changements avant de les commettre. git add déplace les changements du répertoire de travail vers la zone de préparation.
  • Historique des commits (Commit History) : Une séquence d'instantanés de votre projet au fil du temps, représentée par des commits.
  • HEAD : Un pointeur vers le dernier commit de votre branche actuelle.

Ces trois commandes interagissent principalement avec ces zones pour modifier ou rejeter des changements.

git restore : Pour rejeter les changements dans le répertoire de travail et la zone de préparation

La commande git restore, introduite plus récemment dans Git, est conçue pour la tâche simple d'annuler les changements dans votre répertoire de travail ou de désindexer (unstage) des fichiers. Elle est généralement considérée comme plus sûre et plus intuitive pour ces opérations spécifiques que git reset.

Désindexer des fichiers (Unstaging Files)

Si vous avez accidentellement préparé un fichier en utilisant git add et que vous souhaitez le désindexer, git restore est la commande à utiliser. Elle déplace les changements de la zone de préparation vers votre répertoire de travail, mais ne rejette pas les modifications elles-mêmes.

  • Désindexer un fichier spécifique :
    bash git restore <file>
    Cette commande prend la version du fichier de l'index (zone de préparation) et la replace dans l'index. Essentiellement, elle retire le fichier de la préparation pour le prochain commit, mais les modifications restent dans votre répertoire de travail.

  • Désindexer tous les fichiers :
    Bien qu'il n'y ait pas de git restore . direct pour désindexer tout comme git reset peut le faire, vous appliqueriez généralement git restore à des fichiers individuels ou l'utiliseriez conjointement avec d'autres commandes si nécessaire. Cependant, le cas d'utilisation le plus courant est la désindexation de fichiers spécifiques.

Rejeter les changements dans le répertoire de travail

git restore peut également être utilisé pour rejeter tous les changements non préparés dans votre répertoire de travail pour un fichier spécifique, le ramenant à la version présente dans la zone de préparation (index) ou à l'état de dernier commit.

  • Rejeter les changements non préparés dans un fichier :
    bash git restore <file>
    (Note : Cette commande peut avoir deux significations selon le contexte. Lorsqu'elle est utilisée sans --staged, elle cible principalement l'arbre de travail. Si le fichier est préparé, elle le désindexe. Si le fichier est modifié dans l'arbre de travail et n'est pas préparé, elle ramène le fichier de l'arbre de travail pour correspondre à l'index.)

  • Rejeter les changements préparés et non préparés pour un fichier (revenir à HEAD) :
    Pour rejeter complètement tous les changements (préparés et non préparés) pour un fichier et le ramener à l'état où il était lors du commit HEAD :
    bash git restore --staged --worktree <file>
    C'est une commande puissante qui réinitialise effectivement le fichier à son dernier état committé.

Restaurer un fichier à partir d'un commit spécifique

git restore peut également récupérer la version d'un fichier spécifique à partir d'un commit passé sans modifier l'historique de votre branche.

git restore <file> --source <commit>

Remplacez <commit> par le hachage du commit ou une référence symbolique comme HEAD~1.

git reset : Réécrire l'historique

git reset est une commande plus puissante qui peut modifier votre historique de commits en déplaçant le pointeur HEAD de la branche actuelle. Elle peut également affecter la zone de préparation et le répertoire de travail, selon le mode utilisé.

Comprendre les modes (--soft, --mixed, --hard)

git reset possède trois modes principaux :

  1. --soft : Déplace HEAD vers le commit spécifié mais laisse votre zone de préparation et votre répertoire de travail intacts. Les changements des commits réinitialisés apparaissent comme des changements préparés.
    bash git reset --soft HEAD^ # Déplace HEAD d'un commit en arrière, les changements du commit annulé sont préparés

  2. --mixed (par défaut) : Déplace HEAD et réinitialise la zone de préparation pour correspondre au commit spécifié. Les changements des commits réinitialisés sont présents dans votre répertoire de travail mais ne sont pas préparés.
    bash git reset HEAD^ # Équivalent à git reset --mixed HEAD^ # Déplace HEAD d'un commit en arrière, les changements du commit annulé ne sont pas préparés

  3. --hard : Déplace HEAD et réinitialise à la fois la zone de préparation et le répertoire de travail pour correspondre au commit spécifié. Ceci rejette tous les changements des commits réinitialisés et de tout changement non committé subséquent dans le répertoire de travail. À utiliser avec une extrême prudence.
    bash git reset --hard HEAD~ # Rejette le dernier commit ET tous les changements depuis lors dans le répertoire de travail et la zone de préparation

Cas d'utilisation pour git reset :

  • Désindexer des fichiers : git reset <file> est un raccourci pour git restore --staged <file>, retirant un fichier de la zone de préparation sans affecter le répertoire de travail.
  • Désindexer tout : git reset (sans arguments ou spécifiant HEAD) désindexe tous les changements actuellement préparés, les déplaçant vers le répertoire de travail (équivalent à git restore --staged .).
  • Annuler le dernier commit : git reset HEAD^ (ou git reset --soft HEAD^) est couramment utilisé pour amender le dernier commit. Les changements du commit précédent sont maintenant préparés, prêts à être re-committés avec des modifications ou un nouveau message.
  • Rejeter tous les changements locaux : git reset --hard est utilisé pour rejeter complètement toutes les modifications locales (préparées et non préparées) et ramener le dépôt à un commit spécifique. C'est une opération destructive.

Réinitialiser un ancien commit

Si vous avez besoin d'annuler les changements d'un commit qui n'est pas le plus récent, git reset peut être utilisé. Par exemple, pour réinitialiser à un commit avant un commit problématique :

# Exemple : Annuler les 2 derniers commits, en gardant les changements non préparés
git reset --mixed HEAD~2

Avertissement : git reset réécrit l'historique. Si vous avez déjà poussé les commits que vous réinitialisez, cela peut causer des problèmes importants pour vos collaborateurs. Il est généralement sûr de réinitialiser les commits qui n'existent que dans votre dépôt local.

git revert : Créer un nouveau commit pour annuler les changements

git revert est la manière la plus sûre d'annuler des changements dans un historique partagé ou publié. Au lieu de réécrire l'historique, il crée un nouveau commit qui introduit les changements inverses d'un commit précédent.

Comment ça fonctionne

Lorsque vous exécutez git revert <commit>, Git analyse le commit spécifié, calcule les changements opposés et les applique à votre répertoire de travail actuel et à votre zone de préparation. Il vous invite ensuite à créer un nouveau commit avec un message par défaut indiquant quel commit est annulé.

  • Annuler un commit spécifique :
    bash git revert <commit-hash>
    Ceci créera un nouveau commit qui annule les changements introduits par <commit-hash>. S'il y a des conflits de fusion, Git fera une pause et vous demandera de les résoudre avant de commiter.

  • Annuler plusieurs commits :
    Vous pouvez annuler une plage de commits :
    bash # Annuler les commits de HEAD~3 jusqu'à (mais sans inclure) HEAD git revert HEAD~3..HEAD
    Git tentera de créer un commit de réversion pour chaque commit spécifié. Si des conflits surviennent pendant le processus, vous devrez les résoudre pour chaque annulation.

Avantages de git revert :

  • Préserve l'historique : Il ne modifie pas les commits existants, ce qui le rend sûr pour les branches publiques ou partagées.
  • Piste d'audit claire : Le commit d'annulation indique explicitement ce qui a été annulé et pourquoi.
  • Gère les fusions avec élégance : Git peut souvent annuler automatiquement les commits de fusion, bien qu'une intervention manuelle puisse être nécessaire pour des scénarios complexes.

Quand utiliser git revert :

  • Lorsque vous devez annuler des changements sur une branche qui a déjà été poussée vers un dépôt distant.
  • Lorsque vous souhaitez conserver un enregistrement clair et immuable de tous les changements, y compris les corrections.
  • Lors de l'annulation d'un commit de fusion.

Choisir la bonne commande

Voici un guide simple pour vous aider à décider :

  • Pour désindexer un fichier : Utilisez git restore <file> ou git reset <file>.
  • Pour rejeter les changements non préparés dans votre répertoire de travail pour un fichier : Utilisez git restore <file>.
  • Pour rejeter tous les changements (préparés et non préparés) pour un fichier : Utilisez git restore --staged --worktree <file>.
  • Pour annuler le dernier commit et garder les changements préparés (pour amender) : Utilisez git reset --soft HEAD^.
  • Pour annuler le dernier commit et garder les changements non préparés : Utilisez git reset HEAD^.
  • Pour rejeter complètement le dernier commit et tous les changements subséquents (destructif) : Utilisez git reset --hard HEAD^.
  • Pour annuler un commit sur une branche partagée sans réécrire l'historique : Utilisez git revert <commit-hash>.
  • Pour rejeter tous les changements locaux dans l'ensemble du dépôt (destructif) : Utilisez git reset --hard.

Conclusion

Maîtriser git reset, git restore et git revert est fondamental pour une utilisation efficace de Git. git restore est votre outil de choix pour rejeter en toute sécurité les changements dans le répertoire de travail et la zone de préparation. git reset offre de puissantes capacités de réécriture de l'historique, à utiliser de préférence sur des commits locaux et non poussés. git revert fournit une méthode sûre, préservant l'historique, pour annuler les changements, ce qui est particulièrement crucial dans les environnements collaboratifs. En comprenant leurs comportements distincts et en choisissant la commande appropriée, vous pouvez gérer l'évolution de votre projet avec confiance et corriger toutes les erreurs en cours de route.