Resetting, checking out & reverting
The git reset, git checkout, and git revert commands are some of the most useful tools in your Git toolbox. They all let you undo some kind of change in your repository, and the first two commands can be used to manipulate either commits or individual files.
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.
It helps to think about each command in terms of their effect on the three state management mechanisms of a Git repository: the working directory, the staged snapshot, and the commit history. These components are sometimes known as "The three trees" of Git. We explore the three trees in depth on the git reset page. Keep these mechanisms in mind as you read through this 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.
Ressource connexe
Comment déplacer un dépôt Git complet
DÉCOUVRIR LA SOLUTION
Découvrir Git avec Bitbucket Cloud
Cet exemple illustre une séquence de commits sur la branche principale (main
). Les réfs HEAD
et de branche (main
) pointent actuellement vers le commit d. Exécutons maintenant git checkout b
.
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.
Git reset vs revert vs checkout reference
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 | Périmètre | Utilisations courantes |
---|---|---|
| Périmètre Niveau commit | Utilisations courantes Discard commits in a private branch or throw away uncommitted changes |
| Périmètre Niveau fichier | Utilisations courantes Annuler le staging d'un fichier |
| Périmètre Niveau commit | Utilisations courantes Basculer entre les branches ou inspecter d'anciens instantanés |
| Périmètre Niveau fichier | Utilisations courantes Annuler des changements dans le répertoire de travail |
| Périmètre Niveau commit | Utilisations courantes Annuler des commits dans une branche publique |
| Périmètre Niveau fichier | Utilisations courantes (N/A) |
Commit level operations
Les paramètres que vous définissez pour git reset
et git checkout
déterminent leur périmètre. 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 a specific commit
À 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 :
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é.
It’s easier to think of these modes as defining the scope of a git reset
operation. For further detailed information visit the git reset page.
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.
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
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é.
Undo public commits with 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 :
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.
File-level operations
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.
Git reset a specific file
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.
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.
Git checkout file
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 la zone de staging. 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.
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, son périmètre est limité 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é.
Résumé
You should now have all the tools you could ever need to undo changes in a Git repository. The git reset, git checkout, and git revert commands can be confusing, but when you think about their effects on the working directory, staged snapshot, and commit history, it should be easier to discern which command fits the development task at hand.
Partager cet article
Thème suivant
Lectures recommandées
Ajoutez ces ressources à vos favoris pour en savoir plus sur les types d'équipes DevOps, ou pour les mises à jour continues de DevOps chez Atlassian.