Suivre les versions d’un code source avec GIT et SourceTree

S’il est un problème auquel tout codeur (ou équipe de codeurs) est un jour confronté, c’est bien la gestion des versions de codes. 
GIT est l’un des logiciels les plus utilisés à cet effet (12 millions d’utilisateurs selonwikipédia au moment où j’écris ces lignes). 
Ce tutoriel s’adresse à ceux qui ne connaissent pas GIT ou ne savent pas s’en servir. 
Il vise seulement à une première prise en main du concept et des fonctions de base à l’aide de l’interface graphique SourceTree sur Windows.

C’est quoi GIT ?

Il s’agit d’un logiciel en ligne de commande (noyau UNIX) permettant le suivi de toutes les modifications dans un code source. Il permet de 
- revenir à un état antérieur, 
- travailler à plusieurs et de fusionner de temps à autres les avancées de chacun. 
- sauvegarder le projet à distance 
- publier sur internet, par exemple sur GitHub. 
- etc…

Pourquoi Sourcetree

GIT fonctionne en ligne de commande unix. De nombreux logiciels fenêtrés proposent de servir d’interface pour GIT. 
J’ai choisi SourceTree car il est gratuit (à condition de s’inscrire en ligne) et plus ou moins en Français. 
Au moment où j’écris ces lignes j’utilise la version 3.2.6

Installation de Sourcetree

Il s’agit d’une procédure d’installation classique, je ne vais donc pas m’y attarder.
Il faut noter tout de même qu’il vous sera demandé un compte BitBucker. Il s’agit d’un serveur de dépôt en ligne, qui supporte GIT et Mercurial. Si vous n’en disposez pas, il faudra vous inscrire.
Mercurial est un logiciel « concurrent » de GIT, vous pouvez donc gérer vos versions avec l’un ou l’autre depuis Sourcetree.
Ce tutoriel ne traite que de GIT.

Un peu de vocabulaire

Dépôt

Un dépôt est l’ensemble des fichiers générés par GIT dans lesquels sont stockées les différentes étapes de notre projet.

Dépôt local

C’est le dépôt qui est présent sur l’ordinateur du codeur. Sur Windows, ce dépôt est situé dans un dossier caché nommé .git présent à la racine du projet. Le dépôt local comprend les données GIT et le projet en cours de développement

Dépôt distant

Il s’agit d’un dépôt stocké sur un support amovible (une clé USB par exemple), sur un emplacement réseau, sur internet… Bref à distance du dépôt local. Ce dépôt sert principalement à sauvegarder le projet ou comme point de fusion pour les différents membres d’une équipe de codeurs. 
Le dépôt distant ne contient que des données GIT.

Commit

Enregistrement d’une modification du code source. Un commit associe des lignes de codes dans un ou plusieurs fichiers et un petit descriptif. Commiter désigne l’action de valider un commit.

Remise

Désigne une modification, non aboutie, que l’on doit mettre de côté. Par exemple, on avait commencé l’écriture d’une nouvelle fonction quand arrive une demande de correction de bug. Le logiciel est dans un état instable puisque cette fonction n’est pas finie : même si on corrige rapidement le bug on ne peut pas publier de mise à jour temps que cette fonction est inachevée. 
On doit donc revenir à la dernière version stable. 
Pour ne pas perdre les modifications, on les stocke dans la remise.

Branche

Une branche désigne une suite de commits qui évolue sur un ordinateur à partir d’un commit référence. On peut voir apparaitre des branches à plusieurs occasions. Si on reprend l’exemple au-dessus. On a remisé le code écrit depuis le dernier commit. 
Mais ce dernier commit ne correspond pas à la dernière version publiée. Notre nouvelle fonction a déjà engendré plusieurs commits. Et bien nous pouvons créer une branche qui part de la dernière version publiée pour y corriger le bug et publier la correction. 
On revient ensuite dans la branche de notre fonction. Une fois cette fonctionnalité totalement écrite, on fusionnera les 2 branches. 
Dans le cas d’un développement en équipe, chacun travaille sur une branche, elles sont fusionnées de temps à autre sur le dépôt distant.

