Tag Archives: git

Another Git branching model

We’ve switched to git at work a few month ago. Not an easy task but the rewards are worth the trouble. Our branching model was based on Git Flow because it’s well documented and gives you a structure to start with DVCS. Well, after a few iterations it wasn’t working as expected in our context. So we had to come up with our own workflow.

I guess Git Flow works well on a clean code base with good test coverage. But on legacy code, where one feature means two regressions, a release branch is like the vietnam war, you never know when you will get out of it. That was one of our main problem on subversion, we were creating release branch to go to production. And it would take forever to actually ship the code. Meanwhile all other development efforts remain stuck.

I though that cheap branching and merging in git would solve our issue. But cheap merging is not enough, you also need to be able to easily pick what to merge. And with Git Flow it’s not easy to remove a feature from a release branch once it’s there. Because a feature branch is started from develop it is bound by its parents commits to other features not yet in production. As a result, if you merge a feature without rebasing you always get more commits than wanted.

So here is the workflow we use to solve those issues:

The main branches

We have three branches with an infinite lifetime based on the classical trio (dev/test/prod):

  • master
  • staging
  • develop

Master is the same as in git flow:

We consider origin/master to be the main branch where the source code of HEAD always reflects aproduction-ready state.

Staging is a bit like develop in Git Flow :

We consider origin/develop to be the main branch where the source code of HEAD always reflects a state with the latest delivered development changes for the next release. Some would call this the “integration branch”.

Develop is there for continuous integration, this is where we constanly merge all the changes to detect bugs and conflicts as soon as possible. The source code in the develop branch never reach a stable point where it is ready to be released. Instead only some feature branches reach a stable point. Those stable feature branches are merge into the staging branch. Since feature branches were created from master and not from develop we can pick individualy which one will be merge to staging. In fact this is the main point of this workflow: We can easily choose which features will go into production next. 

To release the code to production we just merge staging into master.

Feature Branches

All work is done in feature branches which can be merge into

  • master for a quick fix in production
  • staging for bug fixes
  • develop constanly for continuous integration

Since we use github we usualy do a pull request to merge feature branches. We don’t always follow the rules and commit on master and staging happens, they are merge back to staging and develop. The only place where we don’t commit is develop ;) (only merge commit)

Summary

Git Flow was not working for us, but by creating feature branches from master instead of develop we gained the ability to easily choose which features we release next. This gave us much more flexibility and got us out of “vietnam release branch”.

Now I should tell about all the best practices to make this workflow really work, but I’m lucky, someone already wrote them down.

And you, what is your branching model ?

De svn à git

Comment migrer un repo svn vers git ? En utilisant svn2git bien sûr!

Mais attention il y a une grosse feinte, le conseil qui suit peut faire gagner des journées entières.

Il y a svn2git et svn2git

Le premier est bien référencé, correctement documenté et facile à mettre en oeuvre. Il fonctionne sur le serveur svn (très lent) ou à distance (très très très lent)

Mais globalement il ne marche pas dès que le repo svn est un peu complexe. (dans mon cas + 13000 révisions et déjà une migration depuis cvs!)

Le second ne sort pas en premier sur google, vous devrez compiler les sources, et la doc est bien cachée (en fait il n’y a que des exemples). Il ne fonctionne que sur le serveur svn.

Mais il est très rapide (moins de 5 min pour mon repo avec 13000 révisions) et  permet simplement de définir des règles pour configurer la conversion des branches et tags. On peut même transformer un repo svn en n repo git en une seule passe.

Voici donc une mini doc pour utiliser le bon svn2git

Installer et compiler (sous ubuntu)

sudo apt-get install libsvn-dev libqt4-dev
git clone git://gitorious.org/svn2git/svn2git.git
cd svn2git
qmake
make

Vous devrier avoir un éxécutable: svn-all-fast-export

Créer un fichier auteurs

Git identifie les utilisateurs par leur email, svn par un identifiant, il faut donc créer un fichier de correspondance entre id svn et email, soit à la main soit de manière automatique

 

#!/usr/bin/env bash
authors=$(svn log -q | grep -e '^r' | awk 'BEGIN { FS = "|" } ; { print $2 }' | sort | uniq)
for author in ${authors}; do
  echo "${author} = NAME ";
done

Créer un fichiers rules

svn2git permet de décrire dans un fichier rules la manière dont on va mapper la structure de répertoire de svn dans des repos et branches git. Pour bien faire les choses il faut connaitre la structure des répertoires svn et leur évolution depuis le début. svneverever vous sera bien utile.

Go

Plus qu’à lancer la commande suivante:
./svn-all-fast-export --identity-map authors  --rules rules --stats pathToYourSvnRepo
En cas d’erreur il est possible de mettre à jour le fichier rules et de repartir de là où on en était.
Bon Git !

Let’s GIT it started

“Pour apprendre  il faut pratiquer, pour comprendre il faut expliquer” ça ne doit pas être la citation exacte mais l’idée est là et s’applique parfaitement à GIT. Il n’y a qu’à voir le nombre de blog de geek qui éprouve l’envie irrésistible de faire un billet sur ce sujet. Je n’échappe pas à la règle, après quelques mois de pratique de ce DVCS.

