Accueil > Réflexions > Git, un puissant outil

Git, un puissant outil

mercredi 4 mai 2011, par Nicolas

Introduction

Utilisateur de Git depuis maintenant plus de deux ans, il me paraît logique de parler de cet outil, et des points forts ou défauts que je lui trouve.

À noter que la plupart des arguments ne sont pas spécifiques à cet outil, et que j’aurais probablement pu utiliser un autre outil du même style, comme Mercurial ou Bazaar, pour les mêmes résultats.

Qu’est-ce que Git ?

Git est un outil de contrôle de source, permettant de suivre l’historique des modifications sur un projet [1]. C’est un outil distribué, il n’y a pas de dépôt central de sources, contrairement à des logiciels comme Subversion, CVS ou Team Foundation Server [2].

Git a été conçu par Linus Torvalds, créateur du noyau Linux, pour gérer les sources du noyau [3], et est un logiciel libre [4].

Il propose les fonctions standard d’un contrôle de source, à savoir suivi des modifications, étiquettes sur les modifications, branches, etc.

Outil distribué

Git est un outil distribué, ce qui signifie que chaque développeur a son propre dépôt en local [5]. Pour transmettre leurs modifications à d’autres, les développeurs leur demandent de pull [6] depuis leur dépôt, push vers un dépôt distant ou envoient les modifications par mail. Avantage, il est possible de travailler sans connexion Internet, notamment en déplacement.

Il n’y a donc pas à proprement parler de « dépôt maître » contenant toutes les modifications, chacun a potentiellement des modifications spécifiques en local. Il est cependant possible, voire très utile, d’avoir un dépôt sur lequel tous les développeurs poussent leurs modifications pour des besoins de synchronisation des sources et afin de tester l’intégration complète du code.

Les dépôts vers ou depuis lesquels les modifications sont transmissibles ou récupérables peuvent être en local [7], ou sur des serveurs distants via des protocoles comme FTP, SFTP, SSH.

Conséquence de l’absence de centralisation, il n’y a pas de numéro de révision [8] comme sur SVN ou TFS. Chaque révision a un identifiant unique [9], et il y a également des façons de spécifier rapidement les révisions précédant la dernière révision de la branche courante.

L’inconvénient de cette stratégie de stockage est que la taille du dépôt peut être importante, surtout s’il y a de nombreux fichiers binaires régulièrement modifiés.

Rapidité des fonctions habituelles

Parce que l’intégralité du dépôt est disponible sur le propre poste du développeur, de nombreuses fonctions sont très rapides : validation de modification, affichage d’historique, fusion de branches, etc. Des logiciels ayant un dépôt centralisé doivent interroger ce dépôt pour par exemple récupérer l’historique, ce qui entraîne des temps de latence [10].

La validation de modifications, en particulier, est très rapide. Du coup moins d’attente, et une plus grande tendance à faire des validations petites modifications par petites modifications plutôt que par gros blocs. Bien sûr cette politique de validation incrémentale est possible sur n’importe quel contrôle de source. Mais si chaque validation prend une ou deux secondes, le développeur attend au final un certain temps. Cette attente dans mon cas peut « casser » mon rythme de travail, alors qu’une validation quasi instantanée me permet de continuer rapidement.

Transmission automatique des sources

Même si chacun a son propre dépôt en local, il est possible, grâce aux « hooks », de configurer Git pour qu’à chaque validation de modification celle-ci soit transmise sur un serveur distant. Cela permet de dupliquer les sources sur différents disques durs, ou différentes machines. Cela permet également une mise à jour instantanée sur des dépôts distants.

Modifications en attente

Git permet simplement de mettre en attente des modifications pour une utilisation future, via sa commande stash. Ceci permet d’expérimenter une modification mineure, la stocker dans un coin pour retravailler dessus plus tard, sans aller jusqu’à utiliser une branche.

Puissance des branches

La gestion des branches par Git est simple et puissante, et est pour moi une raison majeure d’utiliser cet outil plutôt que SVN que j’utilisais précédemment.

Par défaut la branche créée par Git est nommée master et est considérée la principale.

La création d’une branche, à partir d’une autre branche, est une opération très simple et quasiment instantanée [11]. Chaque branche est identifiée par un nom et peut être renommée.

Il est simple d’obtenir les modifications entre différentes branches, et de fusionner, en totalité ou partiellement, ces modifications entre branches. Cerise sur le gâteau, la fusion peut soit préserver l’historique, soit n’ajouter à la branche destination qu’une unique révision, ce qui permet de ne garder que le résultat final sans les étapes intermédiaires.

Git gère la fusion de branche de façon « intelligente », gardant trace de ce qui a été fusionné ou non. Il interdira ainsi la suppression accidentelle d’une branche non fusionnée dans master. La fusion croisée, pour récupérer des modifications en parallèle, est également bien gérée.

Conséquence, il devient pour moi quasiment un réflexe de créer une branche avant de commencer des modifications importantes, voire mineures. Les modifications finies, la fusion de la branche sur la branche d’origine est simple, et utiliser une branche permet de retravailler sur la branche d’origine sans inclure des modifications en cours, ou de totalement jeter ces modifications, si elles s’avèrent une impasse, sans impact.

