GIT

Pourquoi vous ne devriez pas utiliser la Fork Queue de GitHub

GitHub propose une fonctionnalité qui peut sembler magique : la fork queue. Cette fonctionnalité est en soi assez simple à expliquer : elle affiche à l'écran tous les commits faits dans des forks de votre projet et vous permet, en quelques clics, d'appliquer ceux-ci à votre version du projet. Vu comme cela, c'est assez sympa. En pratique, je vous déconseille de l'utiliser. Nous allons voir pourquoi et comment faire sans.

Pourquoi ne dois-je pas utiliser la fork queue ?

La fonctionnalité de la fork queue est similaire à ce que vous pourriez faire manuellement avec git (et que nous détaillons plus bas). Elle prends les commits que vous cochez, en fait un [patch]/patch et commit celui-ci dans votre repository. C'est une fonctionnalité de GIT largement utilisée. C'est ainsi que vous serez ainsi invité à faire si vous soumettez un patch à rails.

Ici cependant, un petit problème se pose : vous pouvez visualiser le contenu du commit. Mais pas le tester. Dès que vous cochez et acceptez ce commit, celui-ci est validé dans votre repository distant et accessible à toute personne ayant accès au projet. En conséquent, si ce commit semble en apparence correct mais qu'il casse une autre fonctionnalité et que vous n'avez pas constaté cela au premier coup d'oeil, vous ne vous en rendrez compte que lorsque vous récupérerez à nouveau le contenu de votre projet et que vous exécuterez ses tests. Et si vous avez accepté plusieurs commits, vous risquez d'avoir beaucoup de mal à trouver lequel a implémenté ce bug et à le corriger.

Le fait qu'un commit passe correctement, c'est à dire qu'il ne crée pas de conflit lors de son merge ne signifie pas qu'il ne casse pas de fonctionnalité par ailleurs.

Oui mais je fais comment à la place ?

Grande question ! :) Tout d'abord vous devez vous imaginer que chaque repository GIT distant est en fait une branche différente. Lorsque vous faites un fetch, vous récupérez le contenu de cette branche.

Supposons que un utilisateur "joe" ait forké mon projet open source jack. Joe a donc son fork situé sur github à joe/jack. Il fait quelques commits puis pousse les modifications effectuées. Pour ma part, je veux placer ces modifications dans le repository principal.

git clone git@github.com:dmathieu/jack.git

Je commence par cloner le repository. A supposer que je ne l'ai pas encore ne local.

git remote add joe git://github.com/joe/jack.git

Ensuite je dois ajouter un nouveau repository distant, que je vais nommer joe. Je pourrai ainsi récupérer les derniers commits effectuée.

git fetch joe master:joe

Maintenant je récupère les commits effectués par joe sur son repository et les place dans une nouvelle branche locale, que je nomme joe.

git checkout joe

Je me rends dans cette nouvelle branche. Le répertoire courant de mon projet contient maintenant les modifications effectuées par joe. Je peux ainsi effectuer tranquillement les tests que je désire sur cette application et ainsi vérifier que toutes les modifications effectuées par joe sont correctes.

Une fois que tous mes tests sont effectués, je vais les valider dans ma branche master. Pour cela je dois remettre cette branche master comme branche active.

git checkout master

Puis je merge la branche joe dans celle-ci.

git merge joe

Tous les commits effectués par joe ont ainsi été approuvés dans ma branche master. Je n'ai plus qu'à pousser les commits ajoutés

git push origin master

C'est bien évidemment plus long et plus complexe que d'utiliser la Fork Queue. Mais la qualité de votre application s'y retrouvera puisque vous limiterez fortement le risque d'erreurs non désirées.

Et si je ne veux accepter que certains commits ?

Supposons que joe ait effectué deux commits. Un est intéressant. Quant à l'autre il casse tout ... Nous ne désirons pas accepter les deux, mais un seul. Pour cela, nous allons utiliser cherry-pick.

Cherry Pick nous permet de sélectionner un identifiant de commit et de l'approuver dans master. Commençons par trouver cet identifiant de commit. Avec joe comme branche active, tapez

git log

Qui vous retournera le log des derniers commits effectués. Supposons que vous ayez le log suivant :

commit 7797aec6a35d928045f2a90fdddd9001dbf1a567
Author: Joe Doe <joe.doe@example.com>
Date:   Tue Jun 15 12:23:45 2010 +0200

    Ca sers à rien ça