Cloner un dépôt

Action de créer un dépôt local et le projet associé à parti d’un dépôt distant.

Projet d’exemple

Pour l’exemple, je crée un projet console en C# avec l’IDE Visual Studio Community 2019. Si vous ne connaissez pas ce langage ou cet IDE peu importe, c’est le fonctionnement de SourceTree qui compte ici.

Création du projet

Je crée un projet console, dans le répertoire

Y:\C#

qui s’appelle TutoSourceTree. Visual studio va écrire plusieurs fichiers dans

Y:\C#\TutoSourceTree

Création du dépôt local

Un onglet représente un dépôt local. 
A la première utilisation, il nous est donc proposé 
- d’ouvrir un dépôt existant, 
- de cloner un dépôt distant, 
- de créer un nouveau dépôt. 

Pour un futur projet, il nous suffira de cliquer sur le plus à côté de l’onglet pour ajouter un nouveau dépôt. 

Cliquons sur « Create »

Et naviguons jusqu’à

Y:\C#\TutoSourceTree

Et cliquons sur « Créer » 
Un message nous alerte que ce répertoire existe déjà, on valide. 

Dans le répertoire

Y:\C#\TutoSourceTree

, Sourcetree a ajouté le dossier caché « .git »

Dans Sourcetree, on voit tous les fichiers présents dans le projet. L’icône ? signifie que le fichier n’existe pas dans le dépôt, ce qui est logique puisque notre dépôt est tout neuf.

Ignorer des fichiers

Commençons par signifier quels fichiers ne sont pas des fichiers de code et ne doivent pas être suivis. Le répertoire « .vs » contient le cache de Visual Studio et le dossier « obj » contient des fichiers servant à la compilation. 
Sélectionnons les fichiers contenus dans « .vs » et affichons le menu contextuel.

Cliquons sur « Ignorer » 
Une fenêtre nous permet de paramétrer comment ignorer les fichiers. Nous allons choisir « tout en dessous de .vs ».

Réitérons l’opération avec « tous les fichiers sous obj » 

On constate la création d’un nouveau fichier nommé « .gitignore »

On voit en haut à droite de la capture qu’il contient 2 lignes signifiant que le contenu des répertoires « .vs » et « obj » est ignoré.

Commiter des modifications

Sélectionnons ce fichier et cliquons sur « Indexer la sélection »

Le fichier passe dans la partie haute : c’est là que l’on regroupe toutes les modifications communes à un seul commit. 
Dans la zone de texte en bas, on saisit un commentaire, une explication de ce commit et on valide. 

Après avoir fait un second commit avec tous les fichiers restants dont le commentaire est « Projet vide », cliquons sur « History » dans le bandeau vertical à gauche

Dans la partie haute on voit se dessiner la première branche de notre projet : elle est composée de 2 commits. 
En sélectionnant le commit « Projet vide », en bas apparait la liste des fichiers commités (sur la gauche) et le détail des modifications du fichier sélectionné (sur la droite). 

Après avoir ajouté 2 lignes de code dans le projet et enregistré le fichier modifié revenons à Sourcetree et cliquons sur « Etat des fichiers »

Parfois un appui sur F5 est nécessaire pour rafraichir l’affichage de SourceTree

Cette fois, le fichier « Program.cs » apparait avec une icône « stylo » signifiant qu’il a été modifié. En haut à droite on voit que 2 lignes sont surlignées en vert avec un « + » au début, cela signifie que ces lignes ont été ajoutées. 

On peut commiter cette modification.

Modifier un commit validé

Une fois le commit validé, modifions une des 2 lignes et enregistrons le fichier

Cette fois, on constate qu’une ligne est surlignée de rouge avec un « - » au début. Cela signifie qu’elle a été supprimée et remplacée par celle en vert. 

Il s’agit d’une toute petite modification qui après réflexion aurait pu figurer dans le précédent commit. 
On peut alors décider de modifier le dernier commit.
Attention cependant ce n’est pas à faire si on a déjà envoyé le dernier commit vers le dépôt distant.

En choisissant « Modifier les dernières validations », on peut indexer la modification pour l’ajouter au dernier commit, éventuellement modifier le commentaire et valider.