Autre usage, créer une branche pour chaque fonction majeure permet de ne fusionner que certaines sur la branche principale, après validation, et d’en laisser d’autres en attente, ou de les supprimer plus tard.

Bien évidemment l’échange de branches entre développeurs est possible. Les branches étant locales par défaut, les dépôts des autres développeurs ne sont pas impactés par ces modifications partielles.

Exemple d’utilisation : à partir de master, une branche fonction est créée, sur laquelle une nouvelle fonction est développée. Durant le développent un bug est signalé. Une branche correction est créée depuis master, sur laquelle le bug sera corrigé avec plusieurs révisions. Puis correction est fusionnée vers master et éventuellement supprimée, enfin master est fusionnée vers correction afin de confirmer que les modifications n’impactent pas la nouvelle fonction. Une fois la nouvelle fonction terminée et validée, correction est fusionnée vers master.

Un outil puissant, à manier avec précaution

Git demandera confirmation avant de faire certaines choses « critiques », comme supprimer une branche non fusionnée sur la branche principale et perdre des modifications. Cependant des commandes comme pull agiront sans confirmation, et sans possibilité d’annuler l’opération. Il est donc nécessaire d’utiliser cette fonction avec attention [12].

Conclusion

Git est pour moi un très bon outil, car il correspond à ma façon de travailler : de façon décentralisée, avec potentiellement plusieurs modifications en parallèle, en attente de validation ou simplement expérimentales, rapidité des opérations usuelles.

Je n’ai cependant pas eu l’occasion de travailler sur des projets impliquant de nombreuses personnes, aussi je ne peux pas juger si cet outil serait adapté ou non. Le fait qu’il soit utilisé pour le développement du noyau Linux, avec plusieurs centaines ou milliers de contributeurs, me laisse à penser qu’il fonctionnerait parfaitement.

Bien sûr il n’est pas forcément adapté à tous les développeurs, chaque personne ayant sa façon de travailler et de structurer ses développements.


[1Voir cet article pour plus de détails sur le contrôle de sources.

[2À noter que TFS est plus qu’un simple contrôle de sources, proposant notamment des fonctions de suivi de bugs, intégration continue etc.

[3Voir la page Wikipédia pour de plus amples détails

[4Sous licence GPL v2.

[5Dans le sous-répertoire .git de la racine du projet pour être précis.

[6Du nom de la commande git associée.

[7Copie de sauvegarde sur un disque dur physique différent par exemple, ou version visible versus version de test interne.

[8Ensemble atomique de modifications, validées au même moment par la même personne.

[9La signature SHA-1 de son contenu.

[10Bien sûr certains logiciels centralisés peuvent garder l’historique en local pour accélérer les traitements.

[11La commande de création est git checkout -b nom de la branche.

[12Bien sûr il y a peut-être des possibilités pour exiger une confirmation, ou alors ma façon d’utiliser cette commande pourrait être mauvaise.

Messages

  • J’ai jamais eut l’occasion de travailler avec Git, mais j’aime vraiment son principe.
    Je serai curieux de savoir comment se passe l’utilisation de Git avec une équipe de "développeurs moyens".
    J’ai très souvent bossé avec des gens qui avaient vachement de mal avec les fonctionnalités de base de cvs/svn/.. et pour qui faire une branche ou un merge signifiait une catastrophe assurée ! Est-ce que ce genre d’outil n’est pas réservé à de bons développeurs à l’aise avec les branch/merge ?

    Autre question : y a-t-il des bonnes pratiques particulières concernant Git pour la gestion des bugs/builds/intégration continue ?
    (Tout ce qui est méthode "classique" fonctionne évidemment très bien, mais je me demandais s’i y avait au contraire des possibilités en plus !)

    Merci pour cet article :)

    • Difficile de dire comment des « développeurs moyens » utiliseraient l’outil. Comme tout outil puissant, il peut être dangereux dans des mains malhabiles :)

      En effet la fonctionnalité de branche est peut-être une utilisation assez avancée, mais tellement efficace, en tout cas de mon point de vue.

      D’un autre côté, il est peut-être plus simple d’imposer cette utilisation de branche à de tels développeurs, qui ont peut-être moins à « désapprendre ».

      Sur l’intégration continue, je ne sais pas si c’est une bonne pratique ou pas, mais il y a une astuce que j’ai trouvée sympathique.

      Le principe est d’avoir un serveur sur lequel les développeurs ont un accès, et peuvent pousser sur des branches mais pas sur la branche master. Un serveur d’intégration continue (type Jenkins, qui est un fork de Hudson) vérifie régulièrement ces branches supplémentaires, lance les tâches programmées (compilation, tests unitaires, génération de documentation, ce genre de choses). Si l’opération réussit alors les branches sont fusionnées sur master.

      Cela permet d’avoir sur le serveur une branche master garantie passer les tests mis en place.

  • Merci pour la réponse :)
    J’aime bien ce principe de tests puis intégration :)
    [TFS utilise un principe de "gated commit" qui me fait penser à ça, bon principe je pense !]