Git Reset vs Revert vs Rebase
Publié: 2021-05-20Dans cet article, vous découvrirez différentes manières de jouer avec les commits dans Git.
En tant que développeur, vous auriez rencontré plusieurs fois de telles situations où vous auriez voulu revenir à l'un de vos commits précédents, mais vous ne savez pas comment le faire. Et même si vous connaissez les commandes Git telles que reset, revert, rebase, vous n'êtes pas au courant des différences entre elles. Alors commençons et comprenons ce que sont git reset, revert et rebase.
Réinitialiser Git
Git reset est une commande complexe, et elle est utilisée pour annuler les modifications.
Vous pouvez considérer git reset comme une fonctionnalité de restauration. Avec git reset, vous pouvez passer d'un commit à l'autre. Il existe trois modes d'exécution d'une commande git reset : –soft, –mixed et –hard. Par défaut, la commande git reset utilise le mode mixte. Dans un workflow de réinitialisation de git, trois mécanismes de gestion internes de git entrent en jeu : HEAD , zone de transit (index) et le répertoire de travail .

Le répertoire de travail est l'endroit où vous travaillez actuellement, c'est l'endroit où vos fichiers sont présents. En utilisant une commande git status, vous pouvez voir quels sont tous les fichiers/dossiers présents dans le répertoire de travail.
La zone de transit (Index) est l'endroit où git suit et enregistre toutes les modifications apportées aux fichiers. Les modifications enregistrées sont reflétées dans le répertoire .git. Vous utilisez git add "filename" pour ajouter le fichier à la zone de transit. Et comme avant, lorsque vous exécutez git status, vous verrez quels fichiers sont présents dans la zone de transit.
La branche actuelle de Git est appelée HEAD. Il pointe vers le dernier commit, qui s'est produit dans la branche de paiement actuelle. Il est traité comme un pointeur pour toute référence. Une fois que vous passez à la caisse dans une autre succursale, le HEAD se déplace également vers la nouvelle succursale.
Laissez-moi vous expliquer comment git reset fonctionne en modes dur, doux et mixte. Le mode difficile est utilisé pour accéder au commit pointé, le répertoire de travail est rempli avec les fichiers de ce commit et la zone de transit est réinitialisée. Dans la réinitialisation logicielle, seul le pointeur est remplacé par le commit spécifié. Les fichiers de tous les commits restent dans le répertoire de travail et la zone de transit avant la réinitialisation. En mode mixte (par défaut), le pointeur et la zone de transit sont tous deux réinitialisés.
Git Reset Hard
Le but de git hard reset est de déplacer le HEAD vers le commit spécifié. Il supprimera tous les commits survenus après le commit spécifié. Cette commande modifiera l'historique des commits et pointera vers le commit spécifié.
Dans cet exemple, je vais ajouter trois nouveaux fichiers, les valider, puis effectuer une réinitialisation matérielle.
Comme vous pouvez le voir dans la commande ci-dessous, pour le moment, il n'y a rien à valider.
$ git status On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) nothing to commit, working tree cleanMaintenant, je vais créer 3 fichiers et y ajouter du contenu.
$ vi file1.txt $ vi file2.txt $ vi file3.txtAjoutez ces fichiers au référentiel existant.
$ git add file*Lorsque vous réexécutez la commande status, elle reflétera les nouveaux fichiers que je viens de créer.
$ git status On branch master Your branch is ahead of 'origin/master' by 2 commits. (use "git push" to publish your local commits) Changes to be committed: (use "git restore --staged <file>..." to unstage) new file: file1.txt new file: file2.txt new file: file3.txtAvant de commettre, laissez-moi vous montrer, j'ai actuellement un journal de 3 commits dans Git.
$ git log --oneline 0db602e (HEAD -> master) one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) testMaintenant, je vais m'engager dans le référentiel.
$ git commit -m 'added 3 files' [master d69950b] added 3 files 3 files changed, 3 insertions(+) create mode 100644 file1.txt create mode 100644 file2.txt create mode 100644 file3.txtSi je fais ls-files, vous verrez que les nouveaux fichiers ont été ajoutés.
$ git ls-files demo dummyfile newfile file1.txt file2.txt file3.txtLorsque j'exécute la commande log dans git, j'ai 4 commits et HEAD pointe vers le dernier commit.
$ git log --oneline d69950b (HEAD -> master) added 3 files 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) testSi je supprime le fichier1.txt manuellement et que je fais un état git, cela affichera le message que les modifications ne sont pas mises en scène pour la validation.
$ git status On branch master Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits) Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) deleted: file1.txt no changes added to commit (use "git add" and/or "git commit -a")Maintenant, je vais exécuter la commande de réinitialisation matérielle.
$ git reset --hard HEAD is now at d69950b added 3 filesSi je revérifie l'état, je constaterai qu'il n'y a rien à valider et le fichier que j'ai supprimé est revenu dans le référentiel. La restauration s'est produite car après la suppression du fichier, je ne me suis pas engagé, donc après une réinitialisation matérielle, il est revenu à l'état précédent.
$ git status On branch master Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits) nothing to commit, working tree cleanSi je vérifie le journal de git, voici à quoi cela ressemblera.
$ git log commit d69950b7ea406a97499e07f9b28082db9db0b387 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 19:53:31 2020 +0530 added 3 files commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 testLe but de la réinitialisation matérielle est de pointer vers le commit spécifié et de mettre à jour le répertoire de travail et la zone de transit. Laissez-moi vous montrer un autre exemple. Actuellement, la visualisation de mes commits ressemble à ci-dessous :

