Fondamentaux de Git pour GitLab
Introduction
Dans le chapitre Introduction à GitLab de cet ouvrage, nous avons défini GitLab comme une plateforme web collaborative construite autour du système de gestion de version Git. Nous avons mentionné aussi que GitLab rend ce dernier plus facile à utiliser tout en offrant un emplacement centralisé pour stocker les dépôts Git sur le Web.
Plus encore, GitLab offre plusieurs autres fonctionnalités non liées à Git qui peuvent être intégrées à ce dernier ou utilisées en parallèle. En fait, GitLab est, en quelque sorte, une enveloppe autour de Git qui le rend plus puissant et plus convivial.
Bien que cet ouvrage ne soit pas consacré à Git, il convient toutefois d’en avoir une bonne compréhension, car GitLab emprunte de nombreux concepts à ce gestionnaire de version.
Si vous connaissez déjà Git, vous pouvez passer certaines sections, mais assurez-vous, d’une part, de bien maîtriser son fonctionnement et, d’autre part, d’être à l’aise avec les notions de branche et de fusion (merge).
Le présent chapitre permet, d’abord, de s’interroger sur le rôle des systèmes de gestion de version tels que Git en montrant comment ils sont essentiels à tout projet de développement. Nous proposons ensuite de faire une présentation...
Qu’est-ce que Git ?
1. Contexte d’émergence de Git
Git est un système de gestion de version (Version Control System, VCS) gratuit et open source qui a été introduit en 2005 par Linus Torvalds dans le cadre du projet de développement du noyau Linux qu’il avait lui-même créé en 1991.
À partir de 2002, le code source de Linux était hébergé gratuitement sur la plateforme Bitkeeper sous une licence « community ». Cependant, le fait d’avoir recours à un gestionnaire de version propriétaire était controversé au sein de la communauté Linux, car plusieurs contributeurs estimaient que ce choix n’était pas conforme aux valeurs du logiciel libre qui permet notamment à quiconque de dupliquer et modifier le code source.

Logo de Git
Lorsque la compagnie BitMover qui offrait la solution Bitkeeper a décidé de mettre fin à la version gratuite en 2005, ce fut l’occasion de développer un nouvel outil qui, par le fait même, pourrait mieux répondre aux besoins d’un projet d’envergure comme celui du noyau Linux.
Il était donc essentiel que la conception d’un nouveau système de gestion de version, en l’occurrence Git, puisse remédier à certains inconvénients de son prédécesseur en insistant...
Les systèmes de gestion de version
Avant d’aborder les différents types de systèmes de gestion de version dits aussi « logiciels de gestion de version » ou « systèmes de contrôle de version » (version control systems), commençons par en donner une première définition.
Un VCS est un outil qui permet de suivre et d’enregistrer l’évolution d’un ou plusieurs fichiers dans le temps tout en donnant la possibilité de restaurer une version antérieure ou de consulter l’historique des modifications.
Pour le dire de façon imagée, un gestionnaire de versions est, en quelque sorte, une machine à voyager dans le temps : elle offre la possibilité de retourner rapidement à une date précise du passé et de revenir dans le présent par la suite.
À propos de Git, la page du manuel que nous venons de consulter précise aussi qu’il s’agit d’un système de gestion de version « distribué » (parfois dit aussi « décentralisé »). Pour comprendre cette distinction, il faut faire une petite incursion dans l’histoire des VCS.
1. Les systèmes de gestion de version centralisés
Les gestionnaires de version introduits dans les années 1990 comme CVS (Concurrent Version System) ou Subversion permettent de stocker les fichiers (et leurs différentes versions) sur un serveur distant qui joue un rôle de point de dépôt centralisé.
En plus de dépendre d’un équipement sur le réseau, ces VCS conservent deux versions des fichiers :
-
la version initiale (lors de la création) ;
-
des versions contentant les différences avec l’état qui précède chaque modification.
a. Une approche basée sur le delta
Cette approche axée sur le delta ou la différence (delta-based version control) peut être illustrée de la manière suivante :

