3 Git et GitHub

Le contrôle de source consiste à enregistrer l’ensemble des modifications apportées sur les fichiers suivis. Les avantages sont nombreux : traçabilité et sécurité du projet, possibilité de collaborer efficacement, de revenir en arrière, de tenter de nouveaux développements sans mettre en péril la version stable…

3.1 Principes

3.1.1 Contrôle de source

L’outil standard est aujourd’hui git.

Les commandes de git peuvent être exécutées dans le terminal de RStudio.

Capture d’écran du terminal de RStudio. La commande git status supposée décrire l’état du dépôt renvoie une erreur si le projet R n’est pas sous contrôle de source.

Figure 3.1: Capture d’écran du terminal de RStudio. La commande git status supposée décrire l’état du dépôt renvoie une erreur si le projet R n’est pas sous contrôle de source.

La commande git status (figure 3.1) retourne l’état du dépôt (repository), c’est-à-dire l’ensemble des données gérées par git pour suivre le projet en cours.

RStudio intègre une interface graphique pour git suffisante pour se passer de la ligne de commande dans le cadre d’une utilisation standard, présentée ici.

3.1.2 git et GitHub

git est le logiciel installé sur le poste de travail.

GitHub est une plateforme, accessible par le web32, qui permet de partager le contenu des dépôts git (pour travailler à plusieurs) et de partager de la documentation sous la forme d’un site web (GitHub Pages).

Comme GitHub permet au minimum la sauvegarde des dépôts git, les deux sont toujours utilisés ensemble. GitHub n’est pas la seule plateforme utilisable mais la principale. Les alternatives sont Bitbucket33 et GitLab34 par exemple.

3.2 Créer un nouveau dépôt

3.2.1 A partir d’un projet existant

Dans un projet R existant, activer le contrôle de source dans les options du projet (figure 3.2). La commande exécutée est git init. Redémarrer RStudio à la demande.

Activation du contrôle de source dans le menu “Tools > Project Options…”.

Figure 3.2: Activation du contrôle de source dans le menu “Tools > Project Options…”.

Une nouvelle fenêtre Git apparaît dans le panneau supérieur droit. Elle contient la liste des fichiers du projet (figure 3.3).

Fichiers du projet, pas encore pris en compte par git.

Figure 3.3: Fichiers du projet, pas encore pris en compte par git.

A ce stade, les fichiers ne sont pas pris en compte par git : leur statut est un double point d’interrogation jaune. Pour git, le répertoire de travail local est un bac à sable où toutes les modifications sont possibles sans conséquences.

Le fichier .gitignore contient la liste des fichiers qui n’ont jamais vocation à être pris en compte, qu’il est donc inutile d’afficher dans la liste : les fichiers intermédiaires produits automatiquement par exemple. La syntaxe des fichiers .gitignore est détaillée dans la documentation de git35. En règle générale, utiliser un fichier existant : les modèles de documents notamment incluent leur fichier .gitignore.

3.2.2 Prendre en compte des fichiers

Dans la fenêtre git, cocher la case Staged permet de prendre en compte (Stage) chaque fichier. La commande exécutée est git add <NomDeFichier>. Les fichiers pris en compte une première fois ont le statut “A” pour “Added”.

Les fichiers pris en compte font partie de l’index de git.

3.2.3 Valider des modifications

Fenêtre de validation des modifications prises en compte.

Figure 3.4: Fenêtre de validation des modifications prises en compte.

Les fichiers pris en compte peuvent être validés (Commit) en cliquant sur le bouton “Commit” dans la fenêtre Git. Une nouvelle fenêtre s’ouvre (figure 3.4), qui permet de visualiser toutes les modifications par fichier (ajouts en verts, suppressions en rouge). Le grain de modification traité par git est la ligne de texte, terminée par un retour à la ligne. Les fichiers binaires comme les images sont traités en bloc.

Chaque validation (Commit) est accompagnée d’un texte de description. La première ligne est la description courte. Une description détaillée peut être ajoutée après un saut de ligne. Pour la lisibilité de l’historique du projet, chaque commit correspond donc à une action, correspondant à la description courte : tous les fichiers modifiés ne sont pas forcément pris en compte et validés en une fois. La commande exécutée est git commit -m "Message de validation".

Fenêtre de demande d’identification.

Figure 3.5: Fenêtre de demande d’identification.