Ici, je vais exécuter la commande avec HEAD^, ce qui signifie que je veux réinitialiser le commit précédent (un commit en arrière).
$ git reset --hard HEAD^ HEAD is now at 0db602e one more commitVous pouvez voir que le pointeur principal a maintenant changé en 0db602e à partir de d69950b.
$ git log --oneline 0db602e (HEAD -> master) one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test 
Si vous vérifiez le journal, le commit de d69950b a disparu et la tête pointe maintenant vers 0db602e SHA.
$ git log commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 TestSi vous exécutez les fichiers ls, vous pouvez voir que file1.txt, file2.txt et files3.txt ne sont plus dans le référentiel car cette validation et son fichier ont été supprimés après la réinitialisation matérielle.
$ git ls-files demo dummyfile newfileRéinitialisation logicielle Git
De même, je vais maintenant vous montrer un exemple de réinitialisation logicielle. Considérez, j'ai ajouté à nouveau les 3 fichiers comme mentionné ci-dessus et je les ai validés. Le journal git apparaîtra comme indiqué ci-dessous. Vous pouvez voir que 'soft reset' est mon dernier commit, et HEAD le souligne également.
$ git log --oneline aa40085 (HEAD -> master) soft reset 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) testLes détails de la validation dans le journal peuvent être consultés à l'aide de la commande ci-dessous.
$ git log commit aa400858aab3927e79116941c715749780a59fc9 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 21:01:36 2020 +0530 soft reset commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 testMaintenant, en utilisant la réinitialisation logicielle, je souhaite passer à l'un des anciens commits avec SHA 0db602e085a4d59cfa9393abac41ff5fd7afcb14
Pour ce faire, je vais exécuter la commande ci-dessous. Vous devez transmettre plus de 6 caractères de départ de SHA, le SHA complet n'est pas requis.