Commiter une partie d’un fichier

J J’ai modifié le code de façon à ce que le programme demande la langue de l’utilisateur et en fonction de celle-ci dise « bonjour le monde ». Comme je ne vais pas commiter un code non testé, j’ai écrit tous les cas, ça fait beaucoup de modifications. 
Cependant, j’aimerais faire un commit par langue. 
Sélectionner une partie d’un fichier se dit « Marquer ». 
Quand les modifications sont dispersées dans le fichier Sourcetree les présente en « fragments » ou « blocs ». 
On peut marquer un fragment entier

Dans un bloc, il est possible d’indexer des lignes successives

Notre fichier se trouve alors en parti « indexé » pour le prochain commit et en parti «à indexer » 
En cliquant sur le fichier « à indexer », les fragments « à marquer » s’affichent sur la droite

En cliquant sur le fichier «indexé », les fragments «marqués » s’affichent sur la droite

On peut au besoin « démarquer » des fragments ou des lignes successives.

Refuser une modification

On peut
- rejeter toutes les modifications d’un fichier, 
- rejeter toutes les modifications d’un bloc, 
- ne pas retenir quelques lignes successives. 
En choisissant l’une ou l’autre de ces options les modifications seront annulées dans le fichier de code et irrémédiablement perdues.

Créer une branche

Après avoir commité toutes ces modifications, je me dis que j’aurais dû écrire un objet plutôt que des méthodes. Comme je ne sais pas pour l’instant quelle option est la meilleure, je vais créer une 2eme branche à partir du 4 ème commit (il s’agit d’un ajout dans gitignore dont je ne vous ai pas parlé…) 
Cliquons sur « Changer de branche » :

la traduction est mauvaise car ce bouton permet d’ajouter ou supprimer une branche, pas de passer de l’une à l’autre

.

Par défaut, la nouvelle branche commence au dernier commit : je vais donc sélectionner le commit « Parent » que je veux avec le bouton « … »

Une fois choisi, cliquons sur « Créer la branche » 

Dans l’historique on voit les 2 « têtes » de branches. Pour passer de l’une à l’autre il faut double-cliquer sur le nom de la branche dans le bandeau de gauche. On parle d’extraire telle ou telle branche. 
Le projet se retrouvera dans l’état correspondant au dernier commit de la branche.

Quelques commits plus tard on voit que les commits sont disposés chronologiquement. 
Les 2 commits de la nouvelle branche sont donc placés au-dessus des derniers commits de la branche d’origine. 


En aparté, j’ai commité à 19h36, c’est écrit 07:36, je n’ai jamais trouvé comment afficher l’heure soit en 24h, soit avec AM/PM….

Fusionner les branches

Mon choix est fait : ce sera l’objet .Je vais donc fusionner mes 2 branches de façon à conserver le code qui me convient. Après avoir extrait la branche « master », d’un clic droit sur l’autre branche je vais choisir « Fusionner Nom de la branche dans la branche courante »

Mais ça ne se passe pas bien : la raison est que dans le fichier « Program.cs » il y a des modifications conflictuelles. 
Il faut donc gérer manuellement la fusion de ces conflits. 
Sourctree ne permet pas cela de façon triviale mais il permet de s’intercaler avec plusieurs outils dédiés connu (voir le menu Outils/Options)

Si vous utilisez régulièrement l’un deux n’hésitez pas à l’associer. Sinon je vous conseille de les essayer.

On constate que « Program.cs » est à la fois « indexé » et « à indexer » et que cette fois son icône est un triangle avec un point d’exclamation

Je vais donc lancer mon logiciel de fusion

C’est un peu long à charger. Je gère les conflits, enregistre le fichier et ferme le logiciel de fusion. 
Je vous passe les détails puisque cela dépend du logiciel que vous utilisez. 

Cette fois « Program.cs » est correctement indexé avec les modifications qui correspondent au passage du dernier commit de la branche « master » au fichier fusionné. 
En bas un fichier « Program.cs.orig » contenant le fichier en conflit a été créé pour que nous ayons le choix de le sauvegarder. Choix que je ne fais pas.