Les validations sont liées à leur auteur, qui doit être identifié par git. En règle générale, git utilise les informations du système. S’il n’y parvient pas, une fenêtre demande à l’utilisateur de s’identifier avant d’effectuer son premier commit (figure 3.5). Les commandes indiquées sont à exécuter dans le terminal de RStudio. Elles peuvent aussi être utilisées pour vérifier les valeurs connues par git :

git config user.name
git config user.email

Dès la première validation, la branche principale du dépôt, appelée “master”, est créée. Une branche est une version du dépôt, avec son propre historique et donc ses propres fichiers. Les branches permettent :

  • de développer de nouvelles fonctionnalités dans un projet, sans perturber la branche principale qui peut contenir une version stable. Si le développement est retenu, sa branche pourra être fusionnée avec la branche master pour constituer une nouvelle version stable.
  • de contenir des fichiers totalement différents de ceux de la branche principale, pour d’autres objectifs. Sur GitHub, les pages web de présentation du projet peuvent être placés dans une branche appelée “gh-pages” qui ne sera jamais fusionnée.

Le dépôt git est complètement constitué. Dans le vocabulaire de git, il comprend trois arbres (figure 3.6) :

  • le répertoire de travail, ou bac à sable, qui contient les fichiers non pris en compte : inconnus, modifiés, supprimés ou renommés (case Staged décochée) ;
  • l’index, qui contient les fichiers pris en compte (case Staged cochée) ;
  • la tête, qui contient les fichiers validés.

Les trois arbres de git. Source : https://rogerdudler.github.io/git-guide/index.fr.html

Figure 3.6: Les trois arbres de git. Source : https://rogerdudler.github.io/git-guide/index.fr.html

Le statut des fichiers est représenté par deux icônes dans la fenêtre Git de RStudio : deux points d’interrogation quand ils n’ont pas été pris en compte par git. Ensuite, l’icône de droite décrit la différence entre le le répertoire de travail et l’index. Celle de gauche décrit la différence entre l’index et la tête. Un fichier modifié aura donc l’icône M affichée à droite avant d’être pris en compte, puis à gauche après prise en compte. Il est possible, même s’il vaut mieux l’éviter, de modifier à nouveau un fichier pris en compte avant qu’il soit validé : alors, les deux icônes seront affichées.

3.2.4 Créer un dépôt vide sur GitHub

Création d’un dépôt sur GitHub.

Figure 3.7: Création d’un dépôt sur GitHub.

