Comprendre le processus Git

Traduction libre de votre serviteur de l’article Understanding the Git Workflow par Benjamin Sandofsky

Comprendre le processus Git

Si vous ne comprenez pas ce qui a poussé au design actuel de Git, vous allez souffrir en l’utilisant. Avec toutes ses options, vous arriverez à forcer Git à agir comme vous pensez qu’il doit agir au lieu de le laisser agir comme il le souhaite. C’est comme utiliser un tournevis à la place d’un marteau, vous arriverez au résultat souhaité sauf que cela sera mal fait, ça prendra du temps et ça abîmera le tournevis.

Regardez comment le processus classique de Git peut s’écrouler.

Créer une branche depuis Master, coder, fusionner la branche dans Master quand vous avez fini.

La plupart du temps vous obtiendrez le comportement attendu car Master n’aura pas changé depuis la création de la branche. Plus tard, vous allez fusionner la branche dans Master mais Master n’aura pas divergé. Au lieu de créer un commit de fusion, Git va simplement faire pointer Master sur le dernier commit de la branche (ce qu’on appelle un «fast forward», une avance rapide, cf. ce diagramme).

Malheureusement, votre branche contenait des commits d’étapes, des commits qui permettent de sauvegarder votre progression mais qui fixent un code non stabilisé. Maintenant ces commits sont confondus avec les commits stables de la branche Master. Vous pouvez facilement provoquer une pagaille en revenant en arrière.

Donc vous vous créez une nouvelle règle : «Quand je fusionne une branche, j’utilise l’option –no-ff pour forcer un nouveau commit.». Affaire résolue, on continue.

Et puis un beau jour vous découvrez un bug critique en production et vous avez besoin de revenir en arrière pour trouver quand il a été introduit. Vous utilisez bisect mais vous arrivez toujours sur des commits d’étapes. Vous abandonnez et vous finissez par chercher «à la main».

Vous arrivez à localiser le bug dans un fichier et vous utilisez blame pour voir comment il a évolué dans les dernières 48 heures. Vous savez que c’est impossible pourtant blame vous rapporte que le fichier n’a pas été modifié depuis des semaines. Il se trouve que blame rapporte les changements à la date du commit initial et pas à la fusion. Vos changements ont été fusionnés aujourd’hui mais votre premier commit d’étapes a modifié ce fichier il y a des semaines.

Entre le plâtre no-ff, bisect inutilisable et blame incompréhensible, nous avons tous les symptômes d’un tournevis utilisé comme un marteau.

Repenser le contrôle de révision

Le contrôle des révisions existe pour deux raisons.

La première est d’aider l’acte d’écrire du code. Vous avez besoin de synchroniser des changements avec vos collègues et de régulièrement sauvegarder votre travail. Non, envoyer des zips de vos fichiers ne tient pas la montée en charge.

La seconde est le management de configuration. Cela inclut le management en parallèle de plusieurs axes de développement comme travailler sur la prochaine version majeure tout en appliquant des corrections de bug sur la version existante en production. Le management de configuration est aussi utilisé pour comprendre exactement quand quelque chose a changé, ce qui en fait un outil de débogage qui n’a pas de prix.

Traditionnellement ces deux raisons sont en conflit.

Quand on maquette une fonctionnalité, on fait des commits d’étapes réguliers et souvent ces commits empêchent la compilation. Alors que dans un monde parfait, chaque changement dans votre historique de révision est succinct et stable. Il n’y a pas de bruit créé par des commits d’étapes. Il n’y a pas de commit géant de 10 000 lignes. Un historique propre facilite l’annulation de changement ou l’opération de cherry-pick entre les branches. Un historique propre facilite également l’analyse, l’inspection à posteriori. Cependant, maintenir un historique propre signifie attendre que le code soit parfait avant de l’enregistrer.

Donc quelle approche choisir ? Commit régulier ou historique propre ?

