Gestion de versions avec Git

de | 24 février 2016

L’utilisation d’un outil de gestion de versions est primordiale dans votre pratique de développement logiciel.

Dans ce cadre, nous vous conseillons l’utilisation de Git à la fois car il est d’utilisation très courante et car le LIS met à votre disposition un serveur GitLab permettant l’hébergement de dépôts Git.

Documentation

Introduction à Git

Si la notion de gestion de version et/ou l’utilisation de Git vous sont inconnus, vous pouvez consulter l’introduction à Git présentée lors de la première session LIFTech’.

Prise en main de Git

Ce petit guide peut également vous aider à démarrer sur Git et servir par la suite de pense-bête.

Pour vous aider à bien comprendre les concepts mis en œuvre dans Git, vous pouvez consulter les ressources suivantes qui les illustrent de manière visuelle : A Grip on Git, Learning Git Branching, Visualizing Git Concepts with D3.

Documentation officielle

Pour aller plus loin dans l’utilisation de Git, vous pouvez consulter la documentation officielle.

Bonnes pratiques

Git est un outil puissant mais qui peut parfois être complexe à comprendre et à utiliser. Et comme tout outil, il peut être manié avec plus ou moins de dextérité. Certains auteurs rédigent des articles voir des livres entiers pour décrire la meilleure façon de l’utiliser. Vous pouvez vous inspirez de ces recueils de bonnes pratiques pour perfectionner votre utilisation de Git. Par exemple en commençant par cette page.

Correction d’erreurs de commit

Si vous avez enregistré par erreur des modifications dans un dépôt Git et que vous voulez réparer vos erreurs, consultez cette page.

Recommandations

À utiliser sans modération

L’utilisation d’un serveur central n’est pas une nécessité avec Git, un simple git init permettant de créer un nouveau dépôt local dans le répertoire courant. N’hésitez donc pas à utiliser Git même pour de courts projets ou pour de petites expérimentations qui ne justifieraient pas la création d’un projet sur GitLab.

De plus l’utilisation de Git n’est pas réservée à la gestion de code source. Vous pouvez profiter de ses fonctionnalités de gestion d’historique et de travail collaboratif pour tous vos fichiers textuels, notamment lors de la rédaction de textes, d’articles scientifiques, de supports de présentations ou de supports de cours (si votre format d’édition s’appuie bien sur des fichiers textes, comme par exemple sous Latex).

GitLab

Si vous souhaitez utiliser Git pour un projet de développement significatif au LIS, vous avez intérêt à créer un projet associé sur le serveur GitLab. Ceci vous permettra notamment de profiter des outils en ligne de visualisation des fichiers et des modifications du dépôt Git, de disposer d’une sauvegarde du dépôt et de facilement partager vos développements.

Retrouvez plus d’informations sur cette page.

Configuration initiale

Après l’installation de Git, quelques paramètres doivent être configurés.

Le nom d’utilisateur se configure avec :
git config --global user.name "John Doe"

L’adresse électronique se configure avec :
git config --global user.email "john.doe@sitename.ext"

Le choix de l’outil graphique de visualisation et de fusion des différences de fichiers (dans cet exemple on retient l’outil meld) se configure avec :
git config --global merge.tool meld

Ceci permet par la suite de gérer graphiquement les conflits lors des fusion en lançant :
git mergetool
Pour plus de détails sur la gestion des conflits, consultez la section correspondante.

Bonnes pratiques de commit

Granularité

Pour pouvoir exploiter au mieux Git, il est nécessaire de bien construire ses commits de manière à ce qu’ils contiennent des modifications qui ont une unité logique.

Par exemple évitez de regrouper les modifications résolvant deux bogues correspondants à deux tickets différents dans un même commit, ou plus généralement évitez de faire apparaître dans le même commit des modifications qui touchent des fonctionnalités du logiciel qui n’ont pas de rapport entre elles.

