← Retourner à la liste des articles
Image blog
Auteur

Par Maxime Jumelle

CTO & Co-Founder

Publié le 2 févr. 2022

Catégorie Cloud / DevOps

Git - Tutoriel complet

Que l'on soit Data Scientist, Data Engineer, développeur ou architecte, s'il y a un outil qu'il faut maîtriser, c'est bien Git (prononcé « guite »). Si ce nom est aussi connu, c'est parce qu'il apparaît comme la solution indispensable lorsque l'on collabore à plusieurs sur un projet et est défini comme le standard n°1 des bonnes pratiques de développement.

Git est un système de versions distribué (Distributed VCS pour Version Control System), c'est-à-dire un outil qui permet le contrôle des versions d'un projet, qu'il y ait un ou plusieurs contributeurs. Ce besoin de gérer les versions est d'autant plus renforcé que les environnements sont de plus en plus décentralisés sous forme de microservices, rendant les itérations de développement de plus en plus courtes.

Une introduction à Git

Tout d'abord, qu'est-ce qu'un outil de gestion de versions ? Ces outils, initialement utilisés par les développeurs, sont quasi-exclusivement utilisés pour gérer des codes sources. L'outil est en effet pensé pour suivre l'évolution des lignes de chaque fichier afin de repérer exactement où et quand ont eu lieu les changements.

Ce procédé est justement très puissant : il ne suffit pas versioner l'intégralité du fichier, mais les lignes qui le composent. Cela permet par exemple de travailler à deux sur le même fichier, mais sur des parties de codes différentes. Git va être capable de fusionner conjointement les modifications apportées sans écraser une des deux modifications. Git va donc permettre de suivre l'évolution d'un code source, mais également de travailler à plusieurs dessus.

Il existe deux types principaux outils de gestion de versions.

  • Les outils centralisés : un serveur conserve les anciennes versions des fichiers et les développeurs s’y connectent pour prendre connaissance des fichiers qui ont été modifiés par d’autres personnes et pour y envoyer leurs modifications.
  • Les outils distribués : il n’y a pas de serveur, chaque utilisateur possède l’historique de l’évolution du projet. Les développeurs se transmettent directement entre eux les modifications via peer-to-peer par exemple.

Git est un outil distribué mais avec un ou plusieurs serveurs : plutôt que d'envoyer directement les modifications aux autres utilisateurs, il est possible d'utiliser Git avec plusieurs serveurs distants auxquels les utilisateurs vont s'y connecter.

❓ Mais donc Git, GitHub et GitLab c'est la même chose ?

Non, et c'est une confusion que l'on retrouve souvent lorsque l'on débute avec Git.

  • GitHub et GitLab sont des services d'hébergement de projets Git. Ils ont le rôle de serveur distant qui va héberger un projet Git
  • Git est un outil de VCS distribué. Il va uniquement s'intéresser aux modifications faites dans un projet, car il peut en théorie fonctionner sans serveur distant.

Les fournisseurs Cloud disposent également de services d'hébergement de projets Git. Ils ont également l'avantage de proposer des intégrations avec d'autres services, permettant une approche orientée DevOps.

Pour illustrer les exemples, nous allons créer un compte sur GitHub, qui est très facile à prendre en main.

Dépôts

Les projets versionnés avec Git sont appelés des dépôts (repository). Il s'agit d'une copie d'un projet, que chaque utilisateur possède en local, tout comme le serveur central. Un dépôt est donc en particulier constitué des fichiers du projet, mais contient également d'autres informations que nous allons voir.

Un dépôt peut être local, auquel cas il se situe sur son ordinateur, ou distant, lorsqu'il est stocké sur un serveur distant dont les utilisateurs authentifiés peuvent y avoir accès. Lorsque l'on souhaite débuter un projet avec Git, il y a deux possibilités.

  • Soit en créant un nouveau dépôt vide, par exemple pour commencer un nouveau projet.
  • Soit en clonant un dépôt existant, c’est-à-dire que l'on récupère tout l’historique des changements d’un projet pour pouvoir travailler dessus.

Créons un nouveau dépôt sur GitHub.