Si vous vous êtes à la veille de lancer votre mini startup, un historique propre ne va pas être un avantage décisif. Vous pouvez commiter à tout va et déployer quand bon vous chante.

Mais en conséquence d’une augmentation du nombre des modifications, que ce soit du à l’élargissement de l’équipe de développement ou à la taille de votre base d’utilisateurs, vous allez avoir besoin d’outils et de techniques pour maintenir les choses sous contrôle. Cela inclut les tests automatiques, les revues de code … et un historique propre.

Les branches de fonctionnalités peuvent sembler une solution équilibrée. Elles résolvent les problèmes de base du développement parallèle. Vous pensez à l’intégration au moment le moins opportun, quand vous écrivez du code, mais ça vous rattrapera. Quand le projet aura assez grossi, le simple processus branche/commit/fusion va s’effondrer. Finis les rafistolages, vous aurez besoin d’un historique de révision propre.

Git est révolutionnaire car il vous donne le meilleur des deux mondes. Vous pouvez maquetter une solution avec des commits réguliers mais également délivrer un historique propre lorsque vous avez fini. Et si c’est bien votre but, les choix par défaut de Git prennent alors tous leurs sens.

Le processus

Penser aux branches en les divisant en deux catégories : publique et privée.

Les branches publiques représentent l’autorité historique du projet. Dans une branche publique, chaque commit doit être succinct, atomique et un message de commit correctement rédigé. Une branche publique doit être la plus linéaire possible et non modifiable. Master et les branches de releases sont des branches publiques.

Une branche privée est personnelle. C’est votre brouillon quand vous travaillez sur un problème.

Il est plus sûr de garder locale une branche privée. Si vous avez besoin de la faire remonter sur dépôt, pour synchroniser vos ordinateurs professionnel et personnel par exemple, prévenez vos collègues que cette branche est privée et qu’ils n’ont pas besoin de travailler dessus.

Vous ne devriez jamais fusionner une branche privée directement dans une branche publique avec un merge de base. Vous devez d’abord nettoyer votre branche avec des outils comme reset, rebase, squash merges, et l’amendement de commit.

Mettez vous dans la peau d’un écrivain et prenez chaque commit comme le chapitre d’un livre. Les écrivains ne publient pas leurs premiers brouillons, Michael Crichton a dit «Les grands livres ne sont pas écris, ils sont réécris.».

Si vous venez d’autres systèmes, modifier l’historique peut vous sembler tabou. Vous avez été conditionnés pour considérer que les commits sont écris dans le marbre mais avec cette logique nous devrions désactiver la fonction «Annuler» dans nos éditeurs de textes.

Les gens pragmatiques prennent soin des changements jusqu’à ce que les changements ne soient que du bruit. Pour la gestion des configurations, nous prenons soin des changements importants. Les commits d’étapes ne sont que des brouillons sauvegardés dans le nuage.

Si vous traitez votre historique public comme une lady, les fusions avec avances rapides sont non seulement plus sûres mais nécessaires. Elles conservent l’historique linéaire et sont simples à suivre.

Le seul argument restant pour –no-ff c’est «la documentation». On peut utiliser les commits de fusion pour représenter la dernière version déployée du code en production. C’est un antipattern, utilisez les tags.

Lignes directrices et exemples

J’utilise trois approches de base en fonction de la taille de mes changements, du temps consacré à ce travail et de l’état de divergence de la branche

Travail à courte durée de vie

Dans la majorité des cas, mon nettoyage consiste seulement à une fusion avec squash.

Imaginons que je crée une branche de fonctionnalité et une série de commits d’étapes pendant la prochaine heure :

git checkout -b branche_privee_fonctionnalite
touch file1.txt
git add file1.txt
git commit -am "WIP"

Quand j’ai fini, au lieu d’un merge de base, j’utilise :

git checkout master
git merge --squash branche_privee_fonctionnalite
git commit -v 

Et je prends une minute pour écrire un message de commit détaillé.

Travail plus conséquent

Parfois une fonctionnalité s’étale sur un projet de plusieurs jours avec des douzaines de petits commits.