commit 1cd60cc03530cd88689f19e6c5e3fd5f95b4ed70
Author: Joe Doe <joe.doe@example.com>
Date:   Tue Jun 15 11:56:38 2010 +0200

    Ouh lala le méchant bug

commit 7feb18184cdeff2363d6b608201ac6431f53e070
Author: Damien Mathieu <damien@example.com>
Date:   Tue Jun 15 11:49:52 2010 +0200

    Release v1.0.0

Vous pouvez voir que chaque commit est identifié par un hash. C'est en passant ce hash que nous allons pouvoir identifier un commit en particulier et effectuer le cherry-pick. Retournez dans la branche master.

Puis nous incluons uniquement le premier commit de Joe.

git cherry-pick 1cd60cc03530cd88689f19e6c5e3fd5f95b4ed70

Et voila ! Vous n'avez pas mergé tous les commits de joe dans votre repository principal, mais que celui que vous désirez.

GIT est capable de reconnaitre une partie de hash. Ainsi, nous aurions pu taper `git cherry-pick 1cd60cc`, le commit aurait été reconnu et aurait été mergé dans dev

Conclusion

La fonctionnalité de Fork Queue est peut-être aisée lorsque votre projet est petit et que vous avez peu de commits différents ou de risques de dommages collatéraux. Mais dès que celle-ci commence à prendre de l'ampleur, vous devrez alors appliquer les commits de personnes tiers avec plus d'attention. La, la Fork Queue devient un ennemi et un facteur d'erreurs pour votre application. Utilisez la avec parcimonie !

Corrigez vos régressions avec git bisect

On a beau écrire autant de tests que l'on voudra, il arrivera quasiment inévitablement que l'on ait des régressions dont on ne rends pas forcément compte tout de suite mais parfois après quelques commit supplémentaires, voir plusieurs jours plus tard. Et il est parfois assez complexe de comprendre quelle "amélioration" a inséré cette régression.

Si vous avez versionné votre projet avec GIT cependant, vous allez pouvoir utiliser git bisect afin de traquer ce bug et le corriger plus aisément.

Travaux pratiques

Prenons moqueur avec gitg afin de visualiser le log des commit. Notre arbre de commit ressemble à ceci :

Cependant, nous nous rendons compte que nous avons un bug. Nous réussissons à le reproduire et savons donc à peu près d'où il vient. Cependant nous ne savons pas ou il a été introduit. Faisons donc un bisect afin de trouver cela !

Initialisons le bisect :

git bisect start

Puis nous savons que le commit sur lequel nous sommes actuellement n'est pas bon. Nous le déclarons donc comme en erreur :

git bisect bad

Nous avons maintenant un arbre de commit qui ressemble à ceci :

Il nous faut ensuite trouver un endroit ou notre code sera correct. Allons sur le tag 0.0.1.

git checkout 0.0.1

Vu que nous arrivons à reproduire notre erreur, nous voyons qu'elle ne se produit pas à ce niveau. Nous pouvons donc déclarer notre code comme correct.

git bisect good

Nous avons maintenant un arbre de commit qui ressemble à cela :

Nous pouvons voir que GIT a, automatiquement, ajouté des références aux deux commit que nous avons vérifié comme étant correct ou non. Et, si vous regardez votre console, vous verrez la chose suivante :

((no branch)) damien@pcdamien ~/projects/moqueur $ git bisect good
Bisecting: 3 revisions left to test after this (roughly 2 steps)
[72d09e65ca2fee3d281200d92ec63f15e8c19257] when the url is a regex, we get it's parameters in the content

GIT, voyant que nous avons un commit correct et un incorrect, nous a déplacé automatiquement au commit situé exactement entre les deux. Ainsi, nous n'avons plus qu'à vérifier si notre bug se produit ou non. Quelle chance nous avons, il est correct !

((no branch)) damien@pcdamien ~/projects/moqueur $ git bisect good
Bisecting: 1 revisions left to test after this (roughly 1 steps)
[74d0368b8a7327c6ef7500589b6c8359d55ec8c0] specify if the url has been mocked or not in the counter

Et si nous regardons notre arbre de commit, il ressemble maintenant à ceci :

