Git Reset et Reflog

GitBeginner
Pratiquer maintenant

Introduction

Bienvenue, voyageur temporel de Git ! Aujourd'hui, nous allons explorer deux fonctionnalités puissantes de Git qui vous donneront un contrôle sans précédent sur l'historique de votre dépôt : git reset et git reflog. Ces outils sont comme les commandes avancées de votre machine à remonter le temps Git, vous permettant de naviguer entre les différents états de votre projet et même de récupérer du travail que vous pensiez "perdu".

La commande git reset est un outil polyvalent qui peut vous aider à annuler des modifications, retirer des fichiers de la zone de transit (staging area) et même réécrire votre historique de commits. Cependant, un grand pouvoir implique de grandes responsabilités, et git reset peut s'avérer intimidant pour les débutants. C'est là qu'intervient git reflog : c'est votre filet de sécurité. Il garde une trace de tous les changements effectués sur les références de votre dépôt (comme les pointes de branches), vous permettant de vous remettre même des réinitialisations les plus drastiques.

Dans cet atelier, nous aborderons :

  1. Le Soft Reset : Déplacer le HEAD sans modifier le répertoire de travail ni la zone de transit.
  2. Le Mixed Reset : Retirer des modifications de la zone de transit tout en les conservant dans le répertoire de travail.
  3. Le Hard Reset : Supprimer complètement les modifications.
  4. L'utilisation du Reflog pour récupérer des données après des opérations "destructrices".
  5. Les Resets temporels : Ramener votre dépôt à son état exact à un moment précis dans le passé.

À la fin de cet atelier, vous aurez une compréhension solide de la manière d'utiliser ces fonctionnalités puissantes de Git de manière sûre et efficace. Vous serez capable de manipuler l'historique de votre dépôt en toute confiance, sachant que vous pourrez toujours retrouver votre chemin en cas de besoin.

Plongeons dans le vif du sujet et commençons à maîtriser git reset et reflog !

Configuration de votre espace de travail

Avant de commencer à manipuler les commandes de réinitialisation et de journalisation, configurons un espace de travail avec quelques commits pour nos expérimentations. Nous allons créer un nouveau répertoire, initialiser un dépôt Git et ajouter des fichiers avec plusieurs commits successifs.

Ouvrez votre terminal et saisissez les commandes suivantes :

cd ~/project
mkdir git-reset-lab
cd git-reset-lab
git init

Maintenant, créons quelques fichiers et effectuons une série de commits en copiant et collant les commandes suivantes dans votre terminal :

echo "## Git Reset and Reflog Lab" > README.md
git add README.md
git commit -m "Initial commit"

echo "function add(a, b) { return a + b; }" > math.js
git add math.js
git commit -m "Add addition function"

echo "function subtract(a, b) { return a - b; }" >> math.js
git add math.js
git commit -m "Add subtraction function"

echo "function multiply(a, b) { return a * b; }" >> math.js
git add math.js
git commit -m "Add multiplication function"

Analysons ce que nous venons de faire :

  1. Nous avons créé un fichier README et effectué notre premier commit.
  2. Nous avons créé un fichier JavaScript avec une fonction d'addition et l'avons validé.
  3. Nous avons ajouté une fonction de soustraction au même fichier et l'avons validée.
  4. Enfin, nous avons ajouté une fonction de multiplication et l'avons validée.

Nous avons maintenant un dépôt avec un historique suffisant pour commencer nos tests !

Soft Reset : Déplacer le HEAD

Le premier type de réinitialisation que nous allons explorer est le reset "soft" (doux). Un soft reset déplace le HEAD (et la branche courante) vers un commit différent, mais il ne modifie ni la zone de transit ni le répertoire de travail. C'est très utile lorsque vous voulez "annuler" certains commits tout en conservant toutes vos modifications prêtes pour un nouveau commit.

Essayons un soft reset :

git reset --soft HEAD~2