Modification des fichiers d’un VCS centralisé à travers le temps
Dans les VCS centralisés, l’information est stockée comme un ensemble de fichiers initiaux (version 1 : V1) ainsi que des fichiers contenant les différences par rapport...
Installer et configurer Git
Comme nous l’avons mentionné lorsque nous avons examiné la page de manuel sur Git, l’outil se présente sous la forme d’un utilitaire en ligne de commande. Sous Windows il s’agit de Git Bash, un environnement qui émule le shell UNIX, tandis que sous Linux ou macOS, des commandes propres à Git vont s’ajouter pour être utilisées avec Bash (ou d’autres interpréteurs de commandes tels que zsh ou fish).
Lorsque ces commandes sont disponibles, il est possible d’initialiser un nouveau dépôt Git et de versionner son code, comme nous le verrons plus bas. Un certain nombre de composants supplémentaires peuvent être installés avec Git, en particulier sous Windows. Nous allons les présenter à travers les étapes de l’assistant d’installation.
1. Installer Git sur macOS ou Linux
Normalement, Git est déjà installé sur la plupart des distributions Linux et sur macOS. Dans ce cas, il suffit de vérifier s’il existe sur le système avec la commande suivante :
git --version
macOS
Si vous êtes sur macOS et que Git n’est pas installé, cette commande va déclencher l’assistant d’installation. Vous pouvez également utiliser un gestionnaire de packages tel que HomeBrew ou télécharger les sources vous-même à partir du site web suivant : https://git-scm.com/download/mac
Linux
Si vous êtes sous Linux et que Git n’est pas installé, il suffit d’exécuter les commandes suivantes, selon la distribution :
-
Debian, et dérivées :
sudo apt install git-all
-
Fedora, Red Hat Enterprise Linux (RHEL) et dérivées :
sudo dnf install git-all
-
openSUSE, SUSE Linux Enterprise Server (SLES) et dérivées :...
Créer et configurer un dépôt local Git
Commencer à travailler avec Git se fait généralement soit par la création d’un dépôt local ou en clonant un dépôt hébergé sur un serveur distant comme nous apprendrons à le faire avec GitLab.
Git est utilisé de pair avec un éditeur de texte comme Vim ou avec un environnement de développement intégré (IDE) comme Visual Studio, Visual Studio Code, Sublime Text ou Atom.
1. Configuration initiale de Git
Avant de pouvoir versionner des fichiers avec Git, il faut d’abord configurer les options user.name et user.mail qui vont permettre d’identifier l’auteur des commits et faciliter le suivi des modifications. Il faut garder à l’esprit que Git est un outil collaboratif et tout enregistrement d’information comprend obligatoirement le nom de son auteur et, comme nous le verrons plus loin, un message pour décrire ce qui a été fait.
Utilisation du terminal dans Visual Studio Code
Pour mieux visualiser les tâches effectuées dans Git, il est préférable d’utiliser un éditeur de texte (IDE) comme Visual Studio Code qui comprend des fonctionnalités de gestion de version par défaut tout en vous donnant la possibilité d’utiliser un terminal pour exécuter vos commandes. VS Code est très simple à installer et ne nécessite pas de droits d’administrateur. Vous pouvez le télécharger...
Comprendre le workflow de Git
Le workflow Git passe par trois phases qu’il faut maîtriser avant de commencer à versionner son code source.
1. Les trois états des fichiers dans Git
Les fichiers du répertoire de travail (working directory) d’un projet Git (celui où nous avons initialisé le dépôt) peuvent être dans l’un des trois états suivants :
-
Non suivi (Untracked) ou Modifié (Modified) :
-
Non suivi (Untracked) : un ou plusieurs fichiers du répertoire de travail ont été créés (ils ne sont pas encore suivis par Git).
-
Modifiés (Modified) : un ou plusieurs fichiers du répertoire de travail qui sont déjà enregistrés dans Git à la suite d’un commit ont été modifiés (ces nouvelles versions des fichiers ne sont pas encore suivies par Git).
Cette première phase distingue deux types de contenu modifié : les nouveaux fichiers et les fichiers existants modifiés.
-
En staging (staged) : un ou plusieurs fichiers du répertoire de travail ont été ajoutés avec la commande git add et sont maintenant suivis par Git.
-
Enregistré (commited) : le ou les fichiers ajoutés sont enregistrés dans la base de données de Git (sous /.git) avec la commande git commit qui crée un snapshot des changements.