Si je décide que ma modification doit être séparée en plusieurs modifications plus petites, squash est un peu trop bourrin (comme métrique, je me demande toujours «Est ce que ce code serait facile à faire valider ?»)

Si mes commits d’étapes suivent une progression logique, j’utilise le mode interactif de rebase. C’est très puissant, vous pouvez l’utiliser pour éditer un vieux commit, les séparés, changer l’ordre et dans ce cas utiliser squash sur quelques uns.

Sur ma branche de fonctionnalité :

git rebase --interactive master

Cela ouvre un éditeur avec une liste des commits. Sur chaque ligne, on retrouve l’opération à effectuer, le SHA1 du commit et le message de commit actuel. Une légende de la liste des commandes possibles est affichée.

Par défaut, chaque commit utilise «pick» qui ne modifie pas le commit.

pick ccd6e62 Travail sur le bouton retour
pick 1c83feb Résolutions de bogues
pick f9d0c33 Début du travail sur la barre d'outils

Je change l’opération en «squash» ce qui va fusionner le deuxième commit dans le premier.

pick ccd6e62 Travail sur le bouton retour
squash 1c83feb Résolutions de bogues
pick f9d0c33 Début du travail sur la barre d'outils

Quand je sauvegarde et ferme l’éditeur, un nouvel éditeur va s’afficher pour écrire le message de commit des commits fusionnés.
Et c’est fini.

Travail sur une branche en faillite

Peut être que ma branche de fonctionnalité existe depuis très longtemps et que j’ai du fusionner plusieurs branches dans ma branche de fonctionnalité pour la garder à jour tout en travaillant dessus. L’historique est en vrille. Le plus simple est de récupérer les différences brutes et de créer une nouvelle branche.

git checkout master
git checkout -b branche_propre
git merge --squash branche_privee_fonctionnalite
git reset

J’ai maintenant un répertoire de travail avec toutes mes modifications sans traîner les valises de ma branche précédente. Je peux alors ajouter manuellement mes modifications et faire mes commits

Résumé

Si vous vous battez avec les choix par défaut de Git, demandez vous “pourquoi ?”.

Traiter l’historique public comme immuable, atomique et facile à suivre. Traiter l’historique privé comme jetable et malléable.

Le processus prévu est :

  1. Créer un branche privée depuis une branche publique.
  2. Commiter régulièrement sur cette branche privée.
  3. Une fois que votre code est parfait, nettoyer son historique.
  4. Fusionner cette branche nettoyée vers la branche publique.

L’auteur remercie particulièrement @joshaber et @jbarnette pour leurs retours sur les premiers brouillons.
Le traducteur remercie Mizu no kokoro pour sa lecture attentive d’un texte “totalement incompréhensible mais tellement poétique, hermétique et ésotérique”.

Appliquer un format de code en masse avec Eclipse

Vous venez de vous mettre d’accord avec tout le monde sur un format de code dérivé de la convention de code Java avec quelques ajustements (taille de ligne à 160, on à des 24 pouces quand même, et “space only” pour les tabulations), maintenant faut appliquer ça partout !

Vous avez également configurer le “Save actions” avec “Format source code”, parfait.
Ou pas.
Si vous attendez de passer dans le code pour reformatter, vous risquez de perdre la prochaine modification dans un énorme commit à cause d’un fichier entièrement reformaté, il faut donc faire un traitement de masse.

Attention à bien choisir le moment car
vous risquez de perdre la comparaison de code pour tout le code précédent !

J’ai trouvé la solution dans http://blogs.operationaldynamics.com/andrew/software/java-gnome/eclipse-code-format-from-command-line et http://www.peterfriese.de/formatting-your-code-using-the-eclipse-code-formatter/ par contre je préfère sauter l’étape d’enregistrer le formatage à un projet et utiliser le formattage affecter au workspace, ma ligne de commande ressemble donc plutôt à ça :