Même si certain recommande de tout oublier de svn avant de se mettre à git je préfère pour ma part démarrer par une comparaison des concepts

Les concepts de SVN

Un repository svn ne gère que 3 types d’objets:

  • répertoire
  • fichier (ou plutôt la différence d’une version à une autre)
  • revision

Les revisions sont numérotées de 1 à n, elles se suivent de manière linéaire. Chaque révision pointe vers un arbre décrivant l’état du projet. Les branches et les tags n’existent pas dans un repository svn. Ce ne sont que des répertoires désignés comme branche ou tag uniquement PAR CONVENTION.

Voir  bubble up method pour approfondir

Les concepts de GIT

Un repository git gère 4 types d’objets

  • tree (répertoire en svn)
  • blob (fichier en svn)
  • commit (revision en svn)
  • tags

Et en plus des références qui sont utilisées pour désigner les branches On distingue les références des objets car ceux-ci sont immuables alors que les références sont volatiles (i.e.: HEAD est une référence qui peut pointer sur n’importe quel commit alors qu’un objet sera toujours identifié par le hash SHA-1 de son contenu).

Le stockage de cette structure est si bien optimisé que tout l’historique d’un gros et vieux projet ne prend pas plus de place qu’un seul checkout svn.

Mais surtout cet historique n’est pas linéaire comme celui de svn. Les commit sont stockés dans une structure en graphe (un  DAG pour être précis). Un commit peut avoir un ou plusieurs parents (commit avec plusieurs parents == commit de merge). Cette structure en graphe reflète de manière fidèle la notion de branche.

Voir  getting git pour appronfondir

Workflow de SVN

Svn est extrêmement simple, il y a le repository central et des checkouts partiels en local. Les seules commandes à connaitre pour débuter sont les suivantes:

# copier une révision du projet en local
svn checkout http://monprojet/trunk
# génèrer une nouvelle révision sur le serveur dont l'identifiant sera incrémenté de 1 par rapport à la revision précédente
# Par exemple: touch newFile.txt
svn commit
# mettre à jour son projet en local
svn update

La structure et le workflow simplistes de svn font qu’une bonne pratique est d’utiliser le moins de branches possible, tout simplement car les merges sont longs et risqués.

Workflow de GIT

GIT est un DVCS, donc distribué: il peut y avoir plusieurs repository égaux entre eux. Mais de manière pratique on désigne souvent par convention un repository comme central. On a donc

  • un repository central
  • des repositories locaux (contient les mêmes infos que le central)
  • des workspace locaux (contient un checkout d’un commit du repo local)
  • des  index (contient les prochaines modifications à commiter)
  • des  stash

Une utilisation classique de git est donc la suivante

#dupliquer un repository en local
git clone
#Création d'un branche (MonDevAmoi = nom de ma nouvelle branche, créée à partir de la branche nommée BrancheDeReference)
git checkout -b MonDevAmoi BrancheDeReference
#Ajout des modifications dans l'index
git add ...
#commit de l'index dans le repo local
git commit ...
#récupération d'éventuelles modifications sur le repository central
git fetch
#merge de ces modifications avec notre branche
git merge
#Partage des modifications locales avec le repository central
git push

Avantages de git

Après cette présentation on se rend surtout compte que git est plus complexe. Quels avantages apporte cette complexité?

Rapidité

Toutes les opérations se font en local, git est plus rapide de plusieurs ordres de grandeur.

Merges rapide et facile

La structure de données de git a été pensée pour répondre à ce besoin, git est bien plus intelligent que svn sur ce point. Il devient possible de faire des  feature branch et d’envisager des  workflows évolués

Un historique propre

C’est tout de même la fonctionnalité principale d’un système de gestion de code: conserver l’historique. Conserver l’historique c’est bien, avoir un historique propre et utile c’est mieux. Combien de repository svn sont pollués par des commits du type “oups erreur lors du merge” ou “oublié de commiter un fichier” ?

Git ne résout pas ce problème de manière magique mais il donne les outils pour améliorer la situation

  • L’index:

L’index est l’espace où l’on ajoute les modifications que l’on va commiter, il formalise une bonne pratique qui consiste à préparer et valider un commit avant de le faire réellement.

  • La modification d’un commit:

Mais même avec l’index, il reste difficile de faire des commits “parfait”. Un fois un commit créé il est impossible de le modifier (signé avec un SHA-1) par contre il est tout à fait possible de le supprimer pour le remplacer par un autre tant que l’on a pas “pusher” ses commit vers un repo distant. C’est le  git commit amend qui permet de modifier un commit existant.

  • La revision de l’historique:

Et si ce n’est pas suffisant  git squash et rebase permettent de manipuler l’historique lorsque l’on merge des branches.

Par exemple une feature branch qui contient des dizaines de commit peut se transformer en un seul commit lorsqu’on la merge dans la branche principale.

GitHub