Les 3 états des fichiers dans Git
Pour illustrer ces trois états, prenons l’exemple d’une photo de famille en établissant un parallèle avec le workflow Git :
-
Imaginez que vous êtes photographe et vous devez prendre des clichés d’une famille dont les membres sont devant vous. Cette situation correspond à l’état non suivi : des personnes sont placées dans votre espace de travail.
-
Vous avez des nouveaux fichiers et/ou modifications dans votre répertoire de travail.
-
Vous choisissez, par exemple, les parents seulement pour la première photo et vous les positionnez correctement avant de prendre le cliché. C’est l’étape du staging (ou mise en scène), seules quelques personnes sont retenues pour faire partie de la photo.
-
Vous sélectionnez certains fichiers qui contiennent les modifications désirées et vous...
La notion de commit et le pointeur HEAD
1. Comprendre la notion de commit
Nous avons déjà vu qu’un commit est un snapshot ou un cliché instantané du contenu du répertoire de travail qui a été ajouté préalablement à l’espace de staging. Nous savons qu’un commit comprend un message pour décrire le contenu de ce qui est enregistré, mais d’autres éléments d’informations sont conservés durant cette opération.
Voici les informations (métadonnées) qui sont incluses dans chaque commit :
-
les détails des changements effectués (et les noms et emplacements des fichiers modifiés) ;
-
le nom et l’e-mail de l’utilisateur qui a fait le commit ;
-
un horodatage (timestamp) du commit ;
-
un pointeur vers le commit précédent (ou commit parent) sur la branche en cours (nous verrons cette notion dans la prochaine section).
Dans l’illustration suivante, nous pouvons voir une chaîne de commits avec les pointeurs qui, pour chacun d’entre eux, renvoient au commit parent :

Chaîne de commits dont chacun renvoie à son parent
a. La représentation des commits
Comme on peut le voir sur l’illustration précédente, chaque commit est représenté par une chaîne de caractères (40 en tout) en hexadécimal obtenue grâce à la fonction de hachage SHA-1 (Secure Hash Algorithm) qui est générée lors de l’exécution de la commande git commit -m.
Ce hash est l’identifiant unique de chaque commit et il est stocké dans la base de données objet qui est située dans le répertoire /objects sous /.git. Voici un exemple de ce répertoire sous Windows en mode graphique :

Exemple du répertoire /. git sous Windows
Plus spécifiquement, chaque commit est conservé dans un répertoire qui est généré sous /objects :

Contenu du répertoire /objects sous Windows
Voici un exemple de commit, c’est-à-dire de son identifiant sous la forme d’un hash de 40 caractères :