$ git reset --soft 0db602e085a4Maintenant, lorsque je lance le journal git, je peux voir que HEAD a été réinitialisé au commit que j'ai spécifié.
$ git log commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 (HEAD -> master) Author: mrgeek <[email protected]> Date: Mon May 17 01:04:13 2020 +0530 one more commit commit 59c86c96a82589bad5ecba7668ad38aa684ab323 Author: mrgeek <[email protected]> Date: Mon May 17 00:54:53 2020 +0530 new commit commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD) Author: mrgeek <[email protected]> Date: Mon May 17 00:16:33 2020 +0530 testMais la différence ici est que les fichiers du commit (aa400858aab3927e79116941c715749780a59fc9) où j'avais ajouté 3 fichiers sont toujours dans mon répertoire de travail. Ils n'ont pas été supprimés. C'est pourquoi vous devez utiliser une réinitialisation logicielle plutôt qu'une réinitialisation matérielle. Il n'y a aucun risque de perdre les fichiers en mode logiciel.
$ git ls-files demo dummyfile file1.txt file2.txt file3.txt newfileGit Revenir
Dans Git, la commande revert est utilisée pour effectuer une opération de restauration, c'est-à-dire pour annuler certaines modifications. Elle est similaire à la commande reset, mais la seule différence ici est que vous effectuez un nouveau commit pour revenir à un commit particulier. En bref, il est juste de dire que la commande git revert est un commit.
La commande Git revert ne supprime aucune donnée lors de l'exécution de l'opération de restauration.
Disons que j'ajoute 3 fichiers et que j'effectue une opération de validation git pour l'exemple de retour.
$ git commit -m 'add 3 files again' [master 812335d] add 3 files again 3 files changed, 3 insertions(+) create mode 100644 file1.txt create mode 100644 file2.txt create mode 100644 file3.txtLe journal affichera le nouveau commit.
$ git log --oneline 812335d (HEAD -> master) add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) testMaintenant, je voudrais revenir à l'un de mes commits passés, disons - "59c86c9 new commit". Je lancerais la commande ci-dessous.
$ git revert 59c86c9Cela ouvrira un fichier, vous trouverez les détails du commit auquel vous essayez de revenir, et vous pouvez donner un nom à votre nouveau commit ici, puis enregistrer et fermer le fichier.
Revert "new commit" This reverts commit 59c86c96a82589bad5ecba7668ad38aa684ab323. # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # # On branch master # Your branch is ahead of 'origin/master' by 4 commits. # (use "git push" to publish your local commits) # # Changes to be committed: # modified: dummyfileAprès avoir enregistré et fermé le fichier, voici la sortie que vous obtiendrez.
$ git revert 59c86c9 [master af72b7a] Revert "new commit" 1 file changed, 1 insertion(+), 1 deletion(-)Maintenant, pour apporter les modifications nécessaires, contrairement à reset, revert a effectué un nouveau commit de plus. Si vous vérifiez à nouveau le journal, vous trouverez un nouveau commit en raison de l'opération de restauration.
$ git log --oneline af72b7a (HEAD -> master) Revert "new commit" 812335d add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) test 
Git log aura tout l'historique des commits. Si vous souhaitez supprimer les commits de l'historique, alors revert n'est pas un bon choix, mais si vous souhaitez conserver les modifications de commit dans l'historique, alors revert est la commande appropriée au lieu de reset.
Git Rebase
Dans Git, rebase est le moyen de déplacer ou de combiner les commits d'une branche sur une autre branche. En tant que développeur, je ne créerais pas mes fonctionnalités sur la branche principale dans un scénario réel. Je travaillerais sur ma propre branche (une 'branche de fonctionnalité'), et quand j'ai quelques commits dans ma branche de fonctionnalité avec la fonctionnalité ajoutée, je voudrais alors la déplacer vers la branche principale.
Rebase peut parfois être un peu déroutant à comprendre car il est très similaire à une fusion. Le but de la fusion et du rebasage des deux est de prendre les commits de ma branche de fonctionnalité et de les mettre sur une branche master ou toute autre branche. Considérez, j'ai un graphique qui ressemble à ceci:

Supposons que vous travaillez en équipe avec d'autres développeurs. Dans ce cas, vous pouvez imaginer que cela pourrait devenir très complexe lorsque vous avez un groupe d'autres développeurs travaillant sur différentes branches de fonctionnalités et qu'ils ont fusionné plusieurs modifications. Il devient déroutant de tracer.
Donc, c'est là que rebase va aider. Cette fois, au lieu de faire une fusion git, je ferai un rebase, où je veux prendre mes deux commits de branche de fonctionnalité et les déplacer sur la branche master. Un rebase prendra tous mes commits de la branche de fonctionnalité et les déplacera au-dessus des commits de la branche principale. Donc, dans les coulisses, git duplique les commits de la branche de fonctionnalité sur la branche master.

