Chapitre 2 Contrôle de version avec git et GitHub: historique de changement, développement collaboratif et intégration continue

Nous nous intéressons ici aux solutions proposées par RStudio et GitHub pour le contrôle de version de projets, l’hébergement de vos projets et l’automatisation d’un certain nombre de vérifications garantissant un partage facile de votre code.

2.1 Principe du contrôle de version

Le principe du contrôle de version est d’enregistrer les changements successifs apportés à des fichiers (notamment des fichiers .R).

RStudio propose 2 solutions intégrées pour le contrôle de version :

  • git

  • svn (“subversion”)

2.1.1 git

git est un logiciel de contrôle de version (c’est-à-dire un outils qui va enregistrer l’histoire des changements successifs de votre code et permettre de partager ces changements avec d’autres personnes). git est un logiciel en ligne de commande, et sa prise en main n’est pas nécessairement intuitive.

git fonctionne de la façon suivante : sur un serveur distant (par exemple dans le cloud), une version à jour du code est disponible. À tout moment il est possible d’accéder à cette version du code en ligne. Chaque contributeur peut télécharger cette dernière version à jour (dans une action que l’on dénomme pull), avant de l’éditer localement. Une fois ses changements effectués, le contributeur peut alors mettre à jour la version en ligne du code afin que ses changements soient disponibles pour tout le monde (dans une action que l’on dénomme push)

NB : git a été pensé pour des fichiers légers (comme par exemple des fichiers texte) et est loin d’être optimisé pour des fichiers trop lourds et/où compressés.

Artwork CC-BY Allison Horst
Artwork CC-BY Allison Horst

2.1.2 subversion

subversion est l’autre solution disponible dans RStudio. Elle fonctionne de manière similaire à git, mais avec des fonctionnalités un peu plus réduites que nous détaillons pas ici (la différence majeure est que tout les contributeurs travaillent simultanément sur la même version du code).

2.2 Utiliser git localement depuis RStudio

👉 À vous de jouer !

  1. Commencer par activer git depuis l’onglet “Git/SVN” de “Project Options” situé dans le menu “Tools” et suivre les instructions. Vous pouvez aussiplutôt utiliser usethis::use_git()

  2. À partir de l’onglet “Git” maintenant apparu à côté de l’onglet “Build”, enregistrer l’état actuel de votre package en réalisant votre premier “commit” :

  • 2a. sélectionner les fichiers à suivre (ne pas sélectionner le fichier .Rproj)

  • 2b. écrire un message informatif (pour vos collaborateurs - ce qui inclut votre futur vous)

  • 2c. cliquer sur “Commit”

  1. Ajouter une ligne “*.Rproj” au fichier “.gitignore” et effectuez un nouveau commit

  2. Visualiser les changements et leur historique à l’aide des outils de visualisation “Diff” et “History” accessible depuis l’onglet “Git”

Artwork CC-BY Allison Horst
Artwork CC-BY Allison Horst

2.2.1 Bonnes pratiques du commit

Idéalement, chaque commit ne devrait régler qu’un seul problème. Il devrait le régler dans son intégralité (être complet) et ne contenir des changements relatifs qu’uniquement à ce problème (être minimal). Il est alors important d’écrire des messages de commit informatifs (pensez à vos collaborateur, qui incluent votre futur vous). Il faut également être concis, et décrire les raisons des changements plutôt que les changements eux-mêmes (visibles dans le Diff).
NB : Il est parfois difficile de respecter ces directives à la lettre, et celles-ci ne sont qu’un guide et ne doivent pas vous empêcher d’effectuer des commits réguliers.

Par ailleurs, la tentation d’avoir un historique de changements “propre” et bien ordonné est naturelle, mais se révèle une source de problèmes inutiles. Elle entre en contradiction avec l’objectif de traçabilité du contrôle de version. Le développement de code étant généralement un processus intellectuel complexe et non linéaire, il est normal que l’enregistrement des changements reflète ce cheminement. En pratique, votre futur-vous sera le premier utilisateur de votre historique de changements et la priorité est donc de vous faciliter la tache dans le futur lors de la résolution de bug où l’extension de fonctionnalités.

Artwork CC-BY Allison Horst
Artwork CC-BY Allison Horst

2.3 GitHub

GitHub est un site internet proposant une solution d’hébergement de code en ligne, et s’appuyant sur git. Il existe de nombreux sites web et services (GitLab, Bitbucket, …) permettant d’héberger du code et s’appuyant sur git. GitHub est très populaire dans la communauté des développeurs , et est relativement facile à utiliser, même pour un utilisateur novice.

Les avantages d’utiliser GitHub sont :

  • une interface graphique simple pour suivre l’historique des changements de votre code

  • la dernière version de développement de votre code est disponible en ligne et vous pouvez la référencer (on peut même référencer un numéro de commit précis pour geler une version spécifique du code)

  • les utilisateurs disposent d’un canal clair et transparent pour signaler les bugs/difficultés

  • cela facilite grandement le développement collaboratif

2.3.1 Mettre son package sur GitHub