Nous attribuons le nom git-test à notre projet avec une description. Nous choisissons une visibilité publique, c'est-à-dire que tout le monde pourra lire le code présent (mais pas le modifier). À noter que sous GitHub, les dépôts privés nécessitent un compte payant.

Ensuite, nous pouvons choisir d'initialiser le dépôt avec plusieurs fichiers.

  • Le fichier README.md est l'équivalent du « lisez-moi », permettant de présenter le projet et d'y fournir des instructions pour installer/exécuter.
  • Le fichier .gitignore permet de spécifier les dossiers et fichiers à ne pas considérer dans le dépôt Git. Par exemple, on ne souhaite pas mettre dans le dépôt Git un fichier qui contiendrait des mots de passe.
  • Le fichier LICENSE est utile dans le cas des dépôts publics avec des licences open-source.

Une fois sélectionné, nous pouvons créer le dépôt.

Nous avons bien les deux fichiers présents comme demandés lors de la création. Maintenant, nous allons récupérer ce dépôt en local. Pour cela, nous pouvons cliquer sur le bouton Code puis copier la commande git à exécuter dans un terminal.

git clone https://github.com/XXXXXXXXX/git-test.git
Cloning into 'git-test'...
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (4/4), 1.59 KiB | 326.00 KiB/s, done.

Nous avons bien récupéré tous nos fichiers. À noter qu'il y a un dossier nommé .git : ce dernier contient tous les fichiers nécessaires au dépôt, aussi bien des copies de code que des journaux ou des informations diverses.

Pour créer un dépôt Git en local, il suffit de se diriger dans le dossier contenant le code source et d'exécuter la commande git init.

Il est maintenant possible de commencer à développer.

Commits

À ce stade, nous n'avons pas encore apporté de modifications. C'est à partir de maintenant que les choses sérieuses vont commencer. Lorsque nous allons commencer à ajouter et modifier des fichiers, nous allons rentrer dans un cycle de développement.

Dans ce cycle, nous allons ajouter ou supprimer des fichiers, ajouter des lignes de codes dans un fichier A puis dans un fichier B sans toucher au fichier C. L'objectif de Git est maintenant de savoir quelles ont été précisément les modifications apportées.

C'est le rôle du commit. Au préalable, nous devons indiquer à Git quels sont les fichiers qu'il doit suivre, c'est-à-dire ceux dont il doit à chaque fois vérifier quels ont été les changements. On appelle cela le tracking.

Pour ajouter des fichiers au tracking Git, nous utilisons la commande git add suivi d'un fichier ou d'un dossier. Prenons la commande suivante.

git add .

Pour rappel, . fait référence au répertoire courant : nous traquons (suivons) tous les fichiers du dossier actuel (sauf ceux mentionnés dans le fichier .gitignore). Cette opération n'est pas faite qu'une seule fois pour chaque fichier, puisqu'une fois tracké, il sera automatiquement dans le viseur de Git.