Pour faciliter la revue de code et la compréhension des évolutions, il peut également être préférable de conserver une bonne granularité des commits en évitant les commits regroupant un trop grand nombre de modifications en une seule fois. Notez à ce propos qu’il est plus facile dans Git de regrouper a posteriori des commits plutôt que de redécouper un commit en plusieurs commits (cf. la section sur la restructuration des commits).

Messages de commit

Retrouvez des conseils pour bien rédiger vos messages de commit sur cette page.

Retenez en particulier que sur le fond, il faut rédiger les messages de commit avec soin de manière à ce qu’ils soient compréhensibles et utiles.

Si vous utilisez GitLab, pensez à mentionner les éventuels tickets liés à un commit comme indiqué dans cette section.

Sur la forme, faites en sorte que la première ligne du message débute par un majuscule et qu’elle ne contienne pas plus de 50 caractères. Si votre message de commit doit comporter plus de 50 caractères, utilisez la première ligne comme  sujet résumant les changements puis sautez une ligne et détaillez les changements dans autant de paragraphes que nécessaire.

Comme indiqué dans la documentation de Git, la forme conseillée pour le message de commit est donc la suivante :

Short (50 chars or less) summary of changes

More detailed explanatory text, if necessary.  Wrap it to
about 72 characters or so.  In some contexts, the first
line is treated as the subject of an email and the rest of
the text as the body.  The blank line separating the
summary from the body is critical (unless you omit the body
entirely); tools like rebase can get confused if you run
the two together.

Further paragraphs come after blank lines.

  - Bullet points are okay, too

  - Typically a hyphen or asterisk is used for the bullet,
    preceded by a single space, with blank lines in
    between, but conventions vary here

Correction et restructuration (rebase) des commits

Si vous avez besoin de corriger des commits, par exemple pour annuler un ou plusieurs commits ou encore corriger un message de commit, vous pouvez consulter cette page pour retrouver les commande Git nécessaires.

Dans certains cas, vous pouvez vouloir restructurer des commits par exemple pour regrouper plusieurs commits en un seul, ou pour réordonner les commits. C’est notamment le cas lorsqu’une modification qui devrait être incluse dans un commit est manquante, par exemple parce que vous avez oublié d’ajouter un nouveau fichier, ou parce qu’une modification a introduit un dysfonctionnement non détecté initialement mais corrigé dans un commit suivant.

Vous pouvez également vouloir effectuer une restructuration pour rendre l’évolution du code plus logique et compréhensible en vue d’une revue de code lors d’une demande de fusion.

Dans ce dernier cas, concernant une demande de fusion, on peut également vouloir changer le commit qui apparaît comme étant la base de la branche à fusionner. En effet, des évolutions peuvent avoir eu lieu dans la branche cible entre le moment où la branche à fusionner a été créée et le moment où se fait la fusion. Dans ce cas la fusion directe de la nouvelle contribution ferait apparaître des structures complexes dans l’arbre des branches du dépôt lors de la fusion. Ceci rendrait l’analyse des modifications de la branche cible plus compliquée que si la contribution était apparue de manière linéaire dans l’évolution de la branche en partant du dernier commit présent sur la branche cible.

Vous pouvez retrouver d’autres exemples de cas qui peuvent motiver la restructuration des commits dans la section « On Sausage Making » de cette page.

Pour réaliser ces différentes restructuration de commits, il faut utiliser la commande rebase de Git. Vous pouvez consultez cette page et les références qu’elle contient pour une prise en main rapide de la commande rebase --interactive de Git. La documentation plus complète de rebase est ici. Notez que l’utilisation de rebase peut générer des conflits. Consultez la section correspondante en cas de besoin.

Pour éviter tout risque de perte d’historique en cas de mauvaise manipulation lors de l’utilisation de rebase, il est souvent souhaitable de travailler dans une nouvelle branche contenant vos modifications lors de l’application de rebase, l’ancienne branche conservant ainsi son historique inchangé.

Utilisation des branches

En abondance