<path-to-eclipse>\eclipse.exe
-nosplash
-verbose
-application org.eclipse.jdt.core.JavaCodeFormatter
-config <path-to-workspace>\.metadata\.plugins\org.eclipse.core.runtime\.settings\org.eclipse.jdt.core.prefs
<path-to-your-source-files>\src\

Script de mise à jour de RetroShare par les sources (svn)

À placer dans un compile_retroshare.sh (par exemple).
Configuration avec RetroShare installé dans «/opt» :

#!/bin/bash
cd /opt/retroshare
svn update
cd /opt/retroshare/libbitdht/src
qmake
make clean
make
cd /opt/retroshare/libretroshare/src
qmake
make clean
make
cd /opt/retroshare/retroshare-gui/src
qmake
make clean
make

Oui, s’il n’y a pas eu de changement, les

make clean

font perdre un peu de temps mais ils m’ont débloqué, surtout pour retroshare-ui, un paquet de fois donc maintenant ils sont permanents.

Source : http://doc.ubuntu-fr.org/retroshare#depuis_la_source

Genesi Efika MX

Genesi Efika MX SmarttopÇa fait plusieurs mois que je réorganise ma présence web, quel service j’utilise ou pas, à qui je donne mes données ou pas et j’ai décidé de rapatrier certaines données @Home comme au bon vieux temps.
Après des tas de lectures, tests, avis, trolls, etc., mon choix s’est porté sur un Genesi Efika MX  Smarttop (ARM et consommation 5W).

Et bien ça y est, je l’ai reçu !
Commandé sur http://www.genesi-europe.com/store/eu/, livraison en une semaine par DHL, la bête vient d’Allemagne.

Headless

Sortie HDMI uniquement. Aïe, j’avais pas vu ce point. Je boot, pas d’accés distant, je branche un écran et … c’était bloqué à l’install d’Ubuntu … Je finis l’installation et ça rame un peu. Allez on vire tout, c’est pour faire un serveur de toute façon. Est ce que je vire la couche X … Est ce que je shoot juste le lancement du service… Je me balade sur le forum officiel : http://www.powerdeveloper.org/forums/ et j’ai trouvé mon bonheur sur http://www.powerdeveloper.org/forums/viewtopic.php?t=1975.

J’ai suivi le README sauf pour la création de la carte SD, j’ai utilisé

xz -dc maverickheadless.img.xz | dd of=/dev/sde

plutôt que

xzcat maverickheadless.img.xz | dd bs=1M of=/dev/sde

Tout se passe comme prévu, réinstall, reboot, etc.

apt-get update
apt-get upgrade
reboot

Et voilà !

SSH