Un dépôt vide sur GitHub doit être créé (figure 3.7) :

  • sur GitHub, cliquer sur le bouton vert “New repository” ;
  • saisir le nom du dépôt, identique à celui du projet R local ;
  • ajouter une description, qui apparaîtra uniquement sur la page GitHub du dépôt ;
  • choisir le statut du dépôt :
    • public : visible par tout le monde ;
    • privé : visible seulement par les collaborateurs du projet, ce qui exclut de compléter par des pages web de présentation.
  • ne pas ajouter de README, .gitignore ou licence : le projet doit être vide ;
  • cliquer sur “create Repository” ;
  • copier l’adresse du dépôt (https://github.com/… ou :…).

Le choix de l’adresse est lié à la méthode d’authentification. L’authentification SSH (voir section 1.4.3) est à privilégier.

3.2.5 Lier git et GitHub

Dans RStudio, un premier commit doit au moins avoir eu lieu pour que la branche principale du projet, nommée “master”, existe. En haut à droite de la fenêtre Git (figure 3.3), il est affiché “(no branch)” avant cela. Ensuite, il est affiché “master”, le nom par défaut de la branche principale du projet. Le projet peut alors être lié au dépôt GitHub.

3.2.5.1 Méthode graphique

Cliquer sur le bouton violet à côté de “master” : une fenêtre apparaît (habituellement utilisée pour la création d’une nouvelle branche, voir section 3.4). Saisir le nom de la branche “master”, cliquer sur “Add Remotes” et compléter :

  • Remote Name : origin ;
  • Remote URL : coller l’adresse du dépôt GitHub ;
  • Cliquer sur “Add”.

Cocher la case “Sync with Remote”.

Au message indiquant qu’une branche master existe déjà, cliquer sur “Overwrite”.

3.2.5.2 En ligne de commande

Plutôt que la manipulation précédente, le lien entre Git et GitHub peut être mis en place par quelques commandes de git exécutées dans le terminal de RStudio. Elles sont affichées sur la page d’accueil de tout dépôt vide nouvellement créé sur GitHub et peuvent donc être copiées et collées directement vers le terminal.

git remote add origin git@github.com:GitHubID/NomDuDepot.git
git branch -M master
git push -u origin master

La première commande déclare le dépôt GitHub comme dépôt distant. Le nom origin est une convention de git. Il peut être modifié mais l’organisation du projet sera plus lisible en respectant la convention. L’adresse du dépôt est https://github.com/GitHubID/NomDuDepot.git si l’authentification HTTPS est choisie.

Les commandes suivantes activent la branche principale du projet et poussent son contenu vers GitHub.

Attention au nom de la branche principale (voir section 3.4) : par défaut, elle s’appelle “master” dans un projet créé dans RStudio mais “main” sur GitHub. Les lignes de commande ci-dessus fournies par GitHub remplacent donc master par main et doivent être corrigées pour correspondre au nom de la branche créée par RStudio.

3.2.5.3 Authentification

Si l’authentification HTTPS est choisie, à la première connexion de RStudio à GitHub, une fenêtre permet de saisir ses identifiants GitHub (figure 3.8).

Identification HTTPS sur GitHub.

Figure 3.8: Identification HTTPS sur GitHub.

Depuis août 2021, GitHub n’accepte plus le mot de passe du compte de l’utilisateur pour cette authentification : le jeton personnel (PAT) créé en section 1.4.4 doit être saisi à sa place.

Si l’authentification SSH est choisie et a été configurée à l’installation de git (section 1.4.3), aucune action n’est nécessaire.

3.2.6 Pousser les premières modifications

La manipulation précédente a automatiquement poussé (Push) les modifications validées sur GitHub. Par la suite, il faudra cliquer sur le bouton “Push” de la fenêtre Git pour le faire.

Sur GitHub, les fichiers résultant des modifications enregistrées par git sont maintenant visibles.

Chaque commit réalisé localement est compté par git et un message “Your branch is ahead of ‘origin/master’ by n commits” affiché dans en haut de la fenêtre Git indique qu’il est temps de mettre à jour GitHub en poussant l’ensemble de ces commits. Cliquer sur le bouton “Push” pour le faire.

A ce stade, le projet doit disposer d’un fichier README.md qui présente son contenu sur GitHub. Son contenu minimal est un titre et quelques lignes de description :

# Nom du Projet

Description en quelques lignes.

Il est conseillé d’utiliser des badges36, à placer juste après le titre, pour déclarer l’état de maturité du projet, par exemple :

![stability-wip](https://img.shields.io/badge/|>
stability-work_in_progress-lightgrey.svg)

3.2.7 Cloner un dépôt de GitHub

Clonage d’un dépôt à partir de GitHub.

Figure 3.9: Clonage d’un dépôt à partir de GitHub.

Tout dépôt sur GitHub peut être installé (on dit cloné) sur le poste de travail en copiant son adresse qui apparaît en cliquant sur le bouton vert (figure 3.9).

Dans RStudio, créer un nouveau projet et, dans l’assistant, choisir “Version Control”, “Git” et coller l’adresse dans le champ “Repository URL”. Le nom répertoire à créer pour le projet est déduit automatiquement de l’adresse. Choisir le répertoire dans lequel celui du projet va être créé et cliquer sur “Create Project”. Le projet créé est lié au dépôt distant sur GitHub.

Pour travailler à plusieurs sur le même projet, le propriétaire du projet doit donner l’accès au projet à des collaborateurs (figure 3.10), c’est-à-dire d’autres utilisateurs GitHub dans les réglages du dépôt (Settings).

Attribution des droits d’accès sur GitHub.

Figure 3.10: Attribution des droits d’accès sur GitHub.

Les collaborateurs sont invités par un message envoyé par GitHub.

3.3 Usage courant

3.3.1 Tirer, modifier, valider, pousser

Toute séance de travail sur un projet commence en tirant (Bouton “Pull”) de la fenêtre Git pour intégrer au dépôt local les mises à jour effectuées sur GitHub par d’autres collaborateurs.

Les modifications apportées aux fichiers du projet sont ensuite prises en compte (cocher les cases Staged) et validées (Commit) avec un message explicatif. Une bonne pratique consiste à valider les modifications à chaque fois qu’une tâche élémentaire, qui peut être décrite dans le message explicatif, est terminée plutôt que d’effectuer des commits regroupant de nombreux changements avec une description vague.

Dès que possible, pousser (Push) les mises à jour pour qu’elles soient visibles par les collaborateurs.

3.3.2 Régler les conflits

Il n’est pas possible de pousser les modifications validées si un collaborateur a modifié le dépôt distant sur GitHub. Il faut alors les tirer pour les intégrer au dépôt local avant de pousser les modifications fusionnées.

Un conflit a lieu si un Pull importe dans le fichier local une modification qui ne peut pas être fusionnée automatiquement parce qu’une modification contradictoire a eu lieu localement. Git considère chaque ligne comme un élément indivisible : la modification de la même ligne sur le dépôt distant et le dépôt local génère donc un conflit.

Git insère dans le fichier contenant un conflit les deux versions avec une présentation particulière :

<<<<<<<<< HEAD # Version importée du conflit
Lignes en conflit, version importée
========= # limite entre les deux versions
Lignes en conflit, version locale
>>>>>>>>> # Fin du conflit

Les lignes de formatage contenant les <<<<, les ==== et les >>>> doivent être supprimés et une seule version des lignes problématiques conservée, qui peut être différente des deux versions originales. La résolution du conflit doit être prise en compte et validée.

Pour limiter les conflits dans un document contenant du texte (typiquement, un document R Markdown), une bonne pratique consiste à traiter chaque phrase comme une ligne, terminée par un retour à la ligne qui ne sera pas visible dans le document mis en forme : un saut de ligne est nécessaire pour séparer les paragraphes.

3.3.3 Voir les différences

Dans la fenêtre Git de RStudio, le menu contextuel (affiché par un clic droit) “Diff” peut être utilisé pour afficher les modifications apportées à chaque fichier (figure 3.11).

Différences entre le répertoire de travail et la tête.

Figure 3.11: Différences entre le répertoire de travail et la tête.

3.3.4 Revenir en arrière

Le menu contextuel “Revert” permet d’annuler toutes les modifications apportées à un fichier (affichées par Diff) et de rétablir son contenu validé la dernière fois (son état dans la tête).

Il n’est pas simple de revenir en arrière au-delà de la dernière validation parce que les modifications ont pu être prises en compte par des collaborateurs : leur suppression rendrait le projet incohérent.

3.3.5 Voir l’historique

Le bouton en forme d’horloge de la fenêtre Git de RStudio affiche l’historique du projet (figure 3.12).

Historique des validations dans le dépôt.

Figure 3.12: Historique des validations dans le dépôt.

En haut se trouve la tête, puis toutes les validations (commits) qui l’ont constituée. Pour chaque validation, les différences de chaque fichier peuvent être affichées en cliquant sur le nom du fichier dans la partie basse de la fenêtre.

3.4 Branches

Les branches d’un projet sont des versions différentes mais simultanées. Un usage typique est le développement d’une nouvelle fonctionnalité. Si son écriture prend du temps, le projet est perturbé par le chantier en cours : le code peut ne plus fonctionner. Si le développement s’avère impossible ou inutile, il faut pouvoir l’abandonner sans dommage. Pour l’isoler pendant sa réalisation et se permettre de le valider ou de l’abandonner à la fin, il faut le placer dans une branche.

La branche principale du projet s’appelle “master” ou “main” à partir de novembre 202037. Elle doit toujours être dans un état stable : c’est elle qui est clonée à partir de GitHub par d’autres utilisateurs éventuels.

Le changement de convention pour le nom de la branche “master” fait qu’à partir de novembre 2020, les projets créés sur GitHub clonés dans RStudio ont pour branche principale “main” alors que les projets créés sur RStudio puis liés à GitHub conservent le nom “master”.

3.4.1 Créer une nouvelle branche

Cliquer sur le bouton violet “New Branch” dans la fenêtre git de RStudio. Saisir son nom et cliquer sur “Create”.

La nouvelle branche est maintenant active.

Les commandes git peuvent aussi être exécutées dans le terminal (pour créer la branche et l’activer) :

git branch new_branch
git checkout new_branch

3.4.2 Changer de branche

Sélectionner la branche à activer dans la liste des branches locales de la la fenêtre git.

Les commits s’appliquent à la branche active. Chaque branche se comporte comme une version différente du projet.

Attention : pour éviter la confusion, sauvegarder les modifications, prendre en compte et valider les changements avant de changer de branche.

3.4.3 Pousser la nouvelle branche

Les premières modifications de la nouvelle branche doivent être poussées en ligne de commande parce que les boutons “Push” et “Pull” de la fenêtre Git ne fonctionnent pas tant que la branche n’existe pas sur le dépôt distant.

Exécuter, dans le terminal :

git push -u origin new_branch

3.4.4 Comportement du système de fichier

A chaque changement de branche, git réécrit les fichiers du projet pour qu’ils reflètent l’état de la branche. Les changements peuvent être observés hors de RStudio, dans l’explorateur de fichier par exemple.

Les fichiers ignorés par .gitignore ne sont pas modifiés. Il est donc indispensable que les fichiers .gitignore des différentes branches soit identiques, sinon des fichiers ignorés dans une branche apparaîtront comme ajoutés dans la branche affichée après un changement.

Les branches de développement ont un contenu proche de celui de la branche principale. Ce n’est pas le cas de branches spécialisées vues plus loin, comme gh-pages (voir section 3.7) qui contient le site web de présentation du dépôt. Il est préférable de ne pas tenter d’afficher ces branches dans RStudio : leur contenu est produit automatiquement et ne doit pas être modifié manuellement. Si c’est indispensable, il faudra y copier le fichier .gitignore de la branche principale et garder à l’esprit que les fichiers ignorés appartiennent en réalité à une autre branche que celle affichée.

3.4.5 Fusionner avec merge

La fusion d’une branche de développement avec la branche principale marque l’atteinte de son objectif : son code va être intégré au projet. L’interface graphique de RStudio ne prévoit pas les fusions, il faut donc utiliser le terminal : tout d’abord, se placer dans la branche cible (possible avec l’interface graphique) :

git checkout master

Ensuite, fusionner :

git merge new_branch

Dans la majorité des situations, la fusion sera automatique (“Fast Forward”). Il est possible que des conflits apparaissent : utiliser la commande git status pour afficher la liste des fichiers concernés, les ouvrir, régler le confit et effectuer un commit.

La branche fusionnée n’est pas supprimée : elles peut être utilisée à nouveau pour d’autres développements ou supprimée manuellement avec la commande suivante :

git branch -d new_branch

3.4.6 Fusionner avec une requête de tirage

L’autre façon de fusionner est plus formelle mais aussi plus générale : elle permet de fusionner une branche dans un dépôt d’un autre utilisateur pour y contribuer, ou de faire valider sa branche par un autre membre de l’équipe dans un projet collaboratif.

Pour contribuer au projet d’un autre utilisateur de GitHub38, il faut commencer par en créer un fork, c’est-à-dire une copie sous la forme d’un dépôt lié à l’original. Il sera possible de tirer les modifications de l’original pour rester à jour39 (par opposition à une simple copie instantanée possible en téléchargeant un Zip du projet) et, à la fin du développement, de fusionner le fork au dépôt original (par opposition à un clone qui ne permettrait pas de contribuer par la suite).

Ensuite, il faut créer une branche de développement comme précédemment, la modifier et finalement demander au propriétaire du dépôt de la fusionner. Ce processus est décrit en détail dans la documentation de git .

Dans le cadre plus simple d’une branche de son propre projet comme dans le cas d’un fork, la branche de développement est prête à être fusionnée. Elle doit avoir être poussée sur GitHub. Sur la page GitHub du projet, un bouton “Create Pull Request” permet de demander la fusion. Un message décrivant les modifications proposées avec leur argumentaire doit être ajouté.

Le propriétaire du projet (les membres de l’équipe dans le cadre d’un projet collaboratif, ou soi-même si l’équipe se réduit à une personne) est averti de la requête de tirage. Sur la page du projet original, il est possible de voir le message, la liste des modifications (chronologie des commits ou comparaison des fichiers), d’engager un discussion avec l’auteur de la requête… Si la requête n’est pas retenue, elle peut être fermée. Si elle est validée, le bouton “Merge Pull Request” permet de fusionner la branche de développement avec la branche “master” (ou une autre) du projet source.

Les requêtes de tirage sont le seul moyen de contribuer à un dépôt sur lequel on ne dispose pas de droits d’écriture. C’est aussi le moyen de fusionner une branche de développement dans sont propre projet en en gardant une trace explicite (dans la rubrique Pull requests de la page GitHub du projet). Dans le cadre d’un projet collaboratif, les propositions d’un membre (auteur de la requête) peuvent être validées par un autre (qui accepte la fusion).

3.5 Usage avancé

3.5.1 Commandes de git

Au-delà de l’usage courant permis par l’interface graphique de RStudio, des manipulations avancées des projets sont permises en utilisant git en ligne de commande. Quelques exemples utiles sont présentés ici.

Un petit guide des commandes est proposé par Roger Dudler40. Il résume les commandes essentielles, donc intégrées à l’interface graphique de RStudio. Des liens vers des références plus complètes sont donnés en bas de la page.

3.5.2 Taille d’un dépôt

Pour connaître l’espace disque occupé par un dépôt, utiliser la commande git count-objects -vH41.

Les données pour ce document au stade de la rédaction sont présentées à titre d’exemple.

$ git count-objects -v
count: 200
size: 2.66 MiB
in-pack: 0
packs: 0
size-pack: 0
prune-packable: 0
garbage: 0
size-garbage: 0

La taille totale est sur la ligne size. Les packs sont une méthode utilisée par git pour réduire la taille du dépôt : des fichiers similaires sont stockés sous la forme d’une partie commune et de différences. La ligne prune-packable donne la taille d’objets stockés à la fois sous forme individuelle et dans des packs. Si leur taille est importante, exécuter git prune-packed pour la ramener à zéro.

La ligne size-garbage donne la taille des objets qui peuvent être supprimés. git gc les supprime, mais pas seulement : il optimise le stockage.

$ git gc
Enumerating objects: 194, done.
Counting objects: 100% (194/194), done.
Delta compression using up to 8 threads
Compressing objects: 100% (188/188), done.
Writing objects: 100% (194/194), done.
Total 194 (delta 83), reused 0 (delta 0)

$ git count-objects -vH
count: 1
size: 5.72 KiB
in-pack: 194
packs: 1
size-pack: 4.00 MiB
prune-packable: 0
garbage: 0
size-garbage: 0 bytes

Ici, la majorité des objets du dépôt a été placée dans un pack (mais sa taille est supérieure à celle des objets individuels).

Il est généralement inutile d’effectuer la collecte des déchets manuellement : git gère bien l’organisation de ses dépôts.

GitHub limite la taille des dépôts. En mai 2020, la limite est de 100 Go. La taille de tous les dépôts d’un utilisateur authentifié peut être affichée dans les réglages de son compte (“Personal Settings”, “Repositories”)42.

3.5.3 Supprimer un dossier

Toutes les modifications apportées à un dépôt sont stockées dans son historique. Il peut être utile d’en supprimer dans quelques cas particuliers :

  • si un fichier contenant des informations confidentielles a été validé par mégarde. La validation de sa suppression ne le retire pas de l’historique, et les informations confidentielles restent visibles en consultant l’historique.
  • si des fichiers volumineux ne sont plus nécessaires, par exemple des fichiers PDF produits par R Markdown (chapitre 4), binaires (donc inadaptés à git) et reproductibles à partir du code.

Typiquement, le dossier docs est utilisé pour stocker les documents produits à partir de code R Markdown. Les fichiers HTML et PDF doivent s’y trouver pour constituer les pages GitHub du projet. Chaque modification du dépôt génère une nouvelle version de ces fichiers dont le volume de l’historique devient rapidement considérable. Une solution efficace consiste à déléguer la création de ces fichiers à un système d’intégration continue (chapitre 6) et à retirer le dossier docs de la branche principale (master) du dépôt. Il faut alors supprimer tout son historique pour récupérer la place qu’il occupe, qui peut être l’essentiel de la taille du dépôt.

Les commandes de suppression complète d’un dossier d’un dépôt son présentées ici43. Le dépôt doit être propre, c’est-à-dire sans modifications non validées, et les versions distantes et locales synchronisées.

Les trois commandes suivantes suppriment complètement le dossier docs de l’historique du dépôt git :

git filter-branch --tree-filter "rm -rf docs" |>
    --prune-empty HEAD
git for-each-ref --format="%(refname)" refs/original/ |>
    | xargs -n 1 git update-ref -d

Le dossier n’est pas supprimé du répertoire de travail. Il doit donc être ajouté au fichier .gitignore pour ne plus être suivi. La modification de .gitignore doit être validée. Ces opérations peuvent être réalisées avec l’interface de RStudio ou en ligne de commande :

echo docs/ >> .gitignore
git add .gitignore
git commit -m 'Removing docs folder from git history'

Le nettoyage du dépôt est nécessaire pour supprimer physiquement les données retirées :

git gc

Enfin, le dépôt doit être poussé. L’option --force implique le remplacement du contenu du dépôt distant par celui du dépôt local : toutes les modifications faites par des collaborateurs sont effacées, c’est pourquoi cette opération de nettoyage implique l’arrêt complet du projet pendant qu’elle a lieu.

git push origin master --force

Ce code peut être utilisé pour supprimer totalement n’importe quel fichier ou dossier d’un dépôt en remplaçant simplement docs dans la commande git filter-branch initiale. La réduction de la taille du dépôt peut être suivie en utilisant git count-objects -vH avant l’opération, avant git gc (la taille du dépôt reste stable mais a été déplacée vers garbage) et à la fin (la taille du dépôt est sensiblement réduite).

3.5.4 Revenir en arrière

Il est possible de restaurer un dépôt dans un état précédent en plaçant sa tête (figure 3.6) au niveau d’un ancien commit. Toutes les modifications ultérieures sont alors détruites. Cette opération ne doit pas être réalisée sur un dépôt partagé : les autres utilisateurs ne pourraient plus pousser leurs modifications.

Afficher l’historique du dépôt et rechercher l’identifiant (SHA) du dernier commit à conserver. Dans le terminal de RStudio, exécuter :

git reset --hard <SHA>
git push -f

Tout l’historique du dépôt après le point de restauration choisi est perdu.

Une méthode moins radicale et utilisable sur un dépôt partagé consiste à exécuter un commit qui annule les modifications d’un autre mais ne détruit aucune donnée de l’historique. Cette opération n’annule qu’un seul commit à la fois et doit donc être répétée pour en annuler plusieurs, en commençant par le plus récent. Dans le terminal de RStudio, exécuter :

git revert <SHA>

Pour annuler le dernier commit, exécuter :

git revert HEAD

Utiliser HEAD évite simplement de rechercher l’identifiant correspondant.

3.6 Données confidentielles dans un dépôt public

Un dépôt public sur GitHub pose problème quand des données utilisées dans le projet ne le sont pas.

Une solution peu satisfaisante consiste à ne pas inclure les données au projet, ce qui le rend non reproductible. Une meilleure solution est de les crypter, en permettant à certains utilisateurs de les décrypter. C’est l’objet du package secret.

Un coffre-fort (dossier vault) est créé dans le projet. Il contient une liste d’utilisateurs autorisés : chacun d’entre eux doit disposer d’une paire de clés de cryptage, une clé publique incluse dans le coffre-fort et une clé privée, gardée secrète. Les données sont cryptées avec toutes les clés publiques disponibles (et donc dupliquées). Les utilisateurs utilisent ensuite chacun sa clé privée pour le décryptage.

Pour ne pas multiplier les copies des données, le propriétaire du dépôt a intérêt à créer un utilisateur générique pour le projet, dont il communiquera la clé privée hors de GitHub. Le coffre contiendra les clés du propriétaire du projet et de l’utilisateur générique seulement. En cas de compromission de la clé privée de l’utilisateur générique, il suffira de le retirer du coffre-fort et d’en créer un nouveau.

3.6.1 Génération d’une paire de clés pour le propriétaire du projet

Les clés sont générées par le logiciel ssh, installé avec git ou par défaut sous Linux.

La procédure est identique à celle de la section 1.4.3, mais la clé utilisée doit être au format RSA (pris en charge par le package secret, contrairement au format ed25519, plus sûr, utilisé pour l’authenfication sur GitHub).

Exécuter la commande suivante dans le terminal de RStudio pour créer une clé RSA :

ssh-keygen -t rsa -b 4096 -C "user.email"

Stocker la clé publique sur GitHub dans “Settings > SSH and GPG Keys”. Repérer la position de la clé : si une clé d’authentification a déjà été enregistrée pour deux postes de travail par exemple, la clé RSA sera la troisième.

3.6.2 Génération d’une paire de clés pour le projet

Générer une clé au format RSA dans le terminal de RStudio :

ssh-keygen -t rsa -b 4096" 
  • Entrer le nom de la clé : <RepoID>.rsa.
  • Ne pas saisir de phrase de validation (mot de passe) pour permettre l’utilisation de la clé sans interaction.

La clé privée <RepoID>.rsa ne doit être diffusée qu’aux ayant-droits du projet. Il faut donc ajouter la ligne *.rsa au fichier .gitignore du projet pour ne pas pousser la clé sur GitHub.

Pour permettre l’intégration continue du projet (chapitre 6), la clé privée doit être stockée comme un secret du dépôt GitHub contenant le projet. Appliquer la procédure de la section 6.2.2 pour créer un secret nommé “RSA” et coller le contenu du fichier <RepoID>.rsa dans le champ “Value” du formulaire.

L’utilisation du secret est décrite dans la section 6.2.5.

3.6.3 Création d’un coffre-fort

Exécuter :

library("secret")
vault <- "vault"
create_vault(vault)

3.6.4 Ajout des utilisateurs

Le propriétaire du projet est ajouté à partir de sa clé publique stockée sur GitHub, qui est la troisième dans notre exemple.

# Identifiant GitHub du propriétaire du projet
github_user <- "EricMarcon"
# Lecture et stockage de la clé, i est le numéro de la clé
add_github_user(github_user, vault = vault, i = 3)

La clé de l’utilisateur générique du projet est ajoutée par :

## Linking to: OpenSSL 1.1.1t  7 Feb 2023
project_id <- "NomDuProjet"
# Lecture de la clé
rsa_project <- read_pubkey(paste0(project_id, ".rsa.pub"))
# Ajout au coffre-fort
add_user(project_id, public_key = rsa_project, vault = vault)

3.6.5 Stockage des données

Les données, stockées dans des variables de R, sont stockées une à une par la fonction add_secret(). Dans l’exemple suivant, la variable s’appelle X et vaut 1.

X <- 1
add_secret(
  # Nom de la donnée
  "X", 
  # Valeur
  value = X, 
  # Utilisateurs autorisés: propriétaire et générique
  users = c(paste0("github-", github_user), project_id), 
  # Coffre-fort
  vault = vault)

Le contenu du coffre-fort peut être vérifié :

# Liste des données du coffre
list_secrets(vault = vault)
##   secret        email
## 1      X github-E....
# Liste des propriétaire de la donnée 'X'
list_owners("X", vault = vault)
## [1] "github-EricMarcon" "NomDuProjet"

Les données seront lues dans le code du projet par la commande get_secret(). La clé privée de l’utilisateur générique du projet, communiquée par un moyen sécurisé aux ayant-droits, doit se trouver dans le dossier du projet.

# Sélection de la clé privée
Sys.setenv(USER_KEY = usethis::proj_path(paste0(project_id, ".rsa")))
## ✔ Setting active project to
## '/Users/runner/work/travailleR/travailleR'
# Lecture de la donnée 'X'
get_secret("X", vault = vault)
## [1] 1

La clé peut être vérifiée :

## [4096-bit rsa private key]
## md5: e81dcb0745a755286c2dc1fc4c6ad117
## sha256: cca11ef82e17c3b77b699e7f3c23e083e8f0f79cb70be8274799f076c44b0c2d

3.7 Pages GitHub

Tout projet sur GitHub doit avoir contenir un fichier README.md pour le présenter. Ce fichier est écrit au format Markdown.

Le fichier peut être placé dans le dossier docs pour fournir à fois la page d’accueil du dépôt et de son site web. Le package memoiR fournit des commandes permettant d’automatiser ces tâches dans les projets de documents. Un dépôt contenant un article écrit en R Markdown (voir section 4.3.2) est utilisé comme exemple44.

Son fichier README.md existe aux deux emplacements : il est écrit par le développeur à la racine du projet et dupliqué dans docs.

3.7.1 Activation

Pour activer les pages GitHub, il faut ouvrir les propriétés du dépôt (Settings) et modifier la rubrique “GitHub Pages” (dans “Options”). Sélectionner la branche du projet et le dossier contenant les pages web, ici : master et /docs. En option, le choix d’un thème personnalise l’apparence des pages.

Le site web est accessible à une adresse45 du domaine github.io.

Le fichier README.md affiché en page d’accueil a un aspect très différent mais le même contenu que celui affiché avec le code sur la page du dépôt dans GitHub.

L’intérêt des pages GitHub est de permettre un accès simple aux documents formatés quand le dépôt contient une production écrite et ou à la documentation des packages R. Ces contenus seront présentés dans le chapitre suivant.

Un site web principal est proposé avec chaque compte GitHub, à l’adresse https://GitHubID.github.io46. Il sera utilisé pour héberger un site web personnel produit par blogdown.

3.7.2 Badges

Les badges sont de petites images, éventuellement mises à jour dynamiquement, qui renseignent rapidement sur le statut d’un projet. Ils doivent être placés immédiatement après le titre du fichier README.md.

Une bonne pratique consiste à indiquer l’avancement dans le cycle de vie du projet. Les badges correspondants sont listés sur le site du Tidyverse47.

Leur code Markdown est le suivant :

![stability-wip]
(https://img.shields.io/badge/lifecycle-maturing-blue.svg)

Le package usethis simplifie leur création en plaçant le code nécessaire dans le presse-papier. Il suffit ensuite de le coller dans le fichier.

usethis::use_lifecycle_badge("maturing")