Cette approche vous donnera un graphique linéaire clair avec tous les commits d'affilée.

Cela permet de retracer facilement les commits qui sont allés où. Vous pouvez imaginer que si vous faites partie d'une équipe avec de nombreux développeurs, tous les commits sont toujours consécutifs. Il est donc très facile à suivre même si plusieurs personnes travaillent sur le même projet en même temps.
Laissez-moi vous montrer cela pratiquement.
Voici à quoi ressemble ma branche master actuellement. Il a 4 commits.
$ git log --oneline 812335d (HEAD -> master) add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) testJe vais exécuter la commande ci-dessous pour créer et basculer vers une nouvelle branche appelée fonctionnalité, et cette branche sera créée à partir du 2ème commit, c'est-à-dire 59c86c9
(master) $ git checkout -b feature 59c86c9 Switched to a new branch 'feature'Si vous vérifiez le journal dans la branche de fonctionnalité, il n'a que 2 commits provenant du maître (mainline).
(feature) $ git log --oneline 59c86c9 (HEAD -> feature) new commit e2f44fc (origin/master, origin/HEAD) testJe vais créer la fonctionnalité 1 et la valider dans la branche de fonctionnalité.
(feature) $ vi feature1.txt (feature) $ git add . The file will have its original line endings in your working directory (feature) $ git commit -m 'feature 1' [feature c639e1b] feature 1 1 file changed, 1 insertion(+) create mode 100644 feature1.txtJe vais créer une fonctionnalité supplémentaire, c'est-à-dire la fonctionnalité 2, dans la branche de fonctionnalité et la valider.
(feature) $ vi feature2.txt (feature) $ git add . The file will have its original line endings in your working directory (feature) $ git commit -m 'feature 2' [feature 0f4db49] feature 2 1 file changed, 1 insertion(+) create mode 100644 feature2.txtMaintenant, si vous vérifiez le journal de la branche de fonctionnalité, il contient deux nouveaux commits, que j'ai exécutés ci-dessus.
(feature) $ git log --oneline 0f4db49 (HEAD -> feature) feature 2 c639e1b feature 1 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) testMaintenant, je veux ajouter ces deux nouvelles fonctionnalités à la branche master. Pour cela, j'utiliserai la commande rebase. À partir de la branche de fonctionnalité, je rebaserai sur la branche principale. Cela va ré-ancrer ma branche de fonctionnalité contre les dernières modifications.
(feature) $ git rebase master Successfully rebased and updated refs/heads/feature.Maintenant, je vais aller de l'avant et vérifier la branche master.
(feature) $ git checkout master Switched to branch 'master' Your branch is ahead of 'origin/master' by 3 commits. (use "git push" to publish your local commits)Et enfin, rebasez la branche master par rapport à ma branche feature. Cela prendra ces deux nouveaux commits sur ma branche de fonctionnalité et les rejouera au-dessus de ma branche master.
(master) $ git rebase feature Successfully rebased and updated refs/heads/master.Maintenant, si je vérifie le journal sur la branche master, je peux voir que les deux commits de ma branche features ont été ajoutés avec succès à ma branche master.
(master) $ git log --oneline 766c996 (HEAD -> master, feature) feature 2 c036a11 feature 1 812335d add 3 files again 0db602e one more commit 59c86c9 new commit e2f44fc (origin/master, origin/HEAD) testTout cela concernait les commandes de réinitialisation, de restauration et de rebase dans Git.
Conclusion
Tout cela concernait les commandes de réinitialisation, de restauration et de rebase dans Git. J'espère que ce guide étape par étape a été utile. Maintenant, vous savez comment jouer avec vos commits selon les besoins en utilisant les commandes mentionnées dans l'article.