Git a été pensé pour permettre très facilement la création et la fusion de branches. Nous vous conseillons donc de les utiliser abondamment. En particulier il est conseillé de réaliser le développement d’une nouvelle fonctionnalité dans une nouvelle branche (la nouvelle branche pouvant éventuellement être supprimée une fois le développement de la fonctionnalité terminé et les modifications fusionnées dans la branche principale).

Si vous avez oublié de créer une nouvelle branche alors que vous avez déjà commencé la modification des fichiers pour implémenter une nouvelle fonctionnalité, utilisez la remise (stash) de Git pour mettre temporairement de côté vos modifications et créer la nouvelle branche.

Nommage

Si vous utilisez effectivement un nombre important de branches, un soin particulier doit être pris dans la façon de nommer les branches pour éviter que le contenu de votre dépôt ne devienne trop confus et désordonné. Pour cela vous pouvez notamment hiérarchiser les branches en utilisant des noms de branche utilisant un / de la forme group/feature. Plus généralement, vous pouvez vous inspirer des bonnes pratiques échangées sur ce fil pour retenir les meilleures conventions pour vos projets.

Modèles de branchement

Diverses approches sont possibles dans la façon d’utiliser les branches dans Git. Vous pouvez retrouver une présentation et une comparaison des trois modèles de branchement les plus couramment préconisés (Git Flow, GitHub Flow, GitLab Flow) à cette adresse afin de définir le fonctionnement le mieux adapté à votre projet.

Nettoyage (suppression, renommage)

Si vous créez de nombreuses branches, il est souhaitable de réaliser une maintenance régulière de votre dépôt pour qu’il reste bien ordonné et pour éviter qu’il ne contienne des branches devenues inutiles.

Pour cela, voici un rappel des commandes permettant de supprimer et de renommer les branches :

  • supprimer un branche locale :
    git branch --delete branch_name
  • supprimer une branche distante (à ne faire que si vous êtes certain que la suppression ne posera pas de problèmes à d’autres utilisateurs du dépôt) :
    git push origin --delete branch_name
  • renommer une branche locale :
    git branch --move old_name new_name
  • renommer une branche distante (à ne faire que si vous êtes certain que le renommage ne posera pas de problèmes à d’autres utilisateurs du dépôt) :
    • d’abord renommer la branche locale :
      git branch --move old_name new_name
    • puis supprimer la branche distante :
      git push origin --delete old_name
    • et pousser la branche renommée :
      git push origin new_name

Gestion des conflits

Lors de l’utilisation de certaines commandes de Git, en particulier les commandes pull, merge et rebase, des conflits demandant une résolution manuelle par l’utilisateur peuvent apparaître. Ces conflits se présentent lorsqu’un même fichier du dépôt à été modifié de manière incohérente entre plusieurs commits et que Git ne peut pas déterminer quelle est la modification qui doit être conservée. Dans ce cas, Git signale dans le terminal qu’un conflit est présent et fait apparaître les conflits dans les fichiers qui posent problème sous une forme décrite dans la documentation de la commande merge.

Les conflits doivent alors être résolus avant de pouvoir continuer le développement. Pour cela on peut directement modifier les fichiers contenant les conflits avec un éditeur de texte, mais cette tâche n’est souvent pas facile. Il est alors plutôt recommandé d’utiliser un outil graphique de fusion qui va faciliter la visualisation, la comparaison et la sélection des différentes versions des portions de code en conflit.

Nous vous conseillons par exemple l’utilisation de meld. Mais de nombreux autres outils comparables existent (opendiff, kdiff3, tkdiff, xxdiff, tortoisemerge, gvimdiff, diffuse, ecmerge, p4merge, araxis, vimdiff, emerge) et certains environnements de développement intégrés peuvent également vous fournir des outils de ce type. Choisissez donc l’outil qui vous convient le mieux.

Comme indiqué dans cette section, notez que vous pouvez configurer dans Git l’outil que vous souhaitez utiliser pour la résolution des conflits, ce qui permet alors de lancer simplement l’outil sur les fichiers à traiter avec la commande :
git mergetool