Cette commande fait reculer le HEAD de deux commits (vers le commit précédant "Add subtraction function"). Le symbole ~2 signifie "deux commits avant le HEAD actuel". Vous pouvez utiliser ~N pour remonter de N commits.

Maintenant, si vous lancez git status, vous verrez que les modifications des commits "Add subtraction function" et "Add multiplication function" sont regroupées dans la zone de transit. Les fichiers de votre répertoire de travail n'ont pas bougé. Tout le travail issu de ces deux commits est maintenant prêt à être validé en un seul nouveau commit.

C'est particulièrement utile pour "écraser" (squash) vos derniers commits en un seul. Vous pouvez faire un soft reset pour revenir quelques commits en arrière, puis créer un nouveau commit unique contenant tous ces changements.

Validons à nouveau ces changements avec un nouveau message :

git commit -m "Add subtraction and multiplication functions"

N'oubliez pas que bien que le soft reset soit généralement sûr (car il ne supprime aucune modification), il réécrit l'historique. Si vous avez déjà poussé (push) les commits originaux, vous devrez forcer la mise à jour de la branche distante, ce qui peut poser des problèmes à vos collaborateurs. Communiquez toujours avec votre équipe avant de réécrire un historique partagé !

Mixed Reset : Retirer des modifications de la zone de transit

Le type de réinitialisation suivant est le reset "mixed" (mixte). C'est le mode par défaut de git reset si vous ne précisez aucun drapeau. Un mixed reset déplace le HEAD et met à jour la zone de transit pour qu'elle corresponde, mais il ne touche pas au répertoire de travail.

Ajoutons quelques modifications et préparons-les :

echo "function divide(a, b) { return a / b; }" >> math.js
git add math.js

Supposons maintenant que nous ayons changé d'avis et que nous ne voulions pas encore mettre cette modification en zone de transit. Nous pouvons utiliser un mixed reset :

git reset HEAD

Cela retire nos modifications de l'index (unstage) mais les conserve dans le répertoire de travail. Si vous lancez git status maintenant, vous verrez que math.js est modifié mais n'est plus prêt à être validé.

Le mixed reset est utile lorsque vous avez ajouté des modifications à la zone de transit mais que vous décidez finalement que vous n'êtes pas prêt à les valider. Cela vous permet de revoir les changements ou d'apporter d'autres modifications avant de les indexer à nouveau.

Notez que contrairement au soft reset, le mixed reset modifie la zone de transit. Cependant, il reste sûr car il ne supprime aucun de vos travaux : tout est toujours présent dans votre répertoire de travail.

Hard Reset : Supprimer les modifications

Le troisième type de réinitialisation, le plus radical, est le reset "hard" (dur). Un hard reset déplace le HEAD, met à jour la zone de transit ET met à jour le répertoire de travail pour qu'ils correspondent exactement au commit cible. Cela signifie qu'il supprime toutes les modifications effectuées depuis le commit vers lequel vous revenez.

Essayons un hard reset :

git add math.js
git commit -m "Add division function"
git status
git reset --hard HEAD~1

Ici, nous indexons et validons notre fonction de division, puis nous effectuons un hard reset vers le commit précédent, ce qui "annule" notre dernier commit et supprime purement et simplement les modifications associées.

Si vous regardez le contenu de math.js maintenant, vous verrez que la fonction de division a disparu. C'est comme si nous ne l'avions jamais écrite.

Le hard reset est puissant mais dangereux. Il est utile lorsque vous voulez abandonner complètement un travail en cours pour repartir de zéro à partir d'un commit précédent. Soyez toutefois extrêmement prudent, car il peut supprimer définitivement vos modifications non validées.

Vérifiez toujours deux fois que vous réinitialisez vers le bon commit avant de lancer un hard reset. En cas de doute, préférez un soft ou mixed reset, ou créez une nouvelle branche de sauvegarde avant d'expérimenter.

Utiliser le Reflog pour récupérer des commits perdus

