GIT : erreurs fréquentes

Quelques confusions GIT classiques.

Ici et là, GIT est utilisé plus ou moins correctement mais déjà rien qu’à dire cette phrase je me rappelle que mon utilisation quotidienne reste basique. Les commandes avancées ce n’est pas pour tous les jours.

Néanmoins, je les apprends car le jour où j’en ai besoin, et c’est arrivé plusieurs fois, je suis content.

🔗 Préambule

Il y a toute une série sur le blog consacrée à GIT, c’est pas ici c’est à côté :

🔗 Commit vs stash

Avec GIT que ce soit lors d’un commit ou en lançant un git stash il s’agit du local ! C’est pas comme dans SVN où le sens est plutôt d’envoyer les modifications sur le dépôt distant comme on peut le faire pour ceux, par exemple qui publient des plugins WP et qui sont contraints à ce système obsolète encore à l’heure où j’écris.

Avec un git commit on fait un snapshot grosso modo. Le stash aussi est une sorte d’enregistrement mais un de ceux qu’on ne veut pas voir figurer dans l’historique car il n’a aucun intérêt.

Le commit, lui, doit figurer dans l’historique, vous y dites avec un message court et précis ce que vous y avez fait. Le stash lui, c’est enregistrer en local des modifications non terminées. C’est utile en phase de travail. Vous devez passer sur une autre branche rapidement pour faire un travail urgent, vous n’allez pas sauvegarder un code à moitié fini potentiellement bogué. Mais en même temps vous n’allez pas perdre tout ce que vous venez de faire sous prétexte qu’il faut travailler sur autre chose.

Le stash c’est ça au final.

source

🔗 Branches et tags

La confusion la plus fréquente.

🔗 Distinguo

Si on commence par la fin :

  • une branche ça évolue
  • un tag est un jalon dans le temps, il est fixe

J’ai longtemps cherché une manière simple de l’expliquer et la notion de temps me semble la manière la plus pertinente de distinguer qui fait quoi :

  • une branche c’est deux versions du code au même moment
  • un tag c’est une seule version du code à tel moment

🔗 Utilisation

Au final, on utilise souvent les deux conjointement. On créé nos branches qui peuvent représenter la répartition du travail, telle série de tickets ou de tâches tout simplement dans telle branche, et le tag qui marque une release du code.

L’intérêt est que l’on segmente bien tout le travail que l’on va enregistrer au fur et à mesure dans la branche en autant de commits, on aura au passage un historique détaillé de ce qui a été fait. Une fois le code créé, testé, approuvé, on va pouvoir fusionner la branche dans le tronc principal du projet. On l’appelle souvent master. Cela permet de garder du code stable dans cette branche principale du projet et de faire les évolutions dans des branches dédiées.

🔗 La notion de tracking

Très très « confusante » dans GIT car utilisée à toutes les sauces et pour des sauces qui n’ont rien à voir, indigestion !

  • les untracked files listés à la suite d’un git status sont les fichiers qui ne seront pas pris en compte lors du commit éventuel que l’on s’apprête à faire.
  • la remote-tracking-branch c’est comme une copie cache locale de l’état du dépôt distant. C’est l’état depuis les dernières nouvelles. Si on veut s’assurer d’être à jour on lance un git fetch et ce cache local est mis à jour.

🔗 Les arbres

3 arbres au total avec GIT :

  • le working tree (espace de travail)
  • l’index
  • le HEAD

Le fonctionnement de base est le suivant : je travaille dans le working tree, j’indexe les fichiers que j’ai modifiés dans l’index qui est une sorte de zone de passage,

STOP !

L’index, c’est l’indexation des fichiers modifiés dans cette zone et qui s’appellorio index. Pour ça qu’on vous demande un git add.

Ok on peut continuer :

une fois indexées mes modifications peuvent être « committées » et validées et le HEAD pointe vers le dernier commit (celui que j’ai fait après avoir indexé toutes mes modifications).

🔗 La notion de checkout

Le git checkout est le cousin de git clone mais pas son frère jumeau mais alors pas du tout !!!

Updates files in the working tree to match the version in the index or the specified tree. If no paths are given, git checkout will also update HEAD to set the specified branch as the current branch.

Source