👉 À vous de jouer !

  1. Sur le site https://github.com/, se créer un compte GitHub (si vous hésitez, une convention courante est d’utiliser prénomnom comme nom d’utilisateur)
  2. Vous pouvez ensuite executer usethis::use_github() dans la console et vous laisser guider.
  3. Ajouter un fichier “README.Rmd” à votre package afin de disposer d’une belle page d’accueil sur GitHub :
    • 3a. dans , executez la commande usethis::use_readme_rmd()
    • 3b. à l’aide de l’outils “Diff” de l’onglet “Git” de RStudio, étudier les changements opérés par la commande précédente
    • 3c. éditez le fichier “README.Rmd” créé, puis créer le fichier README.md correspondant en executant knitr (cliquer su la pelotte de laine “Knit” en haut à gauche dans Rstudio), avant d’effectuer un 3e commit contenant ces changements
    • 3d. à ce stade, si vous visitez la page de votre répertoire sur GitHub, votre 3e commit n’apparait pour l’instant pas. Il faut synchroniser le répertoire GitHub en ligne avec votre dossier local. Pour cela, directement depuis RStudio, cliquer sur “Push” depuis l’onglet “Git”. Maintenant, les changements du 3e commit sont visibles en ligne sur GitHub.

2.4 Collaboration pour la production du code

Artwork CC-BY Allison Horst
Artwork CC-BY Allison Horst

git et GitHub sont particulièrement efficaces lorsque plusieurs personnes collaborent pour développer un code. En effet, chacun peut effectuer des pull et push successifs pour apporter des changements au code, de manière simultanée et en étant sûr de toujours travailler sur la dernière version. Nous allons voir différents concepts utiles dans le cas d’un tel travail collaboratif.

👉 À vous de jouer !

  1. En formant des groupes de 2, vous allez chacun ajouter votre binome comme “collaborator” à votre repertoire GitHub à partir de l’onglet “Settings” (sur GitHub).

  2. Quelques instants plus tard le collaborateur ainsi ajouté reçoit un email l’invitant à accepter l’ajout. Cliquer sur le lien et accepter.

  3. Dans RStudio, créer un nouveau projet “Version control” à partir de l’url https du répertoire de votre binôme sur GitHub.

2.4.1 Branches

Une des fonctionnalités assez utile de git est les branches. Cela permet d’opérer des changements importants dans le code sans perturber le fonctionnement actuel. C’est notamment utile pour explorer une piste de développement dont on ne sait pas si elle sera concluante au final.

D’ailleurs, vous utilisez déjà les branches depuis le depuis de cette partie. En effet, la branche par défaut est appelé “main” (ou parfois “master”).

Grâce à ce système de branches, on obtient un arbre des différents commits au cours du temps (où les nœuds correspondent à la séparations des branches).

2.4.2 Merge

Un pull se décompose en 2 actions de la part de git :

  1. tout d’abord un fetch, qui correspond au téléchargement du code en ligne

  2. suivi d’un merge qui fusionne la version locale avec les changements.

Après avoir conduit un développement expérimental dans une branche, on peut vouloir merger ces changements dans la branche “master” par exemple, après que l’expérience se soit révélée concluante.

Si un les changements concernent des parties distinctes du code, alors le merge peut s’effectuer sans problème. En revanche si les 2 versions à merger comportent des changements depuis leur dernier commit commun qui concerne les mêmes lignes de codes, alors on va rencontrer un (ou des ) conflit(s), qu’il va falloir résoudre.

2.4.3 Les conflits

Prenons l’exemple suivant : le développeur \(D_1\) et le développeur \(D_2\) on tous les 2 pullé la version v0.1 du code à l’instant \(t\) sur leur machine respective. Ils travaillent chacun indépendamment pour apporter des changements au code. Au moment de pusher ses changements, le développeur \(D_2\) reçoit un message d’erreur :

"Sync Error.  
Please resolve all conflicted files, commit, then try syncing again."

Chaque fichier à la source source d’un conflit a alors été automatiquement édité comme suit :

<<<<<<< HEAD
code dans votre version local
=======
code en ligne
>>>>>>> remote

Pour résoudre le conflit, il faut alors éditer chaque fichier un à un en choisissant s’il faut conserver la version locale ou bien celle en ligne, avant de pouvoir commiter à nouveau et enfin de pusher vos changements avec succès.

👉 À vous de jouer !

  1. Modifiez le fichier README.Rmd de votre binome, puis commitez votre changement et pushez le.
  2. une fois que votre binôme a modifié votre README.Rmd, modifiez à votre tour le fichier à la même ligne, SANS puller les changements de votre binôme au préalable ! Commitez et essayez de pusher ces changements.
  3. Résolvez le conflit.

NB: Dans la vraie vie, on cherche à éviter cette situation et donc on va toujours puller avant de pusher. Ici, nous faisons volontairement le contraire pour donner un exemple et démystifier les conflits.

2.4.4 Fork