Exemple du hash de 40 caractères d’un commit
La commande git log permet d’afficher les différents éléments d’information...
La fonctionnalité de branching dans Git
Le branching est la fonctionnalité qui amène une réelle plus-value à Git pour le travail collaboratif en permettant de faire du développement en parallèle.
De manière générale, ce n’est pas une bonne pratique de travailler sur la branche principale (main, master ou autre), à moins d’être le seul contributeur d’un dépôt Git. En fait, cette branche est plutôt considérée comme étant celle de référence, c’est-à-dire celle qui va contenir le code source prêt à être déployé en production.
1. Comprendre la notion de branche
Pour s’assurer de maintenir une branche principale consistante, Git permet de faire du développement non linéaire dans une ou plusieurs branches parallèles qui peuvent être fusionnées lorsque le processus de développement est terminé.
Souvent, les nouvelles branches sont nommées dev ou feature pour le développement d’une nouvelle fonctionnalité à ajouter au code principal d’une application qui réside sur la branche main ou master. Une autre branche pourrait aussi être créée pour quelqu’un qui fait de la documentation ou à des fins expérimentales.
La création de branches parallèles permet notamment d’éviter les conflits dans des situations où plusieurs contributeurs modifieraient le même fichier et tenteraient de l’inclure à la branche principale. Nous verrons plus loin qu’il est possible de mettre à jour son dépôt local Git avant d’envoyer les modifications vers un dépôt partagé, ce qui réduit la possibilité d’avoir des conflits qui arrivent à l’occasion avec Git (nous verrons également plus bas comment les résoudre).
a. Créer une nouvelle branche
Voyons maintenant comment créer une nouvelle branche nommée feature dans notre dépôt avec...
La fusion ou merge de branches dans Git
Une fusion dans Git permet de combiner les modifications de différentes branches en une seule, le plus souvent main (ou master). Cette opération permet d’intégrer les lignes de développement parallèles créées avec la commande git branch dans une branche cible, ce qui crée un historique des commits unifié.
1. Les principaux types de fusion
Il existe plusieurs formes de « merge » dont les trois principaux sont :
-
le fast-forward merge (« fusion vers l’avant ») ;
-
le three-way merge (« fusion à trois voies ») ;
-
le squash and merge (« écrasement et fusion »).
Notons au passage que, pour les merges, les termes anglais sont couramment utilisés en français puisque leur traduction ne reflète pas clairement l’opération effectuée.
Pour explorer ces différents modes de fusion, commençons par supprimer et recréer notre branche feature pour voir le processus depuis le début.
# Faites d'abord un "checkout" vers une autre branche ("main")
$ git checkout main
Switched to branch 'main'
# Supprimez la branche feature
$ git branch -d feature
Deleted branch feature (was eb41526).
# Recréez une branche et déplacez-vous dessus
$ git checkout -b feature
Modifiez vos fichiers à quelques reprises et faites deux commits sur la branche feature selon le workflow que nous avons vu précédemment. Ceci nous permettra de mieux visualiser l’opération de fusion.
L’état de votre dépôt Git ressemblera à l’illustration suivante :

Un dépôt où la branche feature a deux commits de plus que main
Voyons maintenant en quoi consistent les différents modes de fusion.
a. Le fast-forward merge
Un fast-forward merge se produit lorsque la branche principale (main) vers laquelle nous souhaitons faire une fusion n’a pas eu de nouveau commit.
Dans ce cas, Git déplace simplement le pointeur de la branche cible (main) vers le dernier commit de la branche source (ici feature).
Pour faire notre fast-forward merge (et, de manière générale, toute opération...
Conclusion
Dans ce chapitre, nous avons passé en revue le fonctionnement de Git en le replaçant dans le contexte des autres gestionnaires de version de l’époque, notamment ceux dits « décentralisés ». Après avoir présenté l’outil, nous avons vu comment l’installer et nous avons mis en pratique le workflow Git.
Ensuite, nous avons examiné le concept de branche et les principaux types de fusion qui seront particulièrement importants pour la suite de cet ouvrage. Notre parcours s’est terminé sur la notion de rebase et nous avons donné quelques pistes permettant de faire de la résolution de conflits lorsqu’un même fichier a été modifié sur deux branches différentes et qu’un merge est initié.
Dans le chapitre suivant, nous verrons comment utiliser Git pour interagir avec un dépôt distant stocké sur GitLab, ce qui nous amènera à présenter certaines fonctionnalités offertes par la plateforme pour favoriser le travail collaboratif.