Gestion de version avec Git
[TP 1/4] - Génie Logiciel L3
Présentation de Git
Git est un systĂšme de gestion de versions, câest-Ă -dire un logiciel qui permet de stocker un ensemble de fichiers tout en gardant une chronologie de toutes les modifications qui ont Ă©tĂ© effectuĂ©es dessus. Cela offre la possibilitĂ© de rĂ©cupĂ©rer dâanciennes versions de documents et dâexaminer lâhistorique des modifications. Cela permet Ă©galement de travailler de maniĂšre distribuĂ©e, afin que plusieurs personnes puissent collaborer sur un mĂȘme projet. Pour que la collaboration de plusieurs personnes soit efficace, une fonctionnalitĂ© permet de gĂ©rer les conflits lors de modifications concurrentes de la mĂȘme partie dâun fichier.
Il existe deux philosophies de gestionnaire de versions :
- Lâune utilisant un systĂšme centralisĂ©, comme CVS ou Subversion : dans ce genre de systĂšme, il nây a quâun seul dĂ©pĂŽt des versions. Le serveur va donc centraliser tous les fichiers constituant un projet et contient lâhistorique des versions. Dans ce systĂšme, lâutilisateur va rĂ©cupĂ©rer sur son poste une version des fichiers et va toujours travailler sur celle-ci. Lorsquâil le souhaitera, il synchronisera son code avec le dĂ©pĂŽt central pour que le code du dĂ©pĂŽt central soit modifiĂ©. Ce systĂšme prĂ©sente plusieurs dĂ©fauts, le principal Ă©tant quâil est trĂšs difficile de travailler sans connexion ;
- Lâautre un systĂšme dĂ©centralisĂ©, comme Git ou Mercurial : dans ces systĂšmes, chaque utilisateur dispose dâune copie complĂšte du dĂ©pĂŽt, avec son historique complet. Il sera certes plus long de cloner un dĂ©pĂŽt, mais lâutilisateur pourra alors travailler localement sur son poste, sans connexion Ă internet. Par ailleurs, en cas de dĂ©faillance du serveur central, le code et son historique ne sera pas perdu, puisque tous les utilisateurs disposent dâune copie complĂšte du code source.
Git est le systĂšme de gestion de version le plus connu et le plus utilisĂ© de nos jours. Il sâagit dâun CVS dĂ©centralisĂ©, créé par Linus Torvalds pour la gestion du noyau Linux. Pour lâanecdote, Git a Ă©tĂ© conçu en quelques semaines, suite Ă la dĂ©cision de BitKeeper de rendre son outil de gestion de version payant.
Démarche
Les fichiers sont stockĂ©s dans un dĂ©pĂŽt central. Ce dĂ©pĂŽt peut ĂȘtre situĂ© sur un serveur distant, ou sur la machine locale. LâaccĂšs Ă un serveur distant peut se faire soit Ă lâaide dâun protocole spĂ©cifique Ă Git, soit encapsulĂ© dans du SSH ou du HTTP pour ĂȘtre accessible plus facilement.
Afin de travailler, il faut rĂ©cupĂ©rer une copie locale du dĂ©pĂŽt ; câest la copie de travail, sur laquelle les modifications seront apportĂ©es. Une fois les modifications effectuĂ©es, il faut les commiter (les regrouper pour former un âpaquet de changementsâ), puis les transmettre au dĂ©pĂŽt central (push). Ce dernier mettra Ă jour les versions si tout se passe bien, ou refusera sâil y a un conflit quâil ne peut pas rĂ©soudre seul. Afin de faciliter la gestion des versions, il est trĂšs fortement recommandĂ© dâindiquer la liste des modifications effectuĂ©es. De la mĂȘme maniĂšre, il est recommandĂ© de frĂ©quemment envoyer ses modifications et rĂ©cupĂ©rer celles des autres, pour rester synchronisĂ©, et Ă©viter les conflits.
Utilisation de Git
Configuration initiale
Avant de commencer, nous allons créer un environnement de travail. Dans un terminal, tapez les commandes suivantes :
mkdir -p ~/TPGenieLog/Git
cd ~/TPGenieLog/Git
Nous allons ensuite configurer Git. Chacun de nos commits dispose en effet du nom de lâauteur des modifications, et son adresse mail. Il faut donc configurer Git pour quâil les connaisse :
git config --global user.name "Prénom Nom"
git config --global user.email "prenom.nom@etu.uca.fr"
Vous pouvez afficher votre configuration avec la commande :
git config --listCommandes de base
Le programme de base (client) ne fonctionne quâen ligne de commande. Il existe cependant de nombreuses interfaces graphiques (gitGUI, tortoise, etc). La majoritĂ© des IDEs modernes embarquent Ă©galement un visualiseur Git. Ces clients graphiques prĂ©sentent tous lâinconvĂ©nient dâĂȘtre incomplets et de fonctionner en âmagie noireâ, aussi, il est dĂ©conseillĂ© de sâen servir pour autre chose que de la lecture.
CrĂ©ation dâun dĂ©pĂŽt
Tout dâabord, nous allons initialiser notre dĂ©pĂŽt Git en local. Dans le
dossier ~/TpGenieLog/Git créé précédemment, nous allons taper la
commande suivante :
git init
Cette commande va créer un dossier .git dans votre dossier courant. Ce
répertoire contient toutes les informations nécessaires à Git pour gérer
son dĂ©pĂŽt. Les donnĂ©es ne doivent jamais ĂȘtre Ă©ditĂ©es Ă la main.
Lâarborescence est la suivante :
config: contient les options de configuration spécifique au projetdescription: fichier utilisé pour parcourir le dépÎt git via interface graphiqueHEAD: lien symbolique vers la branche courante. En général, redirige vers refs/heads/master.hooks/: contient les scripts exécutés avant ou aprÚs certaines commandes (commit, push, etc)info/: contient divers fichiers de configurationobjects/: contient tout le contenu de la base de code versionnérefs/: contient toutes les références du dépÎt (stashes, tags, branches distantes et locales, etc).
Voir le statut du dépÎt local
Ă tout moment, vous pouvez connaĂźtre lâĂ©tat du dĂ©pĂŽt en utilisant la commande :
git status
Cette commande va indiquer lâensemble des modifications depuis votre dernier commit. Actuellement, elle devrait vous indiquer quâaucun changement nâa eu lieu. Mais cela va vite changer !
Créons maintenant quelques fichiers :
echo "Bonjour !" > bonjour.txt
echo "Un autre fichier" > fichier.txt
echo "### Et un dernier pour la route" > route.md
En relançant votre commande git status , vous allez constater que git
vous indique plusieurs fichiers non-suivis.
Ajouter un fichier
Pour commencer Ă suivre les modifications dans un fichier (et lâajouter Ă votre prochain commit), on utilise la commande :
git add nom_de_fichier
Il est possible de stipuler plusieurs fichiers dâun coup, en listant chaque fichier un par un. Par exemple :
git add bonjour.txt fichier.txt
Ou en utilisant git add . , qui
ajoute tous les fichiers au commit.
Ajoutez lâensemble des fichiers (avec la commande que vous souhaitez),
et relancez un git status . Vous devriez avoir un message de Git
indiquant que les fichiers sont suivis pour le changement.
Commiter les changements
Maintenant que nous avons fait des changements, nous pouvons commiter, câest-Ă -dire fixer nos changements dans lâhistorique de Git. La commande est la suivante :
git commit -m "mon_message_de_commit"
En relançant la commande git status , git doit vous indiquer que la
liste de changement est Ă nouveau vide. Cela signifie que vos
changements sont dĂ©sormais prĂ©sents dans Git, et quâils seront toujours
accessibles dans lâhistorique !
Voir lâhistorique du dĂ©pĂŽt
Vous pouvez regarder lâhistorique avec la commande :
git log
Ce dernier devrait normalement afficher un seul bloc, contenant :
- Le hash du commit (un ensemble de chiffres et de lettre alĂ©atoire permettant dâidentifier le commit)
- La branche sur laquelle les changements ont été poussés
- Lâauteur du commit
- La date
- Et enfin, le message de commit
Maintenant, nous allons ajouter une seconde série de modifications.
Ajoutez du contenu dans le fichier bonjour.txt, et relancez un
git status . Vous devriez voir les changements que vous avez
effectués.
Voir les différences sur le dépÎt local
Une autre commande trĂšs utile est :
git diff
Cette commande va vous permettre de voir lâensemble des changements effectuĂ©s dans un fichier
depuis votre dernier commit. Une ligne commençant par un - est une
ligne supprimée, une ligne commençant par un +est une ligne ajoutée.
Si vous changez un caractĂšre dans une ligne, la ligne entiĂšre sera
considérée comme effacée, et ajoutée.
Commitons Ă nouveau nos modifications (vous avez les commandes plus
haut). git log devrait désormais afficher 2 commits !
Réparer ses erreurs
Malheur, vous vous rendez compte que vous avez fait une vilaine faute dans un message de commit ! Heureusement, la fonction âamendâ vous permet de corriger cela sans ĂȘtre vu :
git commit --amend -m "Update my message !"
Relancer la commande git log vous permettra de voir que le message a bien été mis à jour.
Retourner en arriĂšre
Parfois, vous aurez envie de revenir en arriĂšre, car vous vous rendrez
compte quâune modification dans votre code a eu des impacts
indésirables. git revert est là pour vous !
Exécutons la commande :
git revert HEAD
Quittez vi avec :q ou nano avec CTRL+X. Relancez
git log : que sâest-il passĂ© ?
Il est possible de revenir en arriĂšre de plusieurs versions en spĂ©cifiant le nombre de commits que lâon souhaite annuler, par exmple :
git revert HEAD~2
Cela permet ainsi de revenir en arriÚre de 2 commits. Lancez la commande, et constatez les changements en explorant le contenu de votre dépÎt (avec ls par exemple).
Maintenant, faites un dernier git revert pour revenir Ă lâĂ©tat initial du dĂ©pĂŽt.
Ignorer des fichiers
Parfois, vous souhaiterez ignorer des fichiers de votre arborescence Git
(fichier de base de données, de configuration, etc). Un moyen trÚs
simple de le faire est dâajouter un fichier .gitignore Ă la racine de
notre projet, et dây noter les fichiers Ă exclure. Par exemple :
configuration.txt
base.h2
dossier/ #Va exclure le dossier entier
*.h2 #Va exclure tout les fichiers terminant par .h2
Créez un fichier .gitignore avec le contenu fourni ci-dessus, puis
crĂ©ez un fichier âconfiguration.txtâ. Lancez un git status. Que
constatez-vous ? Ajoutez et commitez les modifications.
Un site trĂšs utile au quotidien est
gitignore.io, qui vous permet
de générer des fichiers .gitignore à la volée.
Gérer des branches
Les branches permettent de contenir des versions déviant de la ligne de développement principale. Cette fonctionnalité est trÚs utilisée, notamment pour pouvoir expérimenter du code sans toucher la branche principale.
Ă lâinitialisation, une premiĂšre branche est créée. Cette branche se
nomme master. Il est possible de voir la liste des branches avec la
commande git branch . La branche actuelle est notĂ©e dâun astĂ©risque.
Pour créer une branche, il existe deux options :
- Pour créer une branche sans vous basculer dessus :
git branch nom_branche
Il faudra basculer avec :
git checkout nom_branche
- Pour créer la branche et vous positionner dessus :
git checkout -b nom_branche
Créez une nouvelle branche experimental , et accédez-y.
Créez un fichier experiment.txt avec du contenu dedans (ce que vous
voulez). Commitez vos changements, et vérifiez avec git log . Basculez
maintenant sur la branche master : git checkout master . Relancez
git log . Que constatez-vous ? Idem pour la commande ls .
Comme vous pouvez le voir, ni git log ni la commande ls ne voient
votre fichier experiment.txt. Ce qui est normal, comme vous lâavez créé
sur une autre branche !
Fusionner des branches
Maintenant, lançons la commande
git merge experimental
Cette commande va récupérer les changements effectués dans la branche experimental , et les rapatrier dans master.
Si vous relancez ls ou git log, vous devriez désormais voir le
fichier experiment.txt et son commit associé ! Nous pouvons désormais
supprimer la branche experimental qui ne sert plus Ă rien.
Supprimer une branche
Pour supprimer une branche, il suffit dâutiliser la commande
git branch avec lâargument -d . Exemple :
git branch -d experimental
Vous pouvez vérifier que la branche a bien été supprimée en listant vos branches.
Gérer les conflits
Lorsque vous fusionnez des branches, il est possible que vous obteniez un conflit ; câest-Ă -dire une situation que Git ne sait pas rĂ©soudre tout seul. Cela arrive notamment lorsque deux personnes modifient le mĂȘme fichier sur deux branches diffĂ©rentes.
Créons une situation de conflit :
git checkout -b conflit
echo "bonjour" > experiment.txt
git add . && git commit -m "bonjour"
git checkout master
echo "coucou" > experiment.txt
git add . && git commit -m "coucou"
Ici, nous venons dâĂ©crire âbonjourâ dans le fichier experiment.txt sur la branche conflit, et coucou dans le mĂȘme fichier sur la branche master. Tentons de merger notre branche :
git merge conflit
Comme attendu, Git nous renvoie une erreur indiquant un conflit dans
experiment.txt. Ă ce stade, il nây a pas dâautre choix que de rĂ©soudre
manuellement le conflit. Ăditez le fichier experiment.txt (avec vi,
nano, ou un autre éditeur de text).
Le contenu devrait ĂȘtre le suivant :
<<<<<<< HEAD
coucou
=======
bonjour
>>>>>>> conflit
La structure est assez simple : la partie située entre <<<<<<< HEAD et
======= est issu de la branche actuelle (master), et la partie entre
======= et >>>>>> conflit est issu de la branche conflit. Pour
rĂ©soudre un conflit, il suffit de supprimer ces Ă©lĂ©ments, et dâarranger
comme on le veut le contenu, Ă savoir garder un cĂŽtĂ© ou lâautre (ou les
deux).
Ensuite, on rajoute un commit pour indiquer la résolution du conflit :
git add . && git commit -m "conflit résolu !"
On peut alors supprimer la branche conflit.
DépÎts distants
Pour cette partie TP, nous allons utiliser une instance de GitLab, un serveur Git trÚs utilisé en entreprise. Rendez-vous sur https://gitlab.isima.fr/, et créez un compte avec votre adresse universitaire.
Ensuite, crĂ©ez un dĂ©pĂŽt : cliquez sur + en haut Ă droite de lâinterface, puis sur Create blank project. Donnez-lui un nom, dĂ©cochez lâoption Initialize repository with a README et cliquez sur Create project. Votre dĂ©pĂŽt est dĂ©sormais créé.
Maintenant, nous devons indiquer à notre dépÎt local que nous avons une
cible distante. Pour cela, nous pouvons utiliser la commande
git remote . Cette commande permet dâajouter, modifier ou supprimer
des dépÎts distants à synchroniser.
Lançons la commande :
git remote add origin <URL>
LâURL est votre dĂ©pĂŽt est indiquĂ©e sur lâinterface de GitLab, et termine par un .git.
Ensuite, nous allons pousser nos changements :
git push -u origin master
Git vous demandera trĂšs probablement votre identifiant et votre mot de passe de lâinstance GitLab. Vous devriez voir apparaĂźtre dans lâinterface Web vos fichiers !
Maintenant, imaginons que vous avez deux ordinateurs, sur lequel votre
code est présent. Allez dans ~/TPGenieLog . Nous allons cloner notre
dépÎt distant. Le clone permet de récupérer une copie locale du dépÎt,
pour y travailler dessus :
git clone URL SecondPC
Le dépÎt git sera cloné dans un dossier nommé SecondPC.
Dans le dossier SecondPC, effectuez des modifications, commitez et
poussez les modifications.
Retournez dans le dossier ~/TPGenieLog/Git : vos modifications
apportées ne sont pas encore présentes. Vous pouvez les récupérer avec
git pull .
Conclusion
Nous avons vu dans ce TP quelques possibilitĂ©s offertes par Git. Cependant, nous sommes loin dâavoir tout vu ! Git dispose en effet de commandes trĂšs poussĂ©es permettant dâeffectuer de nombreuses actions (rebase, cherry pick, etc).
GrĂące Ă ce TP, vous ĂȘtes dĂ©sormais en mesure dâutiliser Git dans vos projets universitaires et personnels.
Si vous souhaitez hĂ©berger du code, nâhĂ©sitez pas Ă aller voir les sites GitHub et GitLab, qui permettent de crĂ©er gratuitement des dĂ©pĂŽts Git.