GIT nous a, de nouveau, créé une référence indiquant que le commit que nous venons de tester est correct. Et il nous a envoyé automatiquement sur le commit situé exactement au milieu. Testons ceci à nouveau, jusqu'à ce que nous tombions sur le commit exact qui implémente la régression que nous cherchons à corriger.

((no branch)) damien@pcdamien ~/projects/moqueur $ git bisect good
74d0368b8a7327c6ef7500589b6c8359d55ec8c0 is the first bad commit
commit 74d0368b8a7327c6ef7500589b6c8359d55ec8c0
Date:   Fri Mar 26 11:52:53 2010 +0100</p>

<p>    specify if the url has been mocked or not in the counter</p>

<p>:100644 100644 0e2cf9e02a4595c1a04da670eed109a128fc014f dbfc82c51599afe166b317fb4a5b24c7dbc50451 M	moqueur.js
:040000 040000 412cdf8ce8d2f25cfb5474bee65597d3dc0febf0 e115c9172ed71841466cc009adec71bb50e8ea7f M	spec

Et notre arbre de commit ressemble à ceci :

Nous savons ou est notre bug. Nous pouvons le corriger !

Et nous pouvons arrêter le bisect (et donc enlever toutes les références good/bad créées).

git bisect reset

N'oubliez pas d'en profiter pour écrire un test qui vous évitera d'avoir cette régression une seconde fois dans le futur.

Dans la théorie

La recherche dichotomique

Tous ceux qui ont fait un tout petit peu d'algorithmie (pour ma part, je me souviens avoir fait ça en première année de BTS, aux alentours de novembre. C'est donc réellement les bases), vous vous souvenez probablement des diverses méthodes de recherche, notamment la recherche dichotomique.

Explication rapide : dans une liste triée de chiffres allant de 1 à 10, nous désirons trouver ou se situe le 3. Nous pourrions parcourir la liste dans l'ordre et aller jusqu'à trouver notre chiffre. Mais si nous cherchions 9, nous mettrions énormément de temps à le trouver.

En recherche dichotomique, nous allons faire la chose suivante : prendre le chiffre 5 qui est au milieu. Si celui-ci est plus petit que le chiffre que nous cherchons, nous prendrons ensuite le chiffre situé entre 1 et 5 (2 ou 3). Et ce, jusqu'à trouver le chiffre approprié. Nous réduisons fortement le nombre d'itérations nécessaires pour trouver les chiffres éloignés de notre point de départ ou d'arrivée.

Application au bisect

C'est exactement ce que nous faisons ici. Vous ignorez quand a été implémenté le bug que vous cherchez à corriger. Vous pourriez donc chercher dans chacun de vos commit manuellement. Mais cela vous prendrait énormément de temps si le commit est ancien.

Nous créons donc une intervalle réduite, basée sur le dernier commit, que l'on sait incorrect. Et un autre commit, que l'on sait correct. Puis on fait une recherche dichotomique en divisant à chaque fois par 2 l'intervalle entre un commit correct et un commit incorrect.

En 4 étapes, nous avons donc réussi à localiser un commit qui pouvait se cacher n'importe ou dans les 8 commit entre 0.0.1 et 0.0.2.

C'est lorsque vous utilisez bisect que vous apprécierez tout particulièrement d'avoir fait de petits commit et pas de commit énormes (ce que j'appelle BFUC)

Et encore un point pour git et les gestionnaires de version en général ! ;)

Tu fetch ou tu pull ?

Si j'étais marseillais un verre de ricard à la main, je me serai posé cette question bien plus tôt ! Mais ce n'est pas le cas. Heureusement il n'est jamais trop tard ! ;)

Par habitude, afin de mettre à jour un repository GIT distant, j'utilise git pull. Ca fonctionne à merveille, tout le monde a ses données à jour et on se croirait presque au pays des bisounours. Mais Gargamel vient mettre son nez là-dedans (ouais je mélange Schtroumpf et Bisounours. Honte sur moi !).

Ce matin, j'ai voulu, avant de faire la release de la version 1.0.0 de jesus (car il est prêt pour la production), mettre à jour la documentation. Le principe est simple. J'utilise GitHub Pages. Il me faut donc juste une branche "gh-pages", dont le contenu correspond à ce qui est en ligne chez GitHub pour ma documentation. Dès que je commit sur cette branche, la page en ligne est mise à jour.

Cependant mes deux branches master et gh-pages n'ont pas le même index. Les deux ne peuvent pas être mergées ! Ce matin, je me vois donc faire un