Il faut l’essayer pour comprendre. La fonction phare de github est la pull request qui exploite à merveille les capacités de merge de git. La pull request est aussi le moment idéal pour faire un code review.

Inconvénients de git

La courbe d’apprentissage: il faut investir en formation pour bénéficier pleinement de git.

L’outillage, par encore aussi mature que ce qui est disponible pour svn mais ça viendra, pour l’heure la ligne de commande est ton amie.

Git Flow VS pull request

Git permet de mettre en oeuvre de nombreux modèles de développement. Deux en particulier ont émergé:  Git Flow et  github pull request. Le premier est plus orienté workflow d’entreprise aux release régulières mais espacées, le deuxième est adapté aux projets open source, de nombreux contributeurs et un nombre restreint de “committers” qui valident les développements.

Mais rien n’empêche d’utiliser les deux: On peut très bien pusher vers github les features branchs de git flow. Et faire une pull request sur celle-ci pour les merger sur develop.

C’est la grande force de git on peut imaginer et mettre en oeuvre toute sorte de workflow, un autre exemple pour la route.

Pour aller plus loin

 

UPDATE: Think like (a) git est de loin le meilleur tuto sur git

Je maintien une liste de délicieux liens à propos de git mais la meilleure façon de se documenter sur Git est probablement de googler Scott Shacon, employé de github c’est l’évangéliste n°1 de git il a entre autre commis:

Mais si vous en avez assez de la théorie voici pour la pratique

Github, Cloudbees, Feature Flags

Quand les enfants ne sont pas là le geek code ;)

Mettre en oeuvre un processus d’intégration continue peut se faire rapidement, avoir une suite de test unitaire couvrant de manière satisfaisante son code est une autre histoire… Particulièrement sur un “code  legacy” (qui a été écrit sans test unitaire) ,  trop souvent les bugs sont découvert en production par les utilisateurs finaux.  Il faut alors revenir en arrière, reproduire et corriger le bug dans un environnement et re-livrer plus tard, sans parler d’une éventuelle reprise des données qui auraient été corrompues. Oui il y a du vécu.

Une technique pour réduire les effets néfastes d’un bug en production est de déployer progressivement à des populations restreintes les nouveautés. Pour cela il faut séparer la livraison du code de l’activation des fonctionnalités qu’il contient.

Un simple if/else peut suffire, on parle de feature flags chez Flikr.

if (newStuffIsOn) {
	doIt
} else {
	doNot
}
Voilà donc ce que j’ai codé ce week-end… Bon un peu plus en fait. Car il faut un moyen propre et élégant de gérer, d’activer et de désactiver ces flags en production.

Voici donc Feature Flags

L’idée est de gérer les flags dans un enum:
public enum Flags implements FeatureFlags {
    ONE("First Feature Flag"),
    TWO("Second Feature Flag", FlagState.UP),
    THREE("Third Feature Flag");
}
if (ONE.isUp()) {
	doIt
} else {
	doNot
}
Feature Flags génére dynamiquement à partir de l’enum une page html pour activer désactiver ces flags en live, mais aussi une interface RESTful pour les manipuler comme on souhaite.

RESTful

GET http://yourhost.net/flags/ONE pour connaitre l'état
POST http://yourhost.net/flags/ONE pour inverser l'état
PUT http://yourhost.net/flags/ONE avec UP ou DOWN en contenu pour forcer l'état d'un flag
Rien de fantastique que ce soit fonctionnellement ou au niveau du code mais il s’agissait aussi d’un pretexte pour me mettre à git et github

GitHub

Quelle claque. J’ai mis du temps à comprendre pourquoi Linus disait que svn ne marchait pas par conception, après tout ça a marché pour moi pendant des années. Git est clairement le bon concept. La preuve: github, il n’existera jamais de svnhub, avec github nous sommes tous à un click de pouvoir contribuer à des milliers de projets open source. D’ici quelques années github aura produit un impact majeur sur la croissance et la vitalité de l’open source. En fait c’est déjà le cas, mais j’ai la conviction que l’on a encore rien vu. Un peu comme les moteurs de blogs ont déclenché la vague web 2.0 du web participatif. On peut parler d’open source 2.0.

Cloudbees

Deuxième claque. Le projet Feature Flags contient une webapp de démo, le plus simple pour montrer ce que fait Feature Flags est encore une démo (vous allez pouvoir découvrir mes talents de designer web, please fork it ! du html là aussi). Mais héberger un war java sur Internet a toujours été un problème. Les différents clouds publiques apportent des solutions. Avec cloudbees déployer du code java est presque aussi simple qu’uploader une appli php. Il s’est écoulé une petite 1/2heure entre le moment où j’ai décidé de m’inscrire à Cloudbees et le moment où mon application était live, le plus long a été de lire un peu la doc. Petite déception, il n’est pas possible n’était pas possible hier de déployer directement un war généré dans le jenkins de DEV@cloud vers le tomcat RUN@cloud.

Age d’or du développeur

Ajouter à ça le mobile (android), html 5, l’adoption des méthodes agiles, le développement vit un nouvel age d’or.