Objectifs de certification
DEVASC 200-901
Gestionnaire de version Git
Dans le cadre de l’Infrastructure as Code, DevOps, du déploiement d’applications par l’orchestration de conteneurs sur du cloud hybride, etc., les ressources et leur configuration sont présentées sous forme de code source. L’hébergement du code source dans un référentiel Git est souvent un pré-requis et au minimum une bonne pratique de gestion.
1. Gestionnaires de version
La gestion de versions (en anglais : version control ou revision control) consiste à gérer l’ensemble des versions d’un ou plusieurs fichiers (généralement en texte). Essentiellement utilisée dans le domaine de la création de logiciels, elle concerne surtout, mais pas nécessairement, la gestion des codes source.
1.1. Code source
Le code source est un ensemble de codes écrits généralement en texte brut dans un langage de programmation conçu et lisible par des humains. Le code source d’un programme indique les actions à effectuer par un ordinateur. Le code source est souvent transformé par un compilateur en code machine binaire qui peut être exécuté par un ordinateur. Le code machine peut ensuite être stocké pour être exécuté ultérieurement. Alternativement, le code source peut être interprété et donc exécuté immédiatement.
1.2. Gestionnaires de version centralisés
Avec les logiciels de gestion de versions centralisée, comme CVS et Subversion (SVN), il n’existe qu’un seul dépôt des versions qui fait référence, sur un serveur central.
1.3. Gestionnaires de version distribués
La gestion de versions décentralisée permet à chacun de travailler à son rythme, de façon désynchronisée des autres, puis d’offrir un moyen à ces développeurs de s’échanger leur travaux respectifs.
En effet, il existe plusieurs dépôts pour un même code. Les clients n’extraient plus seulement la dernière version d’un fichier, mais ils dupliquent complètement le dépôt.
Par exemple, GNU Arch, Git et Mercurial sont des logiciels de gestion de versions décentralisés.
2. Git
Git est une implémentation open source d’un système de contrôle de version distribué créé par Linus Torvalds, l’auteur du noyau Linux.
2.1. Avantages de Git
Parmi ses nombreux avantages, on peut citer :
- Facilité d’apprentissage
- Gestion de tous les types de projets, y compris les projets de grandes entreprises
- Performances rapides
- Conçu pour les projets collaboratifs
- Flexible
- Faible empreinte
- Dispose de tous les avantages d’un système de contrôle de version distribué
- Gratuit
2.2. Installation d’un client Git
Un client Git doit être installé sur la machine cliente. Il est disponible pour macOS, Windows et Linux/Unix. Bien que certains clients Git viennent avec une interface graphique de base, Git se concentre sur l’interface de ligne de commande.
On trouvera les binaires et les méthodes d’installation sur le site Git-SCM ainsi que des interfaces graphiques (GUI).
Pour Windows on conseillera volontiers l’installation de l’implémentation pour Windows de Git “Git for Windows”.
Pour une expérience native sous Windows qui se rapproche de l’expérience Linux, on conseillera Windows Terminal à installer à partir du Microsoft Store et le gestionnaire de paquets Chocolatey :
choco install git.install
Sur les systèmes Unix/Linux :
{yum,dnf,apt,brew} install git
Pour la suite des exercices, les logiciels suivants sont nécessaires :
{yum,dnf,apt,brew} install -y vim curl unzip
3. Configuration de Git
La comportement de Git est contrôlé par la commande git config
sous forme de variables.
3.1. Emplacement de la configuration de Git
Ces variables de configuration sont enregistrées dans trois emplacements distincts dans l’ordre de précédence :
Emplacement | Portée | Commande git |
---|---|---|
.git/config | pour le dépôt courant seulement | git config |
~/.gitconfig | pour l’utilisateur courant | git config --global |
/etc/gitconfig | pour tous les utilisateurs du système | git config --system |
Git contient un outil appelé git config
pour vous permettre de voir et modifier les variables de configuration qui contrôlent tous les aspects de l’apparence et du comportement de Git.
3.1. Configuration de l’identité
La première étape est la configuration de son nom et de son adresse de courrier électronique (veuillez adapter l’exemple) :
git config --global user.name "John Doe"
git config --global user.email johndoe@example.com
3.2. Configuration de l’éditeur de texte
Il peut être utile de définir l’éditeur de texte par défaut que Git va utiliser, ici vim
:
git config --global core.editor vim
3.3. Vérifier les paramètres
Pour vérifier les paramètres de configuration de l’utilisateur courant :
git config --list
user.name=John Doe
user.email=johndoe@example.com
color.status=auto
color.branch=auto
color.interactive=auto
color.diff=auto
...
On peut interroger git sur un paramètre particulier, ici user.name
:
git config user.name
John Doe
3.4. Obtenir de l’aide
On peut obtenir les pages manuel de Git de plusieurs manières :
git help <commande>
git <commande> --help
man git-<commande>
Par exemple, on peut voir la page de manuel pour la commande config
comme ceci :
git help config
4. Commencer un projet Git
On peut commencer un projet Git à partir :
- d’un projet existant ou copié en l’important dans Git,
- d’un référentiel existant, en le “clonant” (voyez plus bas le point “Travailler avec des dépôts distants”).
4.1. Initialiser un référentiel Git dans un dossier existant
Pour transformer un dossier de code source en référentiel Git, il suffit de valider la commande git init
dans le dossier du projet.
Imaginez que vous vouliez créer un projet avec le code zippé sur https://github.com/cisco-goffinet-org/hello_network/archive/master.zip, voici la procédure.
On télécharge le code, on le décompresse et on se rend dans le dossier du code :
curl -L https://github.com/cisco-goffinet-org/hello_network/archive/master.zip -o hello_network.zip
unzip hello_network.zip
cd hello_network-master
ls -a
. .. .gitignore hello_network.py hello_network.sh LICENSE README.md
On crée un référentiel Git :
git init
La commande nous indique qu’un dossier caché .git/
est créé :
Dépôt Git vide initialisé dans ./hello_network-master/.git/
Désormais le dossier courant devient le dossier de travail qui est un instantané de la base de donnée du référentiel situé dans ce dossier .git/
.
4.2. Composants d’un projet Git
Git est une sorte de système de fichier capable de gérer des versions sous forme d’instantané d’un système de fichiers.
Un “référentiel”, un “dépôt” ou un “projet Git” contient trois sections principales :
- le dossier
.git/
qui contient les méta-données et la base de données des objets du référentiel. C’est que l’on télécharge quand on clone un projet. - le “Working Directory”, le dossier de travail, est l’extraction unique de la base de donnée des objets du projet prêts à être modifiés. C’est ce que l’utilisateur voit de la représentation en système de fichier de son projet.
- La “Staging area”, la zone d’index, la zone de préparation est un simple fichier, généralement situé dans le répertoire
.git/
qui enregistre ce qui fera partie des prochains instantanés.
4.3. Worflow habituel d’un projet Git
Le worflow habituel d’un dépôt Git déjà initialisé est le suivant :
- Un fichier du projet dans le dossier de travail local est modifié.
- Le fichier peut alors être ajouté à la zone d’index (staging) car il sera “suivi”, c’est-à-dire qu’il fera probablement partie du prochain instantané, soit la prochaine version du projet. C’est la commande
git add
qui intervient ici. - Le fichier indexé sera inclus au prochain instantané en le validant, faisant ainsi en sorte que les instantanés des fichiers de l’index soient déplacés dans la base de données du répertoire
.git/
devenant ainsi la dernière version. Cette version est représentée par une signature SHA-1. Ce sera la commandegit commit
qui interviendra ici.
4.4. Fichier non suivi, suivi, inchangé, modifié, et indexé
Souvenons-nous que chaque fichier de la copie de travail peut avoir deux états nous dit le Livre GIT-SCM : “sous suivi” de version ou “non suivi” :
- Les fichiers “suivis” sont les fichiers qui appartenaient déjà au dernier instantané ; ils peuvent être inchangés, modifiés ou indexés.
- Tous les autres fichiers sont “non suivis”, soit tout fichier de votre copie de travail qui n’appartenait pas à votre dernier instantané et qui n’a pas été indexé.
Dans un dépôt fraichement “cloné”, “tous les fichiers seront sous suivi de version et inchangés car Git vient tout juste de les extraire et vous ne les avez pas encore édités”.
Le processus consiste donc à effectuer des modifications, à indexer les fichiers modifiés et puis à les valider dans une version du code, et ainsi de suite.
5. Travailler sur un dépôt Git local
5.1. Vérifier l’état des fichiers
C’est la commande git status
qui permet de vérifier le statut des fichiers dans la copie de travail :
git status
Voici ce que vous devriez voir :
Sur la branche master
Aucun commit
Fichiers non suivis:
(utilisez "git add <fichier>..." pour inclure dans ce qui sera validé)
.gitignore
LICENSE
README.md
hello_network.py
hello_network.sh
aucune modification ajoutée à la validation mais des fichiers non suivis sont présents (utilisez "git add" pour les suivre)
Cette sortie nous indique plusieurs choses :
- “Sur la branche master” : on est sur la branche “master”.
- Aucun “commit”
- Fichiers “non suivis”
- Aucune modification ajoutée à la validation
Manifestement, on trouve cinq fichiers non-suivis et non indexés (puisqu’ils sont nouveaux), c’est-à-dire n’étant pas présents dans le dernier instantané. Il s’agit d’éviter de suivre accidentellement des fichiers binaires par exemple.
5.2. Placer de nouveaux fichiers sous suivi de version
Pour commencer à suivre les nouveaux fichiers, on utilise la commande git add
, ici le “point” “.
” pour indiquer tout ce qui est dans le dossier parent et ses sous-dossiers :
git add .
On dira alors que les cinq fichiers sont suivis et indexés, prêts à faire partie de la prochaine version.
git status
Sur la branche master
Aucun commit
Modifications qui seront validées :
(utilisez "git rm --cached <fichier>..." pour désindexer)
nouveau fichier : .gitignore
nouveau fichier : LICENSE
nouveau fichier : README.md
nouveau fichier : hello_network.py
nouveau fichier : hello_network.sh
5.3. Indexer des fichiers modifiés
Si on modifie un fichier qui est déjà sous suivi de version LICENSE
et que l’on lance à nouveau la commande git status
, on verra ceci :
echo "Author: myself" >> LICENSE
git status
Sur la branche master
Aucun commit
Modifications qui seront validées :
(utilisez "git rm --cached <fichier>..." pour désindexer)
nouveau fichier : .gitignore
nouveau fichier : LICENSE
nouveau fichier : README.md
nouveau fichier : hello_network.py
nouveau fichier : hello_network.sh
Modifications qui ne seront pas validées :
(utilisez "git add <fichier>..." pour mettre à jour ce qui sera validé)
(utilisez "git restore <fichier>..." pour annuler les modifications dans le répertoire de travail)
modifié : LICENSE
Le fichier LICENSE
sous suivi de version a été modifié dans la copie de travail mais n’est pas encore indexé.
5.4. Fichiers non-suivis
Veuillez imaginer un fichier NOTES
qui ne doit pas être suivi, quel est le message git status
?
echo "note 1" >> NOTES
git status
Sur la branche master
Aucun commit
Modifications qui seront validées :
(utilisez "git rm --cached <fichier>..." pour désindexer)
nouveau fichier : .gitignore
nouveau fichier : LICENSE
nouveau fichier : README.md
nouveau fichier : hello_network.py
nouveau fichier : hello_network.sh
Modifications qui ne seront pas validées :
(utilisez "git add <fichier>..." pour mettre à jour ce qui sera validé)
(utilisez "git restore <fichier>..." pour annuler les modifications dans le répertoire de travail)
modifié : LICENSE
Fichiers non suivis:
(utilisez "git add <fichier>..." pour inclure dans ce qui sera validé)
NOTES
5.5. Statut court
Les commandes git status -s
ou git status --short
permettent d’obtenir un affichage plus succinct :
git status -s
A .gitignore
AM LICENSE
A README.md
A hello_network.py
A hello_network.sh
?? NOTES
On trouve deux colonnes d’état :
- celle de gauche indique l’état de l’index,
- celle de droite l’état du dossier de travail.
Les lettres signifient l’état du fichier dans l’index et dans le dossier de travail :
-
??
: nouveaux fichiers qui ne sont pas suivis -
A
: fichiers nouveaux et indexés -
M
: fichiers modifiés
5.6. Ignorer des fichiers
Pour éviter dans tous les cas qu’un fichier fasse partie d’un suivi de version, on peut le renseigner dans un fichier .gitignore
situé à la racine du projet. Par exemple, pour que Git “ignore” le fichier NOTES :
echo "NOTES" >> .gitignore
git status -s
AM .gitignore
AM LICENSE
A README.md
A hello_network.py
A hello_network.sh
Le fichier NOTES
a disparu du statut Git ! Le fichier .gitignore
a été modifié dans le dossier de travail mais n’a pas été indexé.
On trouvera sur GitHub une liste maintenue d’exemples de fichiers .gitignore
en fonction du type de projet : https://github.com/github/gitignore.
Ajoutons les fichiers modifiés à l’index pour validation:
git add LICENSE
git add .gitignore
git status -s
A .gitignore
A LICENSE
A README.md
A hello_network.py
A hello_network.sh
6. Valider des modifications et créer des versions
6.1. Valider des modifications
Pour valider les modifications indexées et constiuer une nouvelle version qui correspond à un instantané, on utilise la commande git commit
. Git incite aux bonne pratique et nous oblige d’ajouter un commentaire à la validation. Si on lance la commande git commit
sans commentaire, l’éditeur de texte par défaut s’ouvre et vous en propose un.
Pour indiquer le commentaire directement dans la ligne de commande, on utilisera l’option -m "commentaire"
, comme par exemple :
git commit -m "first commit"
[master (commit racine) 6b29a62] first commit
5 files changed, 158 insertions(+)
create mode 100644 .gitignore
create mode 100644 LICENSE
create mode 100644 README.md
create mode 100755 hello_network.py
create mode 100755 hello_network.sh
La sortie nous offre quelques informations comme :
- la branche validée (
master
) - le somme de contrôle SHA-1
- le nombre de fichiers et de lignes changée
- les fichiers créés
6.2. Valider en passer l’étape de mise en index
Pour éviter la phase de placement des fichiers dans la zone d’index, on utilise la commande git commit -a
.
Ajoutons une modification au fichier LICENSE
:
echo "date: 2021-12-21" >> LICENSE
git status -s
M LICENSE
Mais la commande git commit -a
permet de placer automatiquement tout fichier déjà suivi dans la zone d’index avant de réaliser la validation, ce qui évite le passage par “git add
”
git commit -a -m "add date to LICENSE"
[[master 68a60c2] add date to LICENSE
1 file changed, 1 insertion(+)
6.3. Voir l’historique des validations
git log --pretty=oneline
68a60c28df5a57fe630b2da58aafe3d5c694456b (HEAD -> master) add date to LICENSE
6b29a623dd00c454e19ea3161268ed69e0178df0 first commit
7. Inspecter les modifications indexées et non indexées
Pour savoir non seulement quels fichiers ont changé mais aussi ce qui a changé dans ces fichiers, on utilise la commande git diff
. On peut donc savoir ce qui a été modifié mais qui n’est pas encore indexé, mais aussi quelle modification a été indexée et est prête pour la validation.
7.1. Inspecter les modifications non indexées
Modifions un fichier suivi :
echo "type: MIT" >> LICENSE
La commande git diff
compare le contenu du répertoire de travail avec la zone d’index :
git diff
diff --git a/LICENSE b/LICENSE
index 726ef2d..e6a0486 100644
--- a/LICENSE
+++ b/LICENSE
@@ -21,3 +21,4 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Author: myself
date: 2021-12-21
+type: MIT
Ce résultat indique les modifications réalisées mais non indexées.
7.2. Inspecter les modifications indexées
Pour voir les modifications indexées qui feront partie de la prochaine validation, on utilise git diff --cached
ou git diff --staged
.
La commande git diff --staged
compare les fichiers indexés et le dernier instantané :
git diff --staged
Ajoutons à l’index le fichier LICENSE
, git diff
ne donne pas de résultat :
git add LICENSE
git diff
Mais git diff --staged
donne la différence entre l’index et le dernier instantané.
git diff --staged
diff --git a/LICENSE b/LICENSE
index 726ef2d..e6a0486 100644
--- a/LICENSE
+++ b/LICENSE
@@ -21,3 +21,4 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Author: myself
date: 2021-12-21
+type: MIT
8. Effacer, annuler
8.1. Effacer des fichiers suivis
Pour effacer un fichier de Git, vous devez l’éliminer de la zone d’index puis valider. La commande git rm -f
réalise cette action en effaçant aussi ce fichier de la copie de travail.
git rm -f LICENSE
git status
rm 'LICENSE'
[root@dev1 hello_network-master]# git status
Sur la branche master
Modifications qui seront validées :
(utilisez "git restore --staged <fichier>..." pour désindexer)
supprimé : LICENSE
Lors de la prochaine validation, le fichier sera absent et non-suivi en version.
git commit -m "Remove LICENSE"
[master f89374b] Remove LICENSE
1 file changed, 23 deletions(-)
delete mode 100644 LICENSE
8.2. Annuler le dernier commit
git reset --hard HEAD^
HEAD est maintenant à 7795b55 modify LICENSE
8.3. Désindexer un fichier déjà indexé
echo "I made a mistake!" >> LICENSE
git add LICENSE
git status
Sur la branche master
Modifications qui seront validées :
(utilisez "git restore --staged <fichier>..." pour désindexer)
modifié : LICENSE
git restore --staged LICENSE
Sur la branche master
Modifications qui seront validées :
(utilisez "git restore --staged <fichier>..." pour désindexer)
modifié : LICENSE
[root@dev1 hello_network-master]# git restore --staged LICENSE
[root@dev1 hello_network-master]# git status
Sur la branche master
Modifications qui ne seront pas validées :
(utilisez "git add <fichier>..." pour mettre à jour ce qui sera validé)
(utilisez "git restore <fichier>..." pour annuler les modifications dans le répertoire de travail)
modifié : LICENSE
8.4. Réinitialiser un fichier modifié
git status -s
M LICENSE
git checkout -- LICENSE
git diff
git diff staged
8.5. Ajouter les modifications au dernier commit
…
git commit --amend -m "new commit"
9. Branches
…
9.1. Créer une branche
Créer une branche signifie diverger de la ligne principale de développement et continuer à travailler sans impacter cette ligne.
git branch testing
git branch
* master
testing
9.2. Basculer sur une branche
git checkout testing
Basculement sur la branche 'testing'
9.3. Validation des modifications d’une branche
git checkout testing
echo test > TEST
git add TEST
git commit -m "add TEST"
[testing 69be7b1] add TEST
1 file changed, 1 insertion(+)
create mode 100644 TEST
9.4. Fusionner une branche (Merge)
git checkout master
git merge testing
Mise à jour fe3d6c2..9444eef
Fast-forward
TEST | 1 +
1 file changed, 1 insertion(+)
create mode 100644 TEST
9.5. Effacer une branche
git branch -d testing
Branche testing supprimée (précédemment 9444eef).
9.6. Fusionner une branche (Rebase)
…
9.7. Fusionner une branche (Cherry-pick)
…
10. Créer un référentiel avec un service Git distant
10.1. GitHub, GitLab et beaucoup d’autres
…
10.2. Installer GitHub CLI
- Prenez un compte chez Github
- veuillez installer GitHub CLI.
- Disposez d’une paire de clés SSH, autrement générez les avec la commande
ssh-keygen
.
10.3. Configurer GitHub CLI
gh auth login
gh auth refresh -s write:public_key
gh config set editor vim
10.4 Créer un dépôt sur Github
gh repo create
? Repository name hello_network_test
? Repository description
? Visibility Public
? This will add an "origin" git remote to your local repository. Continue? Yes
✓ Created repository cisco-goffinet-org/hello_network_test on GitHub
✓ Added remote https://github.com/cisco-goffinet-org/hello_network_test.git
11. Travailler avec des dépôts distants
11.1. Afficher les dépôts distants
git remote -v
origin https://github.com/goffinet/hello_network_test.git (fetch)
origin https://github.com/goffinet/hello_network_test.git (push)
11.2. Pousser son travail sur un dépôt distant
Quand le dépôt semble prêt à être partagé, on peut le pousser sur le serveur distant avec la commande git push [nom-distant] [nom-de-branche]
. Ici par exemple la branche master
vers le serveur origin
:
git push origin master
11.3. Récupérer et tirer depuis des dépôts distants
un git pull sur une de ces branches récupère toutes les références distantes et fusionne automatiquement la branche distante correspondante dans la branche actuelle.
git pull
11.4. Cloner un dépôt git existant
Si le projet Git existe déjà sur un serveur distant, vous pouvez le cloner sur votre machine locale, avec la commande git clone [url]
, par exemple :
git clone https://github.com/cisco-goffinet-org/hello_network
Un dossier hello_network
se crée à l’endroit de l’exécution de la commande git clone
et on peut s’y rendre. On constate la présence d’un dossier caché .git/
:
cd hello_network
ls -la
11.5. Cloner un dépôt git en précisant la destination
…
12. Etiquettes
12.1. Types d’étiquettes
Git utilise deux types d’étiquettes : légères et annotées.
Une étiquette légère ressemble beaucoup à une branche qui ne change pas, c’est juste un pointeur sur un “commit” spécifique.
Les étiquettes annotées sont stockées en tant qu’objets à part entière dans la base de données de Git. Elles ont une somme de contrôle, contiennent le nom et l’adresse e-mail du créateur, la date, un message d’étiquetage et peuvent être signées et vérifiées avec GNU Privacy Guard (GPG).
12.2. Lister les étiquettes
git tag
Créer des étiquettes annotées
On crée des étiquettes annotées avec l’option -a
et -m
à la commande git tag
:
git tag -a v0.1 -m 'ma version 0.1'
git tag
De manière plus détaillée :
git show v0.1
12.3. Créer des étiquettes légères
Les étiquettes légères se réduisent à stocker la somme de contrôle d’un “commit” dans un fichier, aucune autre information n’est conservée. On n’utilise aucune des options -a
, -s
ou -m
de la commande git tag :
git tag v0.1-lg
git tag
v0.1
v0.1-lg
12.4. Étiqueter après un commit
Mettont l’étiquette v0
au commit initial du projet :
git tag -a v0 939dafd1 -m 'v0'
git tag
v0
v0.1
v0.1-lg
12.5. Partager les étiquettes sur le serveur distant
Par défaut, la commande git push
ne pousse pas les étiquettes vers les serveurs distants. Il faut explicitement les pousser après les avoir créées localement. Ce processus s’apparente à pousser des branches distantes avec la commande git push origin [nom-du-tag]
.
git push origin v0
Synthèse sur Git
-
init
: Git est une sorte de système de fichiers virtuel (un repo git, un référentiel) pour héberger des fichiers (de code source). -
add
,tag
etcommit
: On soumet une nouvelle version des fichiers qui sont suivis (ajoutés à un index) dans un “commit” représenté par une somme de contrôle comme point de référence. On peut placer des étiquettes sur ces validations de version. -
branch
,switch
etcheckout
: Une branche est une suite de “commits” qui diverge à partir d’un point de contrôle. On peut fusionner des branches de différentes manières (merge, rebase, cherry-pick). -
push
etpull
: synchroniser un référentiel local et un référentiel distant.