Objectifs
Comprendre l'intérêt de la gestion de version arborescente
Maîtriser les différents concepts de la gestion de version arborescente
Effectuer un premier commit simple
Mise en contexte de l'activité
Le début d'une aventure palpitante
Alphonse, Boris et Céline, vos amis de toujours, ont choisi de rédiger leur rapport de CW01 en markdown en utilisant le logiciel de gestion de version git, et tout allait pour le mieux jusqu'à ce qu'Alphonse vous appelle en panique : tout a disparu.
Non connaisseur mais curieux, vous acceptez de vous lancer dans une passionnante aventure à la découverte de Git, cet animal extraordinaire, dans le but d'aider votre ami.
Quelques notions de base
Récupérer le code
Pour récupérer l'entièreté du code de votre ami, ce sera très simple, il faudra entrer une et une seule commande Linux. Pour comprendre pourquoi c'est si simple, il faut comprendre comment on partage usuellement du code sur internet
Le code de votre ami est sur ce que l'on appelle un dépôt, c'est, à l'instar d'un dépôt logistique, un endroit où l'on met du code dans le but qu'il soit récupéré par d'autres personnes.
Définition : Dépôt de code source
Un dépôt de code source est un espace de stockage de données qui permet leur accès à différents utilisateurs. Il stocke également un historique de toutes les modifications apportées au code depuis le début d'un projet.
Pour récupérer le code, nous allons devoir cloner le dépôt de notre ami, c'est à dire créer une copie en tout point identique à l'endroit où ont jusqu'à présent travaillé vos amis. Vous l'aurez compris : on va également cloner toutes les modifications apportées au code depuis le début du projet et savoir ce qui s'est passé.
Récupérer du code existant
Cloner le dépôt
Ça y est, on va cloner le dépôt git.
git clone https://gitlab.utc.fr/bwojtkow/rapport_cw01
C'est notre première commande git, elle dit simplement à Linux de récupérer le dépôt de code situé à https://gitlab.utc.fr/bwojtkow/rapport_cw01
, de créer un dossier et d'y mettre l'entièreté des versions du code.
Si git n'est pas installé, souvenez vous du début d'init :
sudo apt install git
Rendez-vous dans le dossier créé et affichez-y la liste des fichiers cachés, que contient-il ?
Quand git clone un dépôt, il crée un dossier ayant le nom du projet, généralement présent dans l'URL, et il y colle le code et l'historique
cd rapport_cw01/
ls -a
. .. .git readme.md
À votre avis, que contient le fichier .git
?
Il contient énormément d'information dont le fameux historique des modifications, des copies des différentes versions des fichiers, etc.
Attention :
Il est très risqué de manipuler directement le fichier .git
, mieux vaut toujours utiliser les commandes qui permettent de le modifier.
Exploration du dépot
Prise de premières informations
Ça y est, vous avez sur votre machine le code, avec tout son historique dans un fichier .git
. Comme on l'a dit, on ne veut surtout pas manipuler directement le .git
, c'est d'ailleurs pour cela qu'il est caché.
Bon, on va essayer d'obtenir quelques informations sur tout ça, et on va utiliser une commande importante : git log
. Git log, c'est une commande qui permet d'afficher l'historique des modifications. Pour le moment, on va utiliser une version de git log
un peu améliorée pour que ce soit joli et compréhensible. Mais cette version simplifiée n'est pas toujours satisfaisante.
git log --pretty=oneline --reverse
Ce qu'on voit, c'est une suite de changements. On peut voir ainsi en un clin d'œil que d'abord le plan a été ajouté, puis l'introduction, etc. Chaque modification s'appelle un commit, et a un identifiant unique et un nom, ce dernier lui a été donné par l'auteur.
Quelle a été la dernière modification effectuée sur le dépôt ?
D'après l'auteur de la modification, lors de ce commit, ce qui n'était pas intéressant a été retiré du projet.
Quel est l'identifiant du commit de la dernière modification effectuée sur le dépôt ?
dd36dacaa2c6f576a590a6433bb3c31ed9710cd3
Qui est l'auteur de ce commit ? Quelle est son adresse e-mail ?
Comme dit, on utilise une version simplifiée de git log
, pensez à plutôt utiliser sa version initial pour avoir plus d'informations
git log
Vous devriez avoir compris pourquoi l'option qui affiche les commits dans l'ordre s'appelle --reverse
: les commits qui nous intéressent, quand on développe, ce sont les derniers, il est donc normal de les afficher au début par défaut.
Alphonse Robichu, son adresse mail est <arobi@arobase.net>
Historique des versions
On a vu que git enregistrait les modifications sous formes de commits accessibles via git log. Git log est, comme toutes les commandes git, très modulaire et dispose de nombreuses options.
Définition : Commit
Un commit est une version du projet à un instant t. Elle a nécessairement
Un message de commit, ce message est rédigé par l'auteur lors du commit
Un identifiant unique.
Un commit parent unique (la version précédente)
Un auteur, défini par un nom, un prénom et une adresse e-mail
Complément : Identifiant unique
L'identifiant unique est appelé SHA, c'est un hashage de beaucoup d'information, dont notamment :
Le SHA du commit parent
Les diverses modifications apportées par le commit
Les méta-données du commit
Remarque :
Il est possible de connaître les modifications introduites par un commit en utilisant la commande git show
Conseil : Les bonnes pratiques du commit
Un bon commit, c'est un commit dit atomique, c'est à dire qu'il introduit une modification, la plus petite possible tout en ayant du sens.
Un bon commit, c'est un commit dont le message de commit est court et descriptif. On doit comprendre ce que fait le commit sans avoir à regarder dans le code.
Remarque :
On a donc vu deux intérêts de git :
Il permet de stocker et partager son code de manière structurée ;
Il permet de tracer facilement les modifications faites au cours du temps.
Complément : Formalisation
Pour représenter un commit, on les représente souvent avec un cercle et une flèche, qui pointe vers son parent. Par exemple, dans l'image suivante, on a deux commit, C1 et C2, et C2 a été créé à partir de C1
Exploration du dépôt
Utilisez la commande git show
pour afficher le contenu du commit be949407c8a5cb921470a78369ca2ccaa8adf6cb
(il s'agit de l'avant-dernier commit).
Quelle modification a été introduite par ce commit ?
Pour accéder à la documentation d'une commande git
, il faut utiliser la syntaxe "man git-cmd
", dans notre cas :
man git-show
dans notre cas, il faut utiliser git show be949407c8a5cb921470a78369ca2ccaa8adf6cb.
Essayez de comprendre par vous même le retour de cette commande.
Quand on tape la commande précédente, on obtient l'image suivante :
De haut en bas, elle contient :
Les mêmes informations que l'historique ;
Une ligne qui nous indique les fichiers concernés par les modifications ;
Une ligne indiquant l'index, en gros un identifiant de l'état de git au moment de la sauvegarde ;
précédés de -----, les fichiers qui ont subi des suppressions de ligne ;
précédés de ++++, les fichiers qui ont subi des ajouts de ligne ;
En rouge, les lignes supprimées ;
En vert, les lignes ajoutées ;
En blanc, quelques lignes non modifiées pour permettre de comprendre où est le code.
On peut donc en déduire que ce commit a supprimé une ligne et en a ajouté une autre.
SI vous avez de l'avance, utilisez le manuel pour trouver une option de git diff
pour voir précisément ce qui a changé dans la ligne.
il faut utiliser l'option --word-diff
.
git show be949407c8a5cb921470a78369ca2ccaa8adf6cb --word-diff
Trouvez ce qu'il s'est passé entre le commit "retrait ligne pas intéressantes" et le commit "modifications mineures pour améliorer la lecture".
Quand on veut connaître les modifications introduites par plusieurs commits, on utilise la commande git diff.
git diff a des tonnes d'utilisations, dans notre cas, son usage est :
git diff 740df085f4bcbdaef86cfc35a5d927d2453733a1 be949407c8a5cb921470a78369ca2ccaa8adf6cb --word-diff
Entre ces deux commits, on a ajouté deux mots dans le rapport ainsi qu'un fichier readme.md.
Navigation dans le dépôt
Maintenant qu'on a une bonne idée du commit coupable, on va se poser la question suivante : où est le rapport ?
De ce que l'on sait du git diff, le rapport est un fichier rapport.md, supposément à la racine du projet.
On l'a dit, un commit est une version du projet. Ce que l'on va faire, c'est se déplacer dans l'arborescence des commits pour charger la version qui nous intéresse
Utilisez la commande git checkout pour changer de version du rapport et charger le commit be949407c8a5cb921470a78369ca2ccaa8adf6cb
Constatez que le rapport est magiquement réapparu
git checkout be949407c8a5cb921470a78369ca2ccaa8adf6cb
Affichez le rapport dans le terminal, constatez qu'il est très gros
cat rapport.md
Déplacez vous au tout premier commit, constatez que le rapport est encore plus petit
git checkout 348da1f810758f96b987b3e6269ad1897bc5a8b8
cat Rapport.md
git log
#pour trouver l'identifiant du commit
git checkout 348da1f810758f96b987b3e6269ad1897bc5a8b8
cat Rapport.md
# Le rat taupe nu, un animal formidable
## Description
## Mode de vie
## Particularités remarquables
### Longévité exceptionnelle
### Insensibilité à la douleur
### Privation d'oxygène
## Reproduction
## Alimentation
## Systématique
## Le rat-taupe nu dans la fiction
Revenez à l'état initial
Il faut utiliser l'option --all
de la commande git log pour obtenir l'ensemble des commits.
git log --pretty=oneline --all
git checkout dd36dacaa2c6f576a590a6433bb3c31ed9710cd3
Nous venons d'utiliser les hash de commit afin de naviguer dans l'historique. De manière générale nous préférons utiliser les étiquettes de branche directement.
Se déplacer dans les versions
Fondamental : Questionner l'historique
Comme chaque commit a un identifiant, associé à beaucoup d'informations, il est donc possible de :
Voir les changements introduits pas un commit en utilisant
git show
;Comparer deux états du code en utilisant
git diff
.
Fondamental : Se déplacer dans les versions
Il est possible de charger différentes versions du projet en utilisant git checkout
.
Quand cette commande est appelée avec pour argument une version du projet, elle remplace complètement le contenu à la racine du projet, et charge celui correspondant à la version demandée.
La version précédente du projet est désormais cachée quelque part dans le dossier .git
.
Remarque :
On a vu deux intérêts supplémentaires de la gestion de version :
Naviguer entre les versions de manière totalement transparente ;
Pouvoir comparer différentes versions pour voir s’il y a un bug.
Versionnage arborescent
Travailler à plusieurs : notion de branche
Pour travailler à plusieurs, il peut être intéressant de travailler chacun dans son coin à partir d'une version minimale du code et de mettre en commun à la fin.
Dans le cas qui nous occupe c'est ce qui a été fait, si vous exécutez la commande suivante, vous verrez une version arborescente :
git log --graph --oneline
Fondamental : Notion de branche
Une branche, c'est une divergence avec le travail principal, créée dans le but de ne pas déranger les autres membres du projet.
Fondamental : Branche master
La suite de commits qui contient l'ensemble du travail stable et fonctionnel est appelée « branche master »
, c'est également la toute première branche existante lorsque vous créez un projet. Cependant, pour des raisons éthiques, certains hébergeurs (comme GitHub) préfèrent la nommer main
.
Fondamental : Notion de fusion
Fusionner (ou par anglicisme, merger), c'est rassembler le travail produit sur deux branches en créant un commit spécial : le commit de fusion (merge
).
La plupart du temps, cela se passe bien et l'algorithme détermine sans problème comment fusionner ;
Des fois les modifications apportées concernent la même zone du code, et git ne peut pas déterminer tout seul les modifications à apporter ; il y a conflit, et il faut gérer cela manuellement.
Définition : Commit de fusion
Le commit de fusion, c'est le seul commit de git qui peut avoir deux parents. Il contient l'arbitrage entre les deux branches, et détermine comment les modifications de chaque branche doivent être appliquées.
Remarque :
Quand l'une des branches ne contient pas de commit depuis la séparation des deux branches, il n'y a pas d'arbitrage à faire, git fusionne donc les deux branches sans créer de commit.
Définition : Étiquette
Une étiquette, c'est une variable dans git qui permet d'identifier une version et qui peut être utilisée de la même manière que le numéro d'un commit.
Exemple :
L'étiquette
HEAD
peut être utilisée pour identifier le commit qui est actuellement chargé dans votre répertoire courant, vous l'avez normalement vu bouger.L'étiquette
master
identifie le commit au bout de la branche masterL'étiquette
origin/master
identifie le bout de la branche master sur le dépôt distantDans notre cas, l'étiquette alphonse identifie le bout de la branche alphonse.
Remarque :
Cela nous amène à un nouvel intérêt de git : collaborer sur un même projet en ne gênant pas les autres dans leur travail.
Comprendre l'arborescence
Avant de corriger le problème causé par Boris, on va essayer de comprendre ce qu'il s'est passé au cours du projet en utilisant la notion de branche
En utilisant la commande ci-après essayez de comprendre ce qui s'est passé.
git log --pretty=oneline --graph --all
Historique :
un premier commit a été fait sur master ;
3 branches ont été créées à partir de master ;
Alphonse a fait 2 commit, boris 4 et céline 4 également ;
Alphonse a fusionné avec master, cas particulier, comme master n'a pas de commit, il n'y a pas de commit de merge à faire ;
Boris a fusionné avec master ;
Céline a fusionné avec master ;
3 commits ont été faits sur master.
Git branch est une commande qui permet de gérer tout ce qui a trait aux branches.
La commande git branch
permet de lister les branches. Utilisez la avec l'option -a
, puis sans -a
. Combien y a-t-il de branche sur le dépôt original ? Combien y a-t-il de branches sur votre dépôt ?
Consultez la documentation pour voir ce que fait l'option -a.
remotes/origin
correspond aux branches disponibles sur le dépôt origin
. C'est le nom que prend par défaut celui depuis lequel vous avez cloné votre dépôt.
Pour vous en convaincre, vous pouvez entrer :
git remote -v
Sur votre machine, git branch -a
affiche normalement ceci :
* master
remotes/origin/HEAD -> origin/master
remotes/origin/alphonse
remotes/origin/boris
remotes/origin/celine
remotes/origin/master
L'astérisque matérialise la branche sur laquelle est placée HEAD.
On voit qu'il y a 4 branches sur le dépôt originel, que HEAD pointe sur master, et qu'il n'y a qu'une seule branche en local.
Entrez la commande
git checkout alphonse
À votre avis que s'est-il passé ?
Revert un commit
Ça y est, maintenant qu'on a compris tout ce qu'il y avait à comprendre sur le projet, on peut passer à la fin : corriger l'erreur de Boris.
Pour corriger l'erreur de Boris, il faut annuler son commit. On verra plus tard pourquoi, mais, dans ce genre de cas, on veut ajouter un commit qui va complètement annuler l'erreur de Boris, et pas supprimer le commit. Disons pour le moment que c'est simplement pour garder une traçabilité. Pour cela, on va utiliser la commande git revert
.
Il faut utilisez la commande suivante. Lisez les instructions
git revert HEAD
On l'a dit, un message de commit contient un nom, un prénom, et un mail d'auteur. Normalement, si vous faites un git-revert, vous allez vous faire jeter. Une fois votre identité correctement configurée, essayez de faire un git revert
, que se passe-t-il ? À votre avis, pourquoi ?
git config --global user.name "John Doe"
git config --global user.email "john@doe.org"
Pensez aux composantes obligatoires d'un commit.
Un éditeur de texte (nano
normalement) s'ouvre pour que vous puissiez remplir le message du commit. Une fois que vous aurez sauvegardé et quitté, vous aurez désormais effectué un commit.
Vérifiez qu'il y a bien un nouveau commit, qu'il est à vous.
En théorie, il vous faudrait encore propager vos modifications sur le dépôt de votre ami, mais on va y revenir durant l'API.
Configurer son identité
Fondamental : Configurer son identité
Pour pouvoir sauvegarder des modifications, il est absolument nécessaire d'avoir configuré son identité.
Définition : Identité globale
Votre identité globale est propre à l'ordinateur sur lequel vous êtes. Par défaut, lorsque vous committez sur un projet, git utilise votre identité globale.
Complément :
Pour configurer son identité globale, on utilise les commandes :
git config --global user.email "Vous@exemple.com"
git config --global user.name "Votre Nom"
Définition : Identité locale
Votre identité locale est propre au dépôt sur lequel vous êtes. C'est utile si vous voulez par exemple renseigner une adresse personnelle pour un projet particulier.
Complément :
Pour configurer son identité locale, on utilise les commandes :
git config --local user.email "Vous@exemple.com"
git config --local user.name "Votre Nom"