git pull origin gh-pages:gh-pages
En me disant "comme cela, je récupère le contenu de la branche de documentation". Et la je me retrouve avec une dizaine d'erreurs de conflit ! WTF comme dirait l'autre.

Et justement pour le coup, j'aurai du faire un

git fetch origin gh-pages:gh-pages

La différence entre ces deux commandes en apparence similaires est pourtant énorme. Git fetch ne fait que récupérer les données. Git pull les récupère et fait un merge avec la branche courante ... Du coup merge mes deux branches, vu qu'elles ont pas la même base, c'est pas super cool.

Moralité : vous pouvez faire un git fetch afin de mettre à jour votre copie locale avec les derniers commits distants. La branche sur laquelle vous faites le fetch aura les derniers commits. Mais votre branche de travail ne sera pas modifiée. Si vous faites un git pull, non seulement la branche sur laquelle vous faites le fetch aura les derniers commits distants. Mais votre branche de travail sera également mergée avec ces derniers commits.

En y réflechissant bien, fetch est bien plus recommandable que pull, qui peut casser un repository assez facilement.

Les hooks GIT

Désolé j'ai dit dans mon précédent article que je ne reparlerai pas de GIT cette semaine. Mais je tiens à partager ma découverte du jour que je trouve particulièrement cool :)

Il peut être particulièrement utile de, par exemple, recevoir un email à chaque fois que l'un des développeurs de votre application fait un push sur le repository distant. Ou encore vous pouvez désirer exécuter automatiquement les tests de votre application avant chaque commit et n'autoriser le commit que si tous passent. Et automatiser ce genre de choses pourrait être particulièrement kiffant.

Du coup ... haaaave you met GIT Hooks ? Dans le répertoire .git/hooks de votre application existent plusieurs fichiers .sample. Chacun représente un hook et est exécuté au moment opportun. Par exemple "post-receive" sera exécuté du côté du repository distant à chaque fois que quelqu'un poussera le projet :) De même "pre-commit" sera exécuté du côté du client avant chaque commit (et vous pourrez décider de refuser le commit automatiquement).

Par exemple plaçons dans notre fichier "post-receive.sample" que nous commencons par renommer en y enlevant l'extension ".sample" afin qu'il se nomme "post-receive" (il doit également être exécutable).

Le script /home/ruby/scripts/post-receive.rb sera exécuté automatiquement à chaque post receive. Et dans ce script nous plaçons un envoi de mail :

require 'net/smtp'
msg = "Subject: A push has been made\r\n\r\nA push has been made on one of your repositories.\r\nOld commit: " + ARGV[0] + "\r\nNew commit: " + ARGV[1] + "Ref: " + ARGV[2]
Net::SMTP.start('localhost') do |smtp|
    smtp.send_message msg, 'noreply@localhost', 'you@your_email.com'
end

Ainsi à chaque push fait, nous envoyons un email à l'adresse de notre choix (you@your_email.com) signalant qu'un nouveau push a été fait. Cela peut être une liste de diffusion par exemple. Mais bien évidemment cela peut être autre chose qu'un email. Il est tout à fait possible, par exemple, de signaler cela sur un salon Campfire utilisé par l'équipe de développement.

Note : si vous hébergez votre repository sur GitHub, il ne vous est pas utile de créer de hook post-receive de cette manière. Ceux-ci sont gérés via l'interface web.

Pour quelques informations supplémentaires et notamment l'exécution automatique des tests avant un commit que j'ai mentionné plus haut, je vous invite à lire Les hooks sur le Git Book (fr).

Pourquoi je préfère GIT à SVN

Rassurez vous ceci est le dernier article de cette série sur GIT. Je pense repartir sur un peu de rails la semaine prochaine. On me pose souvent la question "pourquoi choisir GIT et pas SVN ?"

