Reset, checkout et revert | Tutoriels Git d'Atlassian

Reset, checkout et revert

Les commandes git reset, git checkout et git revert comptent parmi les outils les plus utiles de votre boîte à outils Git. Toutes vous permettent d'annuler certains types de changement dans votre dépôt. De plus, vous pouvez utiliser les deux premières pour gérer des commits ou des fichiers individuels.

Comme elles sont très similaires, veillez à ne pas les confondre : à chaque scénario sa commande ! Dans cet article, nous allons comparer les configurations les plus courantes de git reset, git checkout et git revert. Ainsi, vous n'éprouverez aucune difficulté à utiliser ces commandes pour parcourir votre dépôt.

Les trois arborescences de Git

Vous pourrez réfléchir à chaque commande en fonction de l'impact sur les trois mécanismes de gestion des états d'un dépôt Git : le répertoire de travail, l'instantané stagé et l'historique des commits. Ces composants sont parfois appelés « Les trois arborescences » de Git. Nous explorons en détail les trois arborescences sur la page git reset. Gardez ces mécanismes à l'esprit lorsque vous lisez cet article.

Un checkout est une opération qui permet de déplacer le pointeur de réf HEAD vers un commit spécifique. Pour démontrer ce point, prenons l'exemple suivant.

Déplacement du pointeur de réf HEAD vers un commit spécifique

Cet exemple illustre une séquence de commits sur la branche master. Les réfs HEAD et de branche master pointent actuellement vers le commit d. Exécutons maintenant git checkout b.

Séquence de commits sur la branche master

Il s'agit d'une mise à jour de l'arborescence « Historique des commits ». La commande git checkout peut être utilisée dans un commit ou un périmètre de niveau fichier. Un checkout de niveau fichier modifiera le contenu du fichier pour correspondre à celui du commit spécifique.

Un revert est une opération qui prend un commit spécifique et crée un nouveau commit qui inverse le commit spécifique. La commande git revert peut uniquement être exécutée pour un périmètre de niveau commit et ne dispose d'aucune fonctionnalité de niveau fichier.

Un reset est une opération qui prend un commit spécifique et réinitialise les « trois arborescences » de sorte qu'elles correspondent à l'état du dépôt au niveau du commit spécifique. Un reset peut être appelé dans trois modes différents qui correspondent aux trois arborescences.

Le checkout et le reset sont généralement utilisés pour procéder à des « annulations » locales ou privées. Ils modifient l'historique d'un dépôt, ce qui peut entraîner des conflits lors d'un push vers des dépôts partagés distants. Le revert est considéré comme une opération sûre, étant donné qu'il crée un nouvel historique qui peut être partagé à distance et n'écrase pas un historique dont peuvent dépendre les membres de l'équipe à distance.

Référence git reset, git revert et git checkout

Le tableau ci-dessous répertorie les utilisations les plus courantes de toutes ces commandes. Veillez à le conserver pour vous y référer ultérieurement, car vous aurez sans doute besoin d'en utiliser au moins quelques-unes en tant que développeur Git.

Commande Portée Utilisations courantes
git reset Niveau commit Supprime les commits dans une branche privée ou les changements non commités
git reset Niveau fichier Annuler le staging d'un fichier
git checkout Niveau commit Basculer entre les branches ou inspecter d'anciens instantanés
git checkout Niveau fichier Annuler des changements dans le répertoire de travail
git revert Niveau commit Annuler des commits dans une branche publique
git revert Niveau fichier (N/A)

Opérations de niveau commit

Les paramètres que vous définissez pour git reset et git checkout déterminent leur portée. Si vous ne spécifiez pas de chemin d'accès dans vos paramètres, ceux-ci s'appliqueront à tous les commits. Pour plus d'informations sur le sujet, consultez la section ci-dessous. Remarque : git revert n'a pas d'homologue au niveau fichier.

Reset d'un commit spécifique

À l'échelle des commits, la réinitialisation permet de déplacer la pointe d'une branche vers un autre commit. Elle peut également servir à supprimer des commits dans la branche courante. Par exemple, la commande suivante fait reculer la branche hotfix de deux commits.

git checkout hotfix
git reset HEAD~2

Les deux commits situés à la fin de hotfix constituent désormais des commits libres ou orphelins. Cela signifie qu'ils seront supprimés au prochain nettoyage de type garbage collection effectué par Git. En d'autres termes, cette opération revient à supprimer les commits concernés. Elle peut être visualisée comme suit :

Reset de la branche hotfix sur HEAD-2

Cette utilisation de git reset constitue une manière simple d'annuler des changements qui n'ont pas encore été partagés. Cette commande est incontournable lorsque vous commencez à travailler sur une fonctionnalité, puis que tout à coup, vous vous rendez compte que vous vous êtes trompé et que vous voulez tout recommencer.

En plus de déplacer la branche courante, vous pouvez exécuter git reset pour modifier l'instantané stagé et/ou le répertoire de travail en y ajoutant l'un des flags suivants :

  • --soft – L'instantané stagé et le répertoire de travail restent inchangés.
  • --mixed – L'instantané stagé est aligné sur le commit spécifié, tandis que le répertoire de travail reste inchangé. C'est l'option par défaut.
  • --hard : l'instantané stagé et le répertoire de travail sont tous deux alignés sur le commit spécifié.
     

Pour vous aider, considérez ces modes comme une manière de définir le périmètre d'une opération git reset. Pour en savoir plus, consultez la page git reset.