Ajout de la clé avec ssh-copy-id (http://doc.ubuntu-fr.org/ssh#authentification_par_un_systeme_de_cles_publiqueprivee).

On vire l’authentification par mot de passe, on limite les utilisateurs et les tentatives.

SSH ne sera pas accessible de l’extérieur mais retenez toujours : “On ferme tout et on ouvre le strict nécessaire”.

GIT

J’aime bien suivre ce que je modifie donc j’utilise un gestionnaire de source pour suivre tout les changements de /etc. (update : attention à cette opération, cf. le lien d’Etienne Millon dans le premier commentaire)

On installe Git avec

apt-get install git

et on sauvegarde /etc avec

cd /etc
git init
git add *
git -a -m "Add: Import initial."

À chaque modification, upgrade, ne pas oublier de commiter.

Munin

Pour surveiller ce qui se passe un peu sur le serveur, j’adore munin.

apt-get install munin-node smartmontools lm-sensors ethtool

Pour les problèmes de locale, installer le pack fr

apt-get install language-pack-fr

Préciser quel hôte à le droit de consulter les données avec le «allow» de /etc/munin/munin-node.conf

La suite ?

La suite bientôt avec nginx, owncloud, seeks, etc.

Applications Android de gestion de liste de course et d’aide à la consommation

Aide à la consommation, quel titre horrible …

GroceryIQ
https://market.android.com/details?id=com.coupons.GroceryIQ

Site internet, on s’inscrit, on commence à remplir les listes, etc. On télécharge l’appli sur le market pour synchroniser et … et … non. Application réservée aux States …

Bye.

OurGroceries
https://market.android.com/details?id=com.headcode.ourgroceries

Site internet, on s’inscrit, un peu viellot mais on fait ses listes, on synchronise et … Pas de gestion des accents français.

Bye.

Prixing
https://market.android.com/details?id=fr.epicdream.beamy

En français, application propre malgré la publicité qui envahie l’écran mais “c’est le jeu ma pauvre Lucette”. On trouve les prix à proximité, on scan en rafale, on organise ses listes de courses et … ah non, on organise rien, liste dans l’ordre des scans. Pas de possibilité de remanier la liste en fonction de l’ordre des rayons de son magasin ou de ses habitudes de slalom.

Bye … mais je garde installé pour la recherche de prix, etc.

OI Shopping list
https://market.android.com/details?id=org.openintents.shopping

Code libre ! Génial mais … trop limité.

Shopwise
https://market.android.com/details?id=com.shopwise

Qu’est ce qu’il y a dans ce produit ? C’est quoi le E440 ? Toutes les informations sur un produit par recherche ou scan de son code barre.

Pas de gestion de liste mais à garder de coté comme Prixing.

MonCaddy
https://market.android.com/details?id=com.agilys.moncaddy

Scan des codes barres et récupération des images par internet ou perso par l’appareil photo. Liste pré renseignée. Légumes et fruits de saisons !!!

Possibilité de trier les allées (famille de produit mais vous pouvez créer les vôtres en tant qu’allées), enregistrement des magasins, partage de listes, très bon design pour mobile, etc.

Chapeau !

Conclusion

Pour la liste de course : MonCaddy
Informations : Prixing et Shopwise

Des suggestions ?

Ma configuration internet de novembre 2011

Navigateur

Ce qui devait arriver arriva. Après des mois au bureau, c’est désormais le cas également à la maison : Chromium est mon navigateur par défaut. Bizarre.
Une des raisons est l’extension Evernote qui est une catastrophe sous Firefox.

Chromium (non, pas Chrome)

Navigateur complémentaire principal : Chromium.

Je surveille http://build.chromium.org/p/chromium/console puis je télécharge la version qui me semble la plus appropriée sur http://build.chromium.org/f/chromium/snapshots/

Modules complémentaires :

Je cherche toujours une extension pour remplacer gTranslate et Linky.
Contrairement à Firefox, Chromium indique les éléments auxquels l’extension va pouvoir accéder et comme pour Android et le market, je fais de plus en plus attention à ces éléments là donc j’ai trouvé des extensions qui pourraient faire l’affaire mais qui ont des paramètres de sécurité rédhibitoire. Si vous avez des pistes …

Firefox

Navigateur principal complémentaire : Firefox installé avec les .tar.gz dans un répertoire /opt pour ne pas attendre l’empaquetage de ma distribution.

Sans modules complémentaires on a pas un vrai Firefox donc dans l’ordre d’urgence d’installation :

  • NoScript pour bloquer les scripts
  • Adblock Plus pour bloquer les pubs
  • Lazarus pour sauvegarder les formulaires et ne plus perdre vos textes toujours au pire moment (avec un F5 malencontreux par exemple …)
  • gTranslate pour avoir rapidement, sans 15000 options et fenêtres, la traduction d’un mot
  • Linky pour pouvoir faire clic droit, Open Selected Links in tabs
Modules supprimés
  • Fast Dial avec des raccourcis en 10×6. L’auteur met vraiment trop de temps entre les mises à jour Firefox et les mises à jour de son module.
  • FlashGot pour pouvoir faire clic droit, “Télécharger la sélection avec FlashGot”. Plus besoin puisque JDownloader surveille le presse papiers donc à la place je fais juste un Ctrl+C.

Service

Mail

Google Mail car je n’ai plus envie de gérer les filtres anti-spam, les comptes, etc.

TODO

Toodledo car j’ai erré dans la jungle de GTD pendant des années (preuve sur linuxfr.org d’il y a 4 ans, si si 4 ans …) et j’en ai essayé des kilos. J’utilise donc Toodledo comme système et Evernote pour les références (cf. ci dessous).

En complément : Ultimate To-Do List sur mon téléphone avec le widget 1×1 “New Task”.

Notes et marques pages

Evernote avec mes conseils et rêgles.

Bon environnement logiciel : client Android, intégration dans d’autres logiciels, etc. mais :

  • Bizarrerie dans l’interface web :
  • Nécessite le client lourd pour fusionner les notes (fonctionne sous Wine mais un peu lent)
  • Attention, le client lourd libre Nevernote m’a pourri plusieurs notes en s’emmêlant dans l’encodage.

Sinon :

  • Memonic à surveiller de très prés ! Reverse du code, Python, schéma technique cohérent
  • Springpad je connais des inconditionnels mais je ne supporte pas leur interface
  • Suppression de Diigo car trop de problème de mise à jour des tags
  • Peut être une migration vers Semantic Scuttle le jour où les imports fournis fonctionneront mais c’est limité aux marque-pages

Document

Google docs mais je surveille Owncloud.

Pour OwnCloud, je ne l’utilise pas car mon hébergement actuel est un peu trop juste pour la charge et même si les fonctionnalités sont encore un peu limitées on est bien au delà d’un google docs, c’est carrément un espace disque partagé.

Lecteur RSS

RSS Lounge découvert grâce à Dada. Avec ces 2 hacks : 63 et 81 (de moi !), c’est parfait … et rapide !

J’ai eu plusieurs brefs passages par Tiny Tiny RSS mais c’est vraiment trop lent.

Photos

Google Picasa à cause … du client lourd Picasa pour la gestion des visages, le partage gratuit, la synchronisation des répertoires, la gestion des tags et du client Android pour Google+.

J’envisage Piwigo à terme.

Evernote et ma folksonomie pour le marquage par étiquettes (tag)

Utilisation générale

  • Créer deux catégories : Classées et A traiter
  • Dans les propriétés de A traiter, cocher “Définir comme carnet de notes par défaut”
  • Une fois mises en page, taguées, fusionnées, regrouper, etc. les notes passent dans Classées.
  • Ne pas utiliser d’autre catégorie
    • pas de problème de double classement
    • facilité de migration vers un autre service

Étiquette (tag)

  • Affecter au moins un tag par note
  • Raciniser (stemming) au maximum les tags. Ne pas créer de tag unique : «Si je crée ce tag, est ce que je vais m’en servir qu’une ou deux fois ?»
  • Un tag qui commence par @ est un tag de commande :
    • @check it later : à vérifier plus tard (exemple : commentaire sur un blog)
    • @favoris : les notes dont je me sers très souvent
    • @node : annuaire, point de départ sur un sujet (Racine du mot en titre : Python, Agile, etc.)
    • @read it later : à lire plus tard (exemple : un article long, une conférence TED, etc.)
    • @revolving : à vérifier tous les “tant”, souvent 1 fois par semaine (forum, page de websérie, etc.)
    • @running : en cours de traitement
    • @TODO : contient des choses à faire
  • Un tag qui commence par # est un tag de type
    • #carte de visite
    • #dessin
    • #plan
    • #projet
Référence

Récupérer sa «queue de skill» pour EveOnLine sans Evemon ou un autre client

Votre programme préféré n’est pas à jour des nouvelles APIs, vous n’êtes pas sur votre PC habituel, vous aimez le plain text, etc. ?
Voilà comment faire :
Si vous êtes sur un ordinateur de confiance (ou si vous êtes un naturiste virtuel), enregistrer un marque page.
Pour d’autres fonctionnalités : http://wiki.eveonline.com/en/wiki/Category:API