Voici donc de manière absolument pas triée ni objective tous les arguments qui font que je préfère GIT à SVN (et de loin). Notez que ce n'est que mon opinion. Vous pouvez en avoir une autre c'est absolument pas génant.

  • Pouvoir être nomade

    C'est ce que je montre dans mon article précédent. Avec GIT, contrairement à SVN, vous pouvez continuer à committer et ainsi conserver un repository avec des commits propres et pas un gros commit une fois de temps en temps. Même si vous n'êtes pas connecté ou n'avez pas accès à votre repository distant. Vous restez productif même en déplacement.

  • Une vraie gestion des tags et branches

    Avec SVN si vous désirez créer une nouvelle branche c'est pas compliqué : vous faites un copier/coller de votre répertoire trunk, le mettez dans branch/nom_de_la_branche. Et c'est fait. Y'a plus qu'à committer. Et le jour ou vous voulez fusionner les deux branches, morflez. Pareil pour les tags.

    GIT gère les branches et tags de manière native. Pas besoin d'action manuelle (copier/coller). Vous faites un "git branch <nouvelle_branch>" et votre branche est créée. Un "git checkout <branch>" et vous changez de branche active. Et un "git rebase <branch> <seconde_branch>" et vos deux branches sont fusionnées !

  • GitHub

    Ouais c'est pas vraiment GIT. Mais je kiffe littéralement GitHub. Pouvoir forker un projet en un clic; pouvoir commenter des commits etc. Tout projet libre devrait permettre ce genre de choses sur son repository. C'est ça qui pousse les autres développeurs à créer des patchs.

Ces trois arguments me suffisent personnellement à nettement préférer GIT à SVN. Et vous ? Quel est votre logiciel de contrôle de version préféré ?

Screencast GIT et synchronisation de repositories

Je viens de réaliser un screencast sur GIT et la synchronisation multi repositories. Celui-ci explique :

  • Comment transmettre les données committées sur votre serveur de développement
  • Comment les transmettre sur un système de fichier local (par exemple une clé USB) lorsque vous êtes en hors ligne
  • Comment récupérer les derniers commits distants

Vous pouvez visualiser ce screencast ci-dessous.

Afficher la branche GIT actuelle dans votre console

Lorsque vous manipulez un repository GIT en utilisant (voir en abusant (ce qui n'est pas forcément négatif)) les branches, vous pouvez régulièrement vous poser la question "dans quelle branche suis-je ? Est-ce la bonne ?" Et c'est toujours particulièrement lourd de devoir faire un git branch

Afin de voir toutes les branches et de trouver l'active. Je viens cependant de tomber sur une astuce donnée par le support github. [sourcecode language="plain"]# git branch parse_git_branch() { git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1) /' } PS1="\$(parse_git_branch)$PS1"[/sourcecode]

Placez ceci dans ~/.bashrc ou /etc/bashrc (pour que cela soit valide pour tous les utilisateurs de la machine). Rechargez votre console et admirez :)

[sourcecode language="plain"]dmathieu@dmathieu-ubuntu:~$ cd /home/dmathieu/projects/refstats/ (master) dmathieu@dmathieu-ubuntu:~/projects/refstats$[/sourcecode]

Lorsque vous êtes dans un repository GIT, la branche courante s'affichera. Dans le cas contraire, rien ne s'affichera :)

Commandes de base GIT

