git reflog, ou comment toujours retomber sur ses pieds

Vous êtes un grand fan de git ? Vous adorez tester des  fonctionnalités comme le rebase, cherry-pick, et autre reset –hard unhashdecommit qui passent pour être dangereuses (puisqu’elle réécrivent l’arbre des commits) ? Bien entendu, tout cela est fait dans un contexte professionnel, la veille d’une release, et pas de droit à l’erreur. Saviez-vous qu’avec reflog, c’est possible, et sans stress ?

Tout d’abord, une explication s’impose. “git  reflog –help” est assez sibyllin (qui a dit comme d’habitude ?) : “git-reflog – Manage reflog information”. Un peu plus loin dans le man, on trouve une explication plus détaillée :

Reflog is a mechanism to record when the tip of branches are updated. This command is to manage the information recorded in
it.

Pour paraphraser le man, reflog enregistre tous les changements qui sont faits lorsque l’on modifie une branche afin de lui faire référencer un autre commit.

Je vais utiliser pour exemple un repo github bien connu des lecteurs du lab :

1
git clone git://github.com/excilys/flash-scope.git

Si on lance git reflog juste après le clone, il n’y a qu’une seule ligne dans la sortie, à savoir le clone. Il est maintenant temps de générer du chaos.

1
2
3
4
5
git checkout -b chaos ca6d54199c22a283fa799d5841cf41ace1ce418b
touch pouet.txt && git add pouet.txt
git commit -am "Pouet commit"
git checkout master
git reset --hard a52162509365f394eeb9221317497efc2993ffdf

Arbre des commits après le git reset

À ce stade, j’ai créé une branche chaos, qui contient mon travail, j’ai remis master avant le merge de la branche fluid-api avec master.

Continuons notre réécriture de commit en simulant le fait que Stéphane ait fait un git rebase fluid-api au lieu de git merge fluid-api :

1
2
git checkout chaos
git rebase master

Observons maintenant le git reflog (l’arbre des commits est ici):reflog

Le premier commit que j’ai fait est référencé par :

f80a1b1 HEAD@{7}: commit: Pouet commit

Ensuite, on retrouve les opérations que j’ai faites, qui sont essentiellement des changements de branches et un rebase (qui se décompose en plusieurs lignes de reflog).

Je vais simuler un git pull–rebase origin/master (avec un git rebase origin/master) et ainsi rencontrer un problème de merge :

CONFLICT (content): Merge conflict in src/main/java/com/excilys/utils/web/flash/FlashScope.java
Failed to merge in the changes.
Patch failed at 0001 Implemented the Fluid API FlashScopeHandler.bind(name).to(value);

Le stress aidant, je décide d’arrêter tout. Que faire ? Je ne veux pas perdre mon commit, et plutot que de faire un git rebase où je ne suis pas à l’aise, je préfère effectuer un git merge (qui, dans certains cas, se débrouille mieux, mais c’est un autre sujet !). Essayons donc de faire un git reset –hard f80a1b1.

Comme prévu, l’arbre des commits a été réécrit et est exactement le même que celui du début de l’article. C’est à ce moment qu’on dit “Merci git !”

PS : Bien entendu, ces manipulations ne sont à faire que sur des commits ! Un git reset –hard appliqué sur des fichiers non commités est rédibitoire !

VN:R_U [1.9.22_1171]
Rating: 0 (from 0 votes)
Share
Ce contenu a été publié dans Outils, Trucs & astuces, avec comme mot(s)-clef(s) . Vous pouvez le mettre en favoris avec ce permalien.

6 réponses à git reflog, ou comment toujours retomber sur ses pieds

  1. mgrenonville@excilys.com dit :

    PS 2 : J’ai oublié de préciser que git reflog permet aussi d’annuler un pull, un merge, etc… Il permet aussi de récupérer des commits qui ne seraient plus référencés sur aucune branche en faisant des cherry-pick des hashs de reflog.

    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
  2. Sympa l’article, même si j’ai vite été largué et que j’ai du m’y reprendre à plusieurs fois pour bien comprendre ce qu’il se passe.

    Hier, au Paris jug, Sébastien Douche nous a montré deux commandes sympa : “git add -p”, qui permet de choisir chaque élément de diff (les +++/—) à inclure ou non dans le commit, et “git rebase -i”, qui permet de réécrire l’historique de manière intéractive (supprimer / modifier / réordonner les commits facilement).

    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
  3. mgrenonville@excilys.com dit :

    Il est difficile de créer un repository de SCM compliqué et qui reproduit des cas de la vraie vie. Mon but était seulement de provoquer des actions peu orthodoxes sur le repo et de montrer qu’avec reflog, on peut revenir à l’état initial. Une manière de répondre aux gens qui se plaignent de git car “on fait toujours plein de merge”. “Oui, mais tes merges, tu les aurais eu avec SVN et ca t’est surement arrivé de faire un svn up, d’avoir 10 conflits et de pas pouvoir revenir en arrière” (chose que git permet via le reflog)

    Effectivement, “git rebase -i” est une de mes actions préférées. Masquer les micro-commits, les itérations avant d’obtenir quelque chose de stable, comme dirait Linus : “Don’t expose your crap.”

    “git add -p”, pourquoi pas, mais je prefère le faire avec un utilitaire comme gitg (qui m’a servi à faire les captures d’écran) et qui propose aussi l’ajout interactif de portions de fichier.

    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
  4. Très intéressant le post de linus, merci :-)

    Et gitx, tu as testé ?

    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
    • mgrenonville@excilys.com dit :

      Gitx, c’est comme gitg, mais pour mac. Je n’ai pas vu de différence en bien ou en mal (mais mon dernier test poussé remonte à 1 an…). Visualisation des commits, diff, commit interactif.

      En revanche, pour les cherry-pick, gitk est le meilleur. Et pour les merges, intellij se débrouille mieux que tous les autres.

      Mais la ligne de commande git reste l’outil le plus puissant :

      1
      git log --graph --pretty="format:%C(yellow bold)%h%Creset by %C(red)%an%Creset (%ar)%C(cyan bold)%d%Creset%n%s%n%b" --all

      \o/

      VN:R_U [1.9.22_1171]
      Rating: 0 (from 0 votes)
  5. Ping : Les liens du vendredi » Team Fusion

Laisser un commentaire