Ajoutons un fichier python nommé code.py qui va contenir le code suivant (on peut faire nano code.py si l'on reste uniquement dans le terminal, même s'il est plus pratique d'utiliser Visual Studio Code).

from datetime import datetime

print("Hello ! Il est {}.".format(datetime.now().strftime("%H:%M:%S")))

Ajoutons maintenant ce fichier au tracking Git avec git add . (ou juste git add code.py).

Nous allons maintenant dire à Git que ce fichier a été modifié avec un commit. Pour commit, nous avons besoin de deux informations.

  • L'utilisateur qui fait le commit, c'est-à-dire son nom et adresse mail.
  • Le message associé au commit.

Le message de quelques mots permet d'indiquer aux autres utilisateurs la raison du commit. Essayons de créer un commit.

git commit -m "Ajout du fichier code.py"
*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: unable to auto-detect email address (got 'jovyan@ba60e5f3ddb9.(none)')

Comme nous pouvons le voir, Git n'est pas très content ! Et c'est normal, puisque nous n'avons pas dit qui nous sommes. Pour pouvoir commit, il manque nos informations utilisateur. Pour cela, exécutons les deux commandes suivantes.

git config --global user.email "adresse@mail.com"
git config --global user.name "Prénom Nom"

Relançons à nouveau le commit.

git commit -m "Ajout du fichier code.py"
[main 261b4e4] Ajout du fichier code.py
 1 file changed, 3 insertions(+)
 create mode 100644 code.py

Les modifications ont correctement été apportées. Regardons un peu plus en détails avec la commande git log.

commit 261b4e4532a4dcac3d71cd44af91090ae73272ae (HEAD -> main)
Author: Maxime Jumelle <adresse@mail.com>
Date:   Wed Feb 10 10:24:33 2021 +0000

    Ajout du fichier code.py

commit 0ed9a1b172909ba4f69139a500d671b004a141a6 (origin/main, origin/HEAD)
Author: Maxime Jumelle <adresse@mail.com>
Date:   Wed Feb 10 10:48:54 2021 +0100

    Initial commit

Cette commande permet de retracer l'historique des commits. Ici, nous voyons qu'un identifiant SHA est attribué à chaque commit (261b4...).

Attention toutefois, un commit ne modifie pas le dépôt distant ! Il n'enregistre que les modifications en local. Si l'on souhaite l'envoyer vers le dépôt distant, nous devons faire un push.

git push origin main
Username for 'https://github.com': XXXXXXXXX
Password for 'https://XXXXXXXXX@github.com':
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 410 bytes | 410.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To https://github.com/XXXXXXXXX/git-test.git
   0ed9a1b..261b4e4  main -> main

Pour pouvoir push, nous devons spécifier deux informations.

  • Le serveur distant, référencé par l'alias origin. Il s'agit de l'alias par défaut avec Git pour un serveur distant.
  • La branche (notion que nous allons aborder juste après) sur laquelle nous allons pousser les nouvelles références (modifications).

Lors d'un push, il est nécessaire de s'authentifier pour avoir les droits d'écriture sur le dépôt distant.

Lorsque l'on tape le mot de passe, rien ne s'affiche à l'écran car il est caché pour des raisons de sécurité, mais il est bien pris en compte dans le terminal.

Si l'on retourne sur GitHub, nous devrions voir les nouvelles références apportées.

Et voilà ! Nous venons de faire notre premier push ! 😎

Les branches

Une des fonctionnalités les plus puissantes de Git est incontestablement celui des branches. Pour bien comprendre leur intérêt, revenons sur les cycles de développement des applications.

Prenons comme exemple un site Web et considérons qu'il est actuellement en ligne avec la version la plus récente. Toutes les semaines, le site Web doit être mis à jour pour lui ajouter un article de blog au format HTML. Ainsi, les développeurs doivent effectuer un commit chaque semaine pour ajouter les nouvelles modifications.

Or, en parallèle, on souhaite effectuer une refonte visuelle du site Web, mais cette refonte va prendre plusieurs semaines ! Comment travailler en parallèle sur cette refonte sans poser de conflits avec la version actuellement en ligne qui doit être mise à jour avec les nouveaux articles de blog chaque semaine ?

C'est là qu'interviennent les branches. La branche principale main contient la version en ligne. Chaque semaine, un commit est effectué sur la branche main. Pour pouvoir travailler sur la refonte visuelle, les développeurs vont créer une nouvelle branche nommée refonte qui sera dupliquée à partir de la branche main. Ainsi, les développeurs pourront travailler en parallèle sur la refonte visuelle tout en pouvant mettre à jour continuellement la version en ligne.

git status
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean

Nous sommes bien sur la branche main. Créons une nouvelle branche refonte à partir de la branche main avec la commande git checkout -b.

git checkout -b refonte
Switched to a new branch 'refonte'

Nous sommes à présent sur la branche refonte comme le confirmera git status. Nous allons dans un premier temps ajouter le fichier module.py.

from datetime import datetime

def obtenir_temps():
    return "Hello ! Il est {}.".format(datetime.now().strftime("%H:%M:%S"))

Puis nous allons modifier le fichier code.py.

from module import obtenir_temps

print(obtenir_temps())

Effectuons un commit sur cette branche.

git add .
git commit -m "Nouvelle branche"
[refonte d1cbd09] Nouvelle branche
 2 files changed, 6 insertions(+), 2 deletions(-)
 create mode 100644 module.py

Il ne reste plus qu'à faire un push pour mettre à jour le dépôt distant.

git push origin refonte
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 8 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 509 bytes | 509.00 KiB/s, done.
Total 4 (delta 0), reused 0 (delta 0)
remote:
remote: Create a pull request for 'refonte' on GitHub by visiting:
remote:      https://github.com/XXXXXXXXX/git-test/pull/new/refonte
remote:
To https://github.com/XXXXXXXXX/git-test.git
 * [new branch]      refonte -> refonte

Sur GitHub, nous pouvons maintenant sélectionner une branche sur GitHub.

Sur cette nouvelle branche, nous voyons les modifications apportées.

En parallèle, retournons sur la branche main.

git checkout main

Un checkout sans argument nous permet de changer de branche. APrès ce checkout, le fichier module.py disparaît car il n'est pas présent dans la branche main. Modifions le fichier README.md.

# Test Git

Nous travaillons sur les branches de Git !

Là-aussi, mettons à jour les références vers le dépôt distant.

git add .
git commit -m "Mise à jour du README"
git push origin main

Fusion de branches

Supposons dorénavant que la refonte visuelle soit terminée. Comment allons-nous rapatrier le contenu mis à jour de la branche refonte sur la branche main sans écraser les modifications faites depuis sur cette même branche depuis la création de refonte ?

En particulier, nous avons modifié le fichier README.md dans la branche main, or nous n'y avons pas touché dans la branche refonte. Et encore une fois, Git est très puissant, car lors de la fusion d'une branche vers une autre, il va détecter les lignes non modifiées et ne pas écraser le fichier README.md. Il faut garder à l'esprit que Git s'intéresse toujours au contenu le plus récent : il va donc récupérer le fichier module.py, mettre à jour le code code.py et ne pas modifier README.md.

Pour cela, nous devons nous positionner sur la branche qui va recevoir la fusion (ici la branche main), puis lancer la commande suivante.

git merge refonte

À ce moment là, un éditeur de texte (Vim) nous demande de spécifier un message pour cette fusion. Pour pouvons laisser le message par défaut et taper sur les touches (dans l'ordre) :wq (pour write and quit).

Merge made by the 'recursive' strategy.
 code.py   | 4 ++--
 module.py | 4 ++++
 2 files changed, 6 insertions(+), 2 deletions(-)
 create mode 100644 module.py

Si notre fusion s'est bien passée, nous avons dorénavant les trois fichiers, et nous pouvons faire un push vers le dépôt distant.

git push origin main

Tous nos fichiers sont maintenant présents et à jour sur la branche main.

Les branches sont donc très utiles pour développer de nouvelles fonctionnalités ou pour séparer les codes sources de développement et de production.

Pour aller plus loin avec Git, le livre Pro Git est accessible en ligne et couvre de très nombreux aspects.

Vous souhaitez vous former au Cloud / DevOps ?

Articles similaires

Blog

28 févr. 2024

Cloud / DevOps

Pour de nombreuses entreprises, innover chaque jour en proposant des applications à ses utilisateurs est un sujet primordial. Pour autant, cette course au déploiement continu de nouvelles applications nécessite des compétences bien particulières sur les architectures Cloud, l'automatisation de projets et la supervision. C'est à partir de ce moment qu'intervient le rôle de l'ingénieur DevOps dans les entreprises.

Maxime Jumelle

Maxime Jumelle

CTO & Co-Founder

Lire l'article

Blog

23 févr. 2024

Cloud / DevOps

Dans le monde du DevOps, les conteneurs sont rapidement devenus des incontournables, aussi important que les machines virtuelles. Des plateformes de conteneurisation comme Docker ont permis de simplifier et d'accélérer la création d'image et l'exécution de conteneurs sur différents systèmes, à portée de tous.

Maxime Jumelle

Maxime Jumelle

CTO & Co-Founder

Lire l'article

Blog

16 févr. 2024

Cloud / DevOps

Dans l'approche GitOps, il existe de nombreux outils permettant d'exécuter des pipelines CI/CD : certains se concentrent uniquement sur la partie intégration continue, d'autres avec le déploiement en plus. S'il y en a un qui est considéré comme l'un des plus matures et des plus robustes, c'est bien GitLab.

Maxime Jumelle

Maxime Jumelle

CTO & Co-Founder

Lire l'article