Certaines personnes, notamment Clément (et d'autres) m'ont demandé il y a quelques semaines de cela de rédiger un article sur les commandes GIT de base pour une utilisation console. Déjà, sachez qu'il existe de multiples interfaces graphiques pour Windows et Mac. Il en existe également pour Linux. Mais je n'ai rien trouvé qui ne convienne à mes exigences. Donc je fais tout en ligne de commande et j'utilise gitk pour visualiser les commits faits et en cours. Je n'aborde ici que les commandes de base, pour le développement de tous les jours. Pas de notion de branches ou de tags donc.

A chacune des commandes ci-dessous, il faut précéder l'exécutable "git". Nous aurons donc : git <nom de commande>

  • add

    Permet d'ajouter des fichiers au prochain commit. Cette commande prends comme paramètre le nom du fichier ou du répertoire à ajouter. Exemples : [sourcecode language="plain"]git add app/models/mon_model.rb[/sourcecode] Ajoutera le fichier app/models/mon_model.rb à la liste des fichiers à committer.

    [sourcecode language="plain"]git add app/models[/sourcecode] Ajoutera tous les fichiers présents dans le dossier app/models dans la liste des fichiers à committer

    [sourcecode language="plain"]git add .[/sourcecode] Ajoutera tous les fichiers du projet à committer. Evidemment seuls les nouveaux fichiers ou ceux modifiés seront ajoutés. C'est le principe même d'un SCM ;)

  • rm

    Vous l'aurez peut-être deviné, cette commande est l'inverse de add. Elle vous permet de supprimer un fichier du repository. En effet un fichier supprimé physiquement n'est pas supprimé dans le repository. Il faut donc le faire via ce rm. Note : si vous supprimer un fichier existant avec cette méthode, il sera supprimé physiquement.

    Exemples : [sourcecode language="plain"]git rm app/models/mon_model.rb[/sourcecode] Supprimera le fichier app/models/mon_model.rb

    [sourcecode language="plain"]git rm -r app/models[/sourcecode] Supprimera tous les modèles du projet. Notez le -r qui force la récursivité car vous supprimez un répertoire.

  • commit

    Après avoir ajouté et supprimé tout plein de fichiers à notre prochain commit, il faut faire celui-ci ! La commande commit permet donc de valider les changements faits. Tant que vous n'avez pas committé, vous pouvez revenir en arrière (même après en fait. Mais on verra pas cela dans cet article).

    Exemple : [sourcecode language="plain"]git commit -m "Un super message de description"[/sourcecode]

  • reset

    Comme je disais, tant que vous n'avez pas committé, vous pouvez annuler des changements particulièrement simplement avec git reset. Cette commande réinitialise tous les fichiers dans votre repository à leur état lors du dernier commit. Vous annulez donc tous les changements non committés et revenez sur une base propre.

    Exemple : [sourcecode language="plain"]git reset --hard HEAD[/sourcecode]

  • push

    Après avoir committé vos changements, il vous faut probablement pousser ceux-ci sur le repository distant afin de pouvoir partager vos modifications avec les autres développeurs du projet. Ou bien tout simplement de pouvoir récupérer ces changements sur une autre machine (celle de test ou de production par exemple).

    Exemples : [sourcecode language="plain"]git push[/sourcecode] Poussera la branche courante sur le repository distant nommé "origin"

    [sourcecode language="plain"]git push backup[/sourcecode] Poussera la branche courante sur le repository distant nommé "backup"

    [sourcecode language="plain"]git push backup V2[/sourcecode] Poussera la branche nommée "V2" sur le repository distant nommé "backup".

  • pull

    Pousser c'est bien. Mais il faut récupérer les données qui ont été poussées par vous sur une autre machine ou par un autre développeur. Cette commande fonctionne avec exactement les même arguments que la précédente mais pour récupérer les données de votre repository.

Voila. Avec tout cela, vous pouvez :

  • Ajouter, supprimer des fichiers et les committer
  • Annuler une modification non committée
  • Envoyer et récupérer les données sur un repository distant
Ce qui est, au final, les commandes GIT de tous les jours (dans l'utilisation que j'en fais du moins). Peut-être ferais-je d'autres articles plus avancés au niveau de la gestion des branches ou de l'annulation d'un commit. Mais cela viendra dans un prochain article.

git-svn pour utiliser git sur un repository svn

Je ne m'en cache pas, je suis un pro git à fond. Cependant et malheureusement, git n'est pas (encore) très répandu et beaucoup de projets sont encore hébergés sur des repositories SVN. C'est le cas chez O2Sources (mais on parle d'y remédier, notamment lorsque Townce gèrera cela).

Vu que je viens de migrer ma machine de Windows vers Ubuntu, j'ai décidé d'en profiter pour faire un test. Utiliser git-svn pour commiter en local en git et pousser par la suite sur le repository svn :)

Déjà, l'installation. Sous Debian-Like, sudo aptitude install git-svn Normalement, cela vous crée une commande "git-svn". Moi, ça l'a pas fait. Du coup un petit coup de sudo find / -name git-svn; vous trouvez l'emplacement de l'exécutable (théoriquement dans /usr/bin) et y créer une commande globale. ln -s /chemin/vers/git-svn /usr/bin/git-svn

Ensuite, commençons par récupérer notre repository git-svn clone -s http://domaine.net/chemin/vers/le/repository Si vous avez une arborescence avec des tags (dossiers tags/, trunk/ et branchs/), placez l'option -s. Ainsi, git-svn les convertira en tags et branches GIT. Sinon, c'est inutile :)

Deuxième étape : si vous avez des options git:ignore, elles ne sont pas prises en compte. Faites les donc : git-svn show-ignore > .gitignore

Maintenant, faites vous une session de développement. Committez comme d'habitude sur votre repository git et oubliez svn (youpi !!). Une fois que celle-ci est terminée, il vous faut committer (bah ouais hein).