L’action fork permet de créer une copie qui vous appartient à partir d’un code disponible. Ainsi le code original ne sera pas impacté par vos changements. Cela revient à créer une branche, et la séparer de l’arbre pour pouvoir en assumer la propriété. On aurait aussi pu appeler cette action une “bouture”…

Cette action est principalement utile dans le cadre des pull requests.

2.4.5 Pull request

Il s’agit du moyen le plus facile de proposer des changements dans un code dont vous n’êtes pas collaborateur. GitHub propose une interface graphique facilitant leur traitement.

👉 À vous de jouer !

  1. Modifiez le README.Rmd de votre voisin qui n’est pas votre binôme après avoir forké son package.

  2. Proposez votre changement sous la forme d’une pull request depuis l’onglet “Pull requests” sur la page GitHub du répertoire de votre voisin.

  3. Acceptez la pull request de votre voisin sur la page GitHub de votre répertoire, puis faire le merge.

2.4.6 Issues

Pour n’importe quel répertoire GitHub, vous pouvez poster un commentaire sous forme d’issue afin d’alerter les développeurs sur un éventuel bug, ou une question sur l’utilisation du package, ou encore demander une fonctionnalité supplémentaire…

L’idéal est de proposer vous-même une pull request qui résout votre issue lorsque vous le pouvez (i.e. en avez les capacités et le temps).

👉 À vous de jouer !

  1. Utilisez usethis::use_github_links() afin d’ajouter les 2 lignes suivantes au fichier DESCRIPTION de votre package
    URL: http://github.com/*prenom.nom*/mypkg
    BugReports: http://github.com/*prenom.nom*/mypkg/issues

  2. Visualisez les nouveau changements, puis commitez les.

  3. Créez une issue sur le projet de votre binome

2.5 Intégration continue

À chaque changement, à chaque commit donc, il y a la possibilité d’introduire 1 (ou plusieurs) bugs qui vont empêcher le package de passer le CRAN check. Si l’on accumule trop de ces bugs, au moment de soumettre la nouvelle version, il peut y avoir beaucoup de corrections à apporter. C’est d’autant plus frustrant si le package passait le CRAN check auparavant…

Les services d’intégration continue permettent de checker votre package automatiquement après chaque commit ! En cas d’échec, vous recevez un mail qui vous en informe. Un certain nombre de ces services proposent une offre limitée gratuite pour les projets open-source.

Une autre raison d’utiliser l’intégration continue est qu’elle permet de tester votre package sur des infrastructures différentes de la votre (e.g. Windows, Ubuntu, Mac OS) et pour différentes versions de (current, devel…)

2.5.1 GitHub Actions

Les GitHub Actions permettent de lancer des actions automatiquement à chaque fois que vous pushez sur GitHub La commande usethis::use_github_action("check-standard") permet d’initialiser les Github Actions, et d’ajouter l’action R CMD CHECK du package.

👉 À vous de jouer !

  1. Executer la commande usethis::use_github_action("check-standard") et commiter les changements et regardez ce qu’il se passe sur la page GitHub

  2. Ajouter un badge à votre README.md grâce au code obtenu dans la console et commiter ces changements

N’hésitez pas à consulter la page suivantes qui renseigne sur les différentes GitHub Actions disponibles pour les pacakges : https://github.com/r-lib/actions/blob/v2-branch/examples/README.md

2.6 Construire et déployer simplement un site web pour accompagner son package

Le package pkgdown permet de générer automatiquement un site web attrayant rassemblant la documentation de votre package (y compris les Vignettes).

👉 À vous de jouer !

  1. Executer la commande usethis::use_pkgdown() dans la console .

  2. Commiter et pusher les changements. Rendez-vous sur l’onglet Actions de votre répertoire sur GitHub et constater les nouveautés.

👉 À vous de jouer !

Examiner les changement du fichier DESCRIPTION suite à l’execution des différentes commandes usethis::use_... précedemment.

Modifier le champ URL du fichier DESCRIPTION.

Artwork CC-BY Allison Horst
Artwork CC-BY Allison Horst

2.7 Références additionnelles

Annexe 2.1 : R-hub

Le R consortium met à disposition le R-hub builder, – et a pour ambition de pouvoir un jour proposer un service d’intégration continue spécialement dédié aux packages .

R-hub builder utilise exactement la même infrasrtructure que les serveurs du CRAN, ce qui a l’avantage de pouvoir reproduire exactement le R CMD CHECK tel qu’effectué par le CRAN. Il est possible de l’utiliser grâce à la fonction devtools::check_rhub().

Annexe 2.2 : couverture du code

Le package covr propose une solution pour mesurer la couverture des tests unitaires associés à un package. La couverture de test détermine la proportion du code source qui est effectivement utilisée lors de l’exécution des tests unitaires. La mesure de la couverture du code renforce la fiabilité d’un code et donne confiance à ses utilisateurs potentiels.

👉 À vous de jouer !

  1. Executer la commande usethis::use_coverage(), ajouter un joli badge à votre README.md grâce au code obtenu dans la console .
  1. Commiter ces changements.

Pour plus d’information n’hésitez pas à consulter la vignette de covr.