Faire un checkout des anciens commits

La commande git checkout est utilisée pour mettre à jour l'état du dépôt à un point spécifique de l'historique des projets. Une fois la branche nommée, vous pouvez basculer entre les branches.

git checkout hotfix

En interne, la commande ci-dessus a pour seul effet de déplacer HEAD vers une autre branche et de mettre à jour le répertoire de travail. Puisque cette opération est susceptible d'annuler vos changements en local, Git vous oblige à faire un commit ou un stash de tout changement dans le répertoire de travail qui sera perdu lors du checkout. Contrairement à git reset, git checkout ne déplace aucune branche.

Déplacer HEAD de la branche master vers la branche hotfix

Vous pouvez également réaliser un checkout des commits arbitraires en ajoutant la référence du commit plutôt qu'une branche. Cette opération revient à faire un checkout d'une branche : la référence HEAD est déplacée vers le commit spécifié. Par exemple, la commande suivante va extraire le grand-parent du commit courant :

git checkout HEAD~2
Déplacer le HEAD vers un commit arbitraire

Elle peut s'avérer utile pour jeter un coup d'œil rapide à une ancienne version de votre projet. Cependant, puisqu'aucune référence de branche n'est associée au marqueur HEAD courant, vous passez à l'état HEAD détaché. Attention : si vous commencez à ajouter de nouveaux commits, il vous sera impossible de les récupérer une fois que vous aurez basculé sur une autre branche. C'est la raison pour laquelle vous devez toujours créer une nouvelle branche avant d'ajouter des commits à un HEAD détaché.

Annuler les commits publics avec git revert

L'opération revert annule un commit en créant un nouveau commit. C'est une méthode sûre pour annuler des changements, car elle ne risque pas de réécrire l'historique du commit. Par exemple, la commande suivante détermine les changements contenus dans les commits (du 2e au dernier), crée un nouveau commit qui annule ces changements et ajoute le nouveau commit au projet existant.

git checkout hotfix
git revert HEAD~2

Elle peut être visualisée comme suit :

Faire un revert des commits (du 2e au dernier)

Veillez à ne pas confondre cette commande avec git reset, qui modifie l'historique des commits existant. Par conséquent, utilisez git revert pour annuler des changements apportés à une branche publique, et git reset pour faire de même, mais sur une branche privée.

Gardez à l'esprit que git revert sert à annuler des changements commités, tandis que git reset HEAD permet d'annuler des changements non commités.

À l'instar de git checkout, git revert est susceptible d'écraser des fichiers dans le répertoire de travail et vous demandera donc de faire un commit ou un stash des changements qui risqueraient d'être perdus pendant le revert.

Opérations de niveau fichier

Les commandes git reset et git checkout permettent aussi d'utiliser un chemin d'accès optionnel en guise de paramètre. Leur comportement s'en trouve fortement modifié. Au lieu d'opérer sur des instantanés entiers, elles se limitent à un seul fichier.

Commande git reset sur un fichier spécifique

Associée à un chemin d'accès, la commande git reset met à jour l'instantané stagé staged snapshot pour l'aligner sur la version issue du commit spécifié. Par exemple, elle récupère la version de foo.py dans l'avant-dernier commit et l'indexe pour le prochain commit :

git reset HEAD~2 foo.py

Tout comme la version de git reset de niveau commit, elle est plus souvent utilisée avec HEAD plutôt qu'avec un commit arbitraire. L'exécution de git reset HEAD foo.py annulera foo.py. Les changements qu'il contient seront toujours apparents dans le répertoire de travail.

Transférer un fichier de l'historique des commits vers l'instantané stagé

Les flags --soft, --mixed et --hard n'ont aucun effet sur la version de git reset de niveau fichier, puisque l'instantané stagé est continuellement mis à jour, tandis que le répertoire de travail ne l'est jamais.

Checkout de fichier dans Git

L'extraction de fichiers s'apparente à l'utilisation de git reset associée à un chemin d'accès, à cela près que c'est le répertoire de travail qui est mis à jour, et non l'index. Contrairement à la version de cette commande de niveau commit, la référence HEAD n'est pas déplacée, donc vous ne basculez pas entre les branches.

Transférer un fichier de l'historique des commits vers le répertoire de travail

Par exemple, la commande suivante aligne le fichier foo.py du répertoire de travail sur celui de l'avant-dernier commit :

git checkout HEAD~2 foo.py

Tout comme la version de git checkout de niveau commit, cette commande peut être utilisée pour examiner les anciennes versions d'un projet. Cependant, sa portée est limitée au fichier spécifié.

Si vous indexez et commitez le fichier extrait, il sera remplacé par son ancienne version. Remarque : cette opération supprime tous les changements ultérieurs apportés au fichier, alors que la commande git revert annule uniquement les changements apportés par le commit spécifié.

À l'instar de git reset, cette commande est souvent utilisée avec HEAD en guise de référence de commit. Par exemple, git checkout HEAD foo.py a pour effet d'ignorer les changements non stagés apportés à foo.py. Le résultat est le même que pour git reset HEAD --hard à cela près que seul le fichier spécifié est concerné.

Summary

À présent, vous avez toutes les clés pour annuler des changements dans un dépôt Git. Les commandes git reset, git checkout et git revert peuvent prêter à confusion, mais si vous pensez à leurs effets sur le répertoire de travail, l'instantané stagé et l'historique des commits, vous n'aurez aucun mal à utiliser la bonne commande pour votre tâche en cours.