Pour cela, commencons par faire un update. On sait jamais que vous seriez pas le seul à travailler et que l'un de vos collègues n'ait committé entre temps ;) git-svn rebase Et committons git-svn dcommit

Vous verrez que votre repository svn a été mis à jour. Cool non ? :) Et vous, vous préférez GIT ou SVN ? (ouais, postez des commentaires !!)

De l'intérêt de SVN ou GIT sur des projets perso

Lorsque j'étais en Picardie la semaine dernière, en discutant avec Joris, nous en venons à parler de nos plateformes de développement personnelles. Du coup forcément je lui explique l'architecture contraignante que je m'impose (développement local -> commit svn -> test sur serveur de préproduction -> push en production).

Et la il me dit "je n'ai jamais compris l'utilité de SVN". Honte sur lui que je dis. Et je m'engage à lui expliquer cela. Comme après on est arrivés au bar, je n'ai pas eu le temps de le faire. Mais c'est tous bénéfices pour vous puisque je le fais donc maintenant :)

Commençons par un peu d'histoire. Il y a trois générations de grands systèmes de gestion de version.

Il en existe d'autres évidemment. Mais je les épargne. Ce billet n'est pas là pour faire une liste de tous les systèmes de gestion de versions.

Alors comment ça fonctionne ? C'est au final assez simple. Lorsque vous développez votre application seul et toujours sur la même machine, il est assez aisé de s'y retrouver. Vous avez toujours les dernières modifications de disponibles en local.

Le jour ou vous commencez à développer à deux ou à passer d'une machine à l'autre par contre, c'est plus embêtant. Si vous êtes toujours seul, il vous suffirait d'une clé usb pour avoir toujours tous vos documents. Quand vous êtes à deux en revanche, cela n'est pas faisable.

Et c'est la qu'intervient le contrôle de versions. Supposons trois fichiers : A, B, C

Vous modifiez le contenu du fichier A. Pendant ce temps un second développeur modifie le contenu du fichier B. Ici on a que trois documents. Du coup il n'est pas difficile de s'y retrouver et de merger les modifications. Mais sur des gros projets ?

En faisant un commit sur votre contrôleur de versions, vous ne mettrez donc que le fichier A à jour. Le second développeur ne perdra pas ses modifications. Et lorsqu'il mettra à jour sa version locale avec la version distante, il récupèrera le contenu du fichier A tel que vous l'avez modifié.

Poussons maintenant le vice plus loin :) Le document A est particulièrement long et vous modifiez le début de celui-ci, les lignes 50 et 75 par exemple. Le second développeur modifie les lignes 60 et 160.

Eh bien vos modifications pourront toujours être prises en compte par le contrôleur de versions, qui verra les lignes que vous avez ajouté dans le document et celles que vous avez modifié et sera capable de ne modifier que cela :)

On ira pas plus loin que cela. Il ne faut pas bousser le bouchon trop loin et il n'est pas capable de merger des modifications sur la même ligne. En revanche, vous pouvez lui demander un café et voir ce qu'il répondra.

Ensuite, ous constaterez rapidement, en faisant quelques commits sur le contrôleur de version que vous pouvez placer un commentaire sur chacune d'elle. Ainsi vous avez un historique de toutes les modifications apportées à chacun des fichiers de votre projet (et par qui).

C'est notamment fortement pratique dans un projet libre.  Vous pouvez par exemple suivre toutes les modifications apportées à votre projet préféré. Voici un exemple. Il s'agit du dernier commit fait sur Ruby on Rails, durant la nuit (heure française).

Pour finir, quel contrôleur de version choisir ? J'en utilise pour ma part, deux. SVN, sur ma machine de développement pour tous mes projets privés. Et GIT sur github.com pour mes projets publics.

Entre les deux, je préfère git. Principalement car celui-ci implémente le contrôle de version complet en local. Vous pouvez donc faire votre commit en local puis le "pusher" et il sera en ligne. Ainsi, lors d'un voyage en train, je développe en découpant en commits lisibles et fait un push en arrivant. C'est comme si j'avais eu un accès internet durant mon voyage :) Alors que les commits SVN font directement la mise à jour sur le serveur. C'est un peu moins propre.

Mais je fais face à quelques problèmes pour installer un serveur git sur ma machine. Pour l'instant, je dois donc encore me contenter d'un svn. Mais cela ne saurait tarder à changer.