Et si vous réalisiez soudainement que vous n'aviez pas l'intention de supprimer cette fonction de division ? C'est là que git reflog vient à votre rescousse. Le reflog est un journal de tous les emplacements où le HEAD s'est trouvé dans votre dépôt local. C'est une sorte de super-historique qui enregistre même les commandes de réécriture d'historique comme le reset.

Consultons le reflog :

git reflog

Vous devriez voir une liste de toutes vos actions récentes, y compris vos resets. Chaque entrée possède un identifiant de type HEAD@{n}.

Pour récupérer votre commit perdu, vous pouvez réinitialiser l'état vers celui qui précédait votre hard reset :

git reset --hard HEAD@{1}

Cela ramène le HEAD à l'état où il se trouvait juste avant votre dernière action (qui était le hard reset).

Vérifiez math.js maintenant, et vous devriez voir que votre fonction de division est de retour !

cat math.js
function add(a, b) { return a + b; }
function subtract(a, b) { return a - b; }
function multiply(a, b) { return a * b; }
function divide(a, b) { return a / b; }

Le reflog est un filet de sécurité exceptionnel, vous permettant de vous remettre de presque n'importe quelle erreur Git. Cependant, n'oubliez pas qu'il est local à votre machine et temporaire (les entrées sont généralement conservées entre 30 et 90 jours). Ce n'est pas un substitut aux sauvegardes régulières ou au fait de pousser votre travail sur un dépôt distant.

Resets temporels

Git vous permet également de réinitialiser votre dépôt à son état tel qu'il était à un moment précis dans le temps. Cela peut être utile si vous vous souvenez approximativement du moment où votre dépôt était dans l'état souhaité.

Essayons un reset temporel :

git reset --hard master@{"1 hour ago"}

Cela réinitialise votre dépôt à son état d'il y a une heure. Vous pouvez utiliser divers descripteurs temporels comme "yesterday" (hier), "2 days ago" (il y a 2 jours), "3 minutes ago" (il y a 3 minutes), etc.

Soyez prudent avec les resets temporels, car ils peuvent être moins précis que le ciblage d'un commit spécifique. Vérifiez toujours l'état de votre dépôt après une telle opération pour vous assurer d'être arrivé là où vous le souhaitiez.

Rappelez-vous que vous pouvez toujours utiliser le reflog pour annuler un reset temporel s'il ne donne pas le résultat escompté.

Résumé

Félicitations, maître du temps Git ! Vous venez de maîtriser certaines des commandes les plus puissantes et potentiellement dangereuses de Git. Récapitulons les concepts clés abordés :

  1. Soft Reset : Déplace le HEAD sans modifier la zone de transit ni le répertoire de travail. Utile pour fusionner (squash) des commits.
  2. Mixed Reset : Déplace le HEAD et met à jour la zone de transit, mais ne touche pas au répertoire de travail. Idéal pour retirer des fichiers de l'index.
  3. Hard Reset : Déplace le HEAD, met à jour la zone de transit et le répertoire de travail. Puissant mais potentiellement destructeur.
  4. Reflog : Un filet de sécurité qui enregistre tous les changements du HEAD, vous permettant de récupérer de presque n'importe quel accident Git.
  5. Resets temporels : Permettent de réinitialiser votre dépôt à son état à un moment précis.

N'oubliez pas qu'un grand pouvoir implique de grandes responsabilités. Bien que ces commandes vous offrent un contrôle incroyable sur l'historique de votre dépôt, elles peuvent être dangereuses si elles sont utilisées sans précaution. Vérifiez toujours avant d'exécuter un reset, surtout un hard reset, et gardez à l'esprit que le reflog est votre meilleur ami en cas de problème.

Au fil de votre progression avec Git, entraînez-vous à utiliser ces commandes dans un environnement sûr jusqu'à ce que vous soyez parfaitement à l'aise. Ce sont des outils formidables qui amélioreront considérablement votre flux de travail Git lorsqu'ils sont utilisés correctement.

Bonne réinitialisation, et que votre historique Git soit toujours propre et pertinent !