Validons le commit de fusion

Dépôt distant

Ce dépôt va dans un premier temps me servir de sauvegarde ; Je vais le mettre sur un disque réseau (

Z:\Dépot Distant\Tuto Sourcetree

) . Créer un dépôt distant est, semble-t-il, une des rares actions que Sourcetree ne permet pas. 
Il faut donc afficher la console Unix et naviguer jusqu’au dossier voulu

et taper la commande

git init --bare

Une fois fait, dans le menu « Dépôt », cliquons sur « Ajouter un dépôt distant » 
Cliquons sur le bouton « Ajouter »

On donne un nom et le chemin ; S’il s’agit d’un dépôt nécessitant des identifiants on peut les saisir.

Une fois validé, on peut envoyer nos commits vers le dépôt distant

On choisit les branches à envoyer

Et on envoie.

Cloner un dépôt distant

Mon collègue VB95 se joint à moi pour travailler sur ce projet. Il commencer par cloner le dépôt distant sur son propre ordinateur afin de disposer de son propre dépôt local. 

Dans un nouvel onglet il clique sur « Clone »
Il saisit l’adresse du dépôt distant, le chemin local où enregistrer le projet et le nom de l’onglet, et clique sur « Cloner ».

Il dispose maintenant de son projet.

Travailler à plusieurs

Nous travaillons chacun de notre côté. Je valide plusieurs commits locaux et au bout d’un moment, je souhaite les pousser sur le dépôt distant. Mais si VB95 l’a déjà fait, pour éviter un conflit dans le dépôt distant, GIT va refuser de pousser mes commits. 

Je dois d’abord vérifier si le dépôt distant est dans l’état où je l’ai laissé la dernière fois. 

Je clique sur « Rapatrier » et je valide l’option par défaut 
Je suis informé qu’il y a 3 commits à récupérer sur la branche « master » et que j’en ai 4 à envoyer.

Je vais commencer par récupérer les 3 commits et fusionner avec les miens
Il faut choisir la ou les branches à récupérer et valider

Cette fois il n’y a pas de conflits : le commit de fusion est validé automatiquement 
En plus des couleurs différentes pour chaque branches on peut voir qui a validé chaque commit.

Une fois la fusion réalisée, je peux envoyer mes derniers commits au dépôt distant. (mes 4 commits, plus le commit de fusion)

VB95 en fait autant de son côté.

Remiser un code

Il suffit de cliquer sur « Remiser » et de donner un nom à la remise pour que toutes les modifications non commitées soient stockées dans la remise. Le projet reviendra à l’état du dernier commit.

Pour accéder aux remises, les appliquer ou les supprimer il suffit d’un clic droit dans le bandeau gauche rubrique « Remise »

Les étiquettes

Les étiquettes permettent de mettre un commentaire, d’indiquer un jalon…
Par exemple, notre projet est prêt, c’est la version Realease 1.0 => je mets une étiquette

Conclusions

Je vous ai présenté les principales fonctionnalités de GIT via l’interface Sourcetree.
Il reste de nombreuses possibilités à découvrir par vous-même, par exemple:
-il est possible de cloner un dépôt local
-GIT vous permet de remettre de façon temporaire ou définitive un projet dans un état antérieur
-on peut annuler quelques lignes, fragments ou fichier de n’importe quel commit passé
-un projet peut avoir plusieurs dépôts distants
-un outil permet d’effectuer des recherches dans les commentaires ou les modification des commits
-etc...

Je vous conseille de faire des « petits commits », ne pas mettre toute une feature d’un coup, mais plein de petites étapes.
C’est plus facile si l’on cherche à se rappeler pourquoi, 6 mois auparavent, nous avons écrit ce code comme ça. Ou encore, suivre en gros ce que les autres membres de l’équipe ont fait.

Remerciements

Merci à VB95 pour son apparition à point nommé dans ce tuto ainsi que pour sa relecture attentive.

A voir également
Ce document intitulé « Suivre les versions d’un code source avec GIT et SourceTree » issu de CodeS SourceS (codes-sources.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.
Rejoignez-nous