J’ai rien compris ! Je me doute qu’il faut bien normaliser dans une documentation mais là c’est quand même abstrait. Mais si on reprend notre point précédent avec les 3 arbres, git checkout fait la navette en quelque sorte.

C’est pour cela qu’on l’utilise pour se placer sur une branche, c’est comme bouger la tête de lecture.

Mais un checkout ce n’est pas un pull ! Ce n’est pas parce que vous lancez un checkout vers une branche que la branche est à jour.

🔗 Encore des branches !

Une source intarissable de conflits GIT est l’erreur de checkout et la création de branches à partir d’autres branches pas encore fusionnées dans la branche principale et parfois même en retard important.

Il faut vraiment éviter ce genre de pratiques. Encore une fois tout est possible si vous maîtrisez mais bien souvent ces situations se présentent à cause d’un mauvais départ.

Alors pour un départ serein et standard, on choisit la branche principale à jour :

git checkout master
git pull
git checkout -b ma-nouvelle-branche

🔗 La notion d’interactive

On peut voir dans la doc l’utilisation des commandes GIT avec l’option -i. L’interactivité c’est mieux, ça donne une vision wink

Comme son nom l’indique, -i vous donnera des informations supplémentaire. N’hésitez pas à le faire, c’est très pratique. Par exemple pour vos tests :

git add -i

C’est un mode puissant donc qui possède son propre menu. Tapez 8 pusi entrée pour avoir le détails de chaque option.

Avant de pousser son travail avec un git push, un :

git rebase -i

est bien utile. Il permet de faire comme si on était un champion tout catégorie, une sorte de petit génie qui fait toujours les bons commits, dans le bon ordre sans se tromper, parfait quoi alors qu’en fait pas du tout comme tout le monde. Vous pouvez réordonner les commits et modifier bien d’autres choses et vous la raconter auprès de vos collègues avec vos historiques nettoyés.

🔗 Pas de zèle avec le clean, pas de zèle tout court !

Restons humbles de grâce, nombreux sont les dévs à vouloir cleaner tout ce qu’ils peuvent que ce soit dans GIT ou ailleurs. Ce n’est pas en soit quelque chose de mauvais mais trop de clean tue le clean !

Le clean reste une opération violente et imparfaite. Vous vous rappelez des arbres dont on a discuté plus haut ? Le clean affecte directement l’environnement de travail, donc sur un site en production les fichiers de la production.

En cas de problème, le clean est la dernière des commandes à rentrer ! Ce n’est pas du tout une solution viable en production. Pour peu que le .gitignore soit mal écrit vous allez potentiellement supprimer des fichiers en masse, à commencer par les uploads.

Si  malgré cela vous voulez quand même vous lancez dans l’aventure clean ajoutez-y au moins le mode interactive, ça marche :

git clean -i

ou mieux encore, avant :

git clean --dry-run

🔗 La transparence vs le reset

Les commandes à base de git reset sont d’une très très grande dangerosité, à manier avec précaution voire à pas manier du tout. Je préfère pour ma part le revert.

Alors attention les commandes reset existent et on n’a parfois pas le choix mais ces situations doivent rester exceptionnelles. Soyez transparents, un reset permet de réécrire l’historique ok, ça peut sembler pratique mais quel intérêt d’avoir un historique si on passe notre temps à le réécrire ?

On n’est pas dans le cas d’un rebase -i ici où on s’occupe de nos propres commits et on nettoie, un reset, en général, on y vient parce que c’est la merde.

De bonnes pratiques de commit et des revert suffiront amplement et permettent de voir tout ce qui s’est passé. On peut aussi faire des revert de revert tongue

🔗 Conclusion

Penser GIT c’est d’abord penser local. Toutes les opérations se passent en local, en tout cas 90% d’entre elles.

La confusion vient souvent du fait que plusieurs commandes, qui n’ont aucun rapport entre elles, peuvent  pourtant servir à faire exactement la même chose mais si on ne sait pas ce que l’on fait on fera plus de mal qu’autre chose au final.

Je vous laisse avec une commande que je ne connaissais pas avant de préparer ce dossier et qui est assez graphique (lighttpd est requis) :

sudo apt-get install lighttpd
cd mon-depot-git
git instaweb

Pour une version navigateur de notre GIT local tongue

🔗 Webographie