Corrigés des exercices

Introduction

Au fil des divers TPs, des exercices vous ont été proposés pour tester votre compréhension des concepts abordés. Dans cette annexe, nous allons discuter une solution possible à chacun de ces exercices. Notez que la plupart des exercices ont plusieurs solutions valides.

Exercices TP1

Pour créer un dépôt git, il suffit d’utiliser la commande git init au sein d’une arborescence de fichiers. On peut le faire au sein d’un dossier existant, ou bien créer un nouveau dossier pour le dépôt comme on l’a fait pendant le TP :

mkdir ~/Desktop/Exercice1 cd ~/Desktop/Exercice1 git init

Dans le monde du shell Unix, on désigne les fichiers portant l’extension « .o » par la syntaxe *.o qui signifie « tout fichier ou dossier dont le nom se termine par .o ». On peut, en utilisant cette syntaxe, dire à git d’ignorer les fichiers portant cette extension via le fichier spécial .gitignore :

echo '*.o' > .gitignore

Maintenant, créons un fichier :

echo 'Blabla' > Test.txt

On peut indiquer à git qu’on souhaite versionner ce fichier avec la commande git add. Ce fichier sera alors inclus dans toutes les versions de l’arborescence enregistrées ultérieurement. Nous verrons comment on enregistre des versions de l’arborescence au TP2.

git add Test.txt

Pour déplacer un fichier en informant git de l’opération, on peut utiliser la commande git mv :

git mv Test.txt AutreTest.txt

Si l’on regarde la sortie de git status

git status

…on obtient la sortie suivante dans le terminal :

Sur la branche master Aucun commit Modifications qui seront validées : (utilisez "git rm --cached <fichier>..." pour désindexer) nouveau fichier : AutreTest.txt Fichiers non suivis: (utilisez "git add <fichier>..." pour inclure dans ce qui sera validé) .gitignore

On y trouve, outre l’information de branche actuelle qu’on choisit d’ignorer pour l’instant, les informations suivantes :

  • Aucune version n’a été enregistrée pour l’instant.
  • Si l’on enregistrait notre première version maintenant, le fichier AutreTest.txt en ferait partie, mais pas le fichier .gitignore.

Exercices TP2

La procédure pour créer un dépôt git vide est la même que précédemment :

mkdir ~/Desktop/Exercice2 cd ~/Desktop/Exercice2 git init

Ajoutons-y un peu de contenu :

echo 'Mon premier fichier' > Fichier1.txt echo 'Mon deuxième fichier' > Fichier2.txt echo 'Mon troisième fichier' > Fichier3.txt

On indique à git qu’on souhaite versionner des fichiers avec git add. Lorsqu’on souhaite demander à git de sauvegarder tous les fichiers du dépôt, un raccourci pratique est l’option --all :

git add --all

Ensuite, on peut créer un commit contenant tous ces fichiers avec git commit :

git commit -m 'Mon premier commit'

Maintenant, modifions deux fichiers…

echo 'De plus' >> Fichier1.txt echo 'En plus' >> Fichier2.txt

Si l’on souhaite créer un commit qui ne contient que les modifications d’un seul fichier, il suffit de n’appliquer git add qu’à celui-ci :

git add Fichier1.txt git commit -m 'Mon deuxième commit'

Du coup, il reste des modifications non sauvegardées à l’autre fichier, comme on peut le voir dans la sortie de git status :

git status

Comme ce fichier est sous gestion de version, on peut visualiser ses modifications non sauvegardées avec git diff :

git diff

Pour créer un commit comprenant toutes les modifications non sauvegardées, on a plusieurs possibilités. Nous avons déjà vu git add --all, ici nous sommes aussi dans le cas particulier où tous les fichiers sont sous gestion de version et on peut utiliser git commit -a en toute sécurité :

git commit -am 'Mon troisième commit'

À ce stade, nous avons créé trois commits dans le dépôt. Le plus récemment créé peut être désigné par HEAD, son prédécesseur par HEAD~, et le commit précédent, qui est le premier commit de l’historique, par HEAD~2.

Nous pouvons donc afficher la différence entre les deux premiers commits de l’historique avec la commande…

git diff HEAD~2 HEAD~

Le répertoire de travail est-il bien propre ? Demandons à git status :

git status

On obtient en réponse la sortie suivante :

Sur la branche master rien à valider, la copie de travail est propre

Le répertoire de travail (traduit en copie de travail dans cette version de git) est donc propre, et on peut donc partir en voyage dans les versions historiques de l’arborescence, par exemple en visitant le grand-parent du commit actuel, HEAD~2 :

git checkout HEAD~2

Si, durant notre visite, on se rend compte qu’on pourrait avoir besoin de revenir sur ce commit ultérieurement, il peut être judicieux d’y attacher une étiquette avec la commande git tag :

git tag papy

On peut revenir sur la branche master avec la commande git checkout :

git checkout master

Exercices TP3

Un dépôt git est un dossier comme les autres, on peut en créer une copie avec une copie récursive :

cp -r ~/Desktop/MonDepot ~/Desktop/Exercice3 cd ~/Desktop/Exercice3

Le parent du commit actif est désigné par la syntaxe HEAD~, et on peut le visiter avec la commande git checkout :

git checkout HEAD~

Ensuite, on peut créer une branche qui en part avec git branch :

git branch nouvelle-branche

Et on peut basculer sur cette branche avec git checkout :

git checkout nouvelle-branche

Pour créer un commit ajoutant un nouveau fichier, on crée le fichier, puis on le l’ajoute à l’index avec git add, et on crée le commit avec git commit :

echo 'Un fichier' > LeFichier.txt git add LeFichier.txt git commit -m "Ajout d'un fichier"

On peut ensuite visualiser la branche master et la branche que l’on vient de créer en lançant gitg dans le dépôt…

gitg &

…ou en rafraîchissant son affichage avec Ctrl+R s’il est déjà ouvert. N’oubliez pas de sélectionner l’option « Branches » ou l’option « All commits » dans le menu de droite pour pouvoir visualiser les deux branches simultanément.

Notre branche a un peu de retard avec la branche master, nous pouvons rattraper ce retard en y fusionnant les nouveautés de la branche master avec git merge :

git merge master

Maintenant, remplaçons le contenu d’un fichier au sein de la branche active…

echo 'v1' > LeFichier.txt git add LeFichier.txt git commit -m 'Première version'

…et au sein de la branche master, en basculant sur celle-ci :

git checkout master echo 'v2' > LeFichier.txt git add LeFichier.txt git commit -m 'Deuxième version'

Si l’on essaye de fusionner nouvelle-branche au sein de master avec git merge, il y aura conflit au niveau de ce fichier :

git merge nouvelle-branche

…comme indiqué par le message d’erreur suivant :

CONFLIT (ajout/ajout) : Conflit de fusion dans LeFichier.txt Fusion automatique de LeFichier.txt La fusion automatique a échoué ; réglez les conflits et validez le résultat.

On peut résoudre ce conflit de plusieurs façons, l’approche préconisée dans cette formation est l’utilisation d’un outil de visualisation tel que Meld :

meld .

Au sein de l’interface de Meld, double-cliquez sur le fichier conflictuel, qui apparaît en rouge dans l’interface, puis résolvez le conflit en choisissant la version « de gauche », la version « de droite », ou en écrivant une version de votre cru qui vous semble réunir les meilleures idées de chacune.

Après avoir quitté Meld en sauvegardant vos changements et en validant la résolution du conflit, vous pourrez terminer la fusion avec git merge --continue ou git commit :

git merge --continue

Exercices TP4

Pour cloner un dépôt, on utilise la commande git clone :

git clone ~/Desktop/MonDepot ~/Desktop/Exercice4

Si l’on compare le contenu de l’original et du dépôt du point de vue du répertoire de travail, en lançant la commande ls -al d’abord sur le dépôt original…

cd ~/Desktop/MonDepot/ ls -al

…avec la sortie suivante…

total 28 drwxr-xr-x 4 hadrien users 4096 19 nov. 2018 . drwxr-xr-x 8 hadrien users 4096 18 sept. 16:44 .. -rw-r--r-- 1 hadrien users 19 19 nov. 2018 AutreContenu.txt drwxr-xr-x 8 hadrien users 4096 19 nov. 2018 .git -rw-r--r-- 1 hadrien users 6 19 nov. 2018 .gitignore drwxr-xr-x 2 hadrien users 4096 19 nov. 2018 MonDossier -rw-r--r-- 1 hadrien users 44 19 nov. 2018 Poubelle.log

…puis sur le clone…

cd ../Exercice4/ ls -al

…avec la sortie suivante…

total 20 drwxr-xr-x 3 hadrien users 4096 18 sept. 16:44 . drwxr-xr-x 8 hadrien users 4096 18 sept. 16:44 .. -rw-r--r-- 1 hadrien users 19 18 sept. 16:44 AutreContenu.txt drwxr-xr-x 8 hadrien users 4096 18 sept. 16:44 .git -rw-r--r-- 1 hadrien users 6 18 sept. 16:44 .gitignore

…on observe que le dossier MonDossier et le fichier Poubelle.log ne sont pas présents dans le clone.

Ces différences s’expliquent par le fait que le répertoire de travail d’un clone n’est pas une copie à l’identique de celui du dépôt d’origine, mais représente plutôt une copie du dernier commit enregistré dans le dépôt d’origine.

Ce commit ne contenait pas le dossier MonDossier puisqu’il s’agit d’un dossier vide, non géré par git, ni le fichier Poubelle.log puisqu’il est ignoré par git.

Si maintenant l’on compare les dépôts du point de vue de l’arbre de commits avec gitg

gitg & cd ../MonDepot gitg &

On constate que leur structure générale est similaire mais que le clone possède le dépôt original comme remote (sous le nom par défaut origin), et visualise simultanément sa version locale de la branche master et une copie locale de celle du dépôt original, origin/master.

C’est le fait de pouvoir différentier les versions locales et distantes de branches, comme ici master, qui permet d’utiliser git de façon distribuée sans connexion permanente à internet.

Pour créer une branche en vue d’y ajouter quelques commits, on peut par exemple utiliser le raccourci git checkout -b :

git checkout -b test echo 'Le contenu' > AutreContenu.txt git add AutreContenu.txt git commit -m 'Un commit de test' echo 'Plus de contenu' >> AutreContenu.txt git add AutreContenu.txt git commit -m 'Un autre commit de test'

À ce stade, le clone du dépôt n’est pas au courant de l’existence de ces commits et de cette nouvelle branche, puisqu’avec git les échanges entre dépôts sont déclenchés manuellement. On peut remédier à cela avec git fetch :

cd ../Exercice4 git fetch origin

Maintenant, le clone Exercice4 est au courant de l’existence de la branche test du dépôt MonDepot, qu’il représente comme la branche distante origin/test. Nous pouvons en créer une version locale et basculer dessus avec un raccourci basé sur git checkout :

git checkout test

Ensuite, nous pouvons rajouter des commits à cette branche locale, comme nous le ferions sur n’importe quelle autre branche locale :

echo "Renouvelons l'offre" > NouveauFichier.txt git add NouveauFichier.txt git commit -m "Ajout d'un fichier" echo 'Renouvelons la demande' >> NouveauFichier.txt git add NouveauFichier.txt git commit -m "Complétion d'un fichier"

Pour récupérer ces changements dans le dépôt d’origine, une façon de faire est d’ajouter notre clone comme remote de ce dernier…

cd ../MonDepot git remote add copieur ~/Desktop/Exercice4

…puis récupérer les changements de sa branche test et les intégrer au sein de notre branche test locale avec, par exemple, le raccourci git pull :

git pull copieur test

Pour terminer, ajoutons quelques commits sur la branche master de MonDepot :

git checkout master echo 'Je ne sais quoi inventer' > Incertitude.txt git add Incertitude.txt git commit -m 'Méditation' echo 'Je ne sais quoi penser' >> Incertitude.txt git add Incertitude.txt git commit -m 'Moment philosophique'

On peut propager ces changements sur le master de Exercice4 avec un simple git push :

git push copieur test

Si l’on souhaite intégrer les changements correspondants à la branche test du clone, il faudra comme précédemment s’y rendre, récupérer les changements, et les fusionner. Faisons cela avec git fetch et git merge :

cd ../Exercice4 git fetch origin git merge origin/master

Exercices TP5

Tout d’abord, rendons-nous dans notre clone du dépôt ddhc :

cd ~/Desktop/ddhc

On peut vérifier la configuration des remotes avec git remote -v :

git remote -v

Dans la variante « GitHub ouvert », on attend une sortie de ce genre…

origin git@github.com:francine.dupont/ddhc.git (fetch) origin git@github.com:francine.dupont/ddhc.git (push) upstream https://github.com/HadrienG2/ddhc.git (fetch) upstream https://github.com/HadrienG2/ddhc.git (push)

…avec origin qui pointe sur votre fork en connexion SSH, et upstream qui pointe sur le dépôt officiel en connexion HTTPS.

Dans la variante « GitLab fermé », on attend plutôt cette sortie…

origin git@gitlab.in2p3.fr:grasland/ddhc.git (fetch) origin git@gitlab.in2p3.fr:grasland/ddhc.git (push)

…avec origin qui pointe sur le dépôt officiel en connexion SSH.

Pour créer une nouvelle branche partant de la branche master, on commence par basculer sur la branche master

git checkout master

…puis on crée la nouvelle branche et bascule dessus…

git checkout -b copyright

…et on peut y enregistrer des changements avec les outils habituels :

echo -e '\n(C) 1789, Être Suprême Inc.' >> README.md git add README.md git commit -m "Ajout d'une notice de copyright"

On peut ensuite pousser la branche sur le dépôt origin avec git push. La première fois, on doit spécifier vers quelle remote on pousse, mais on peut le mémoriser avec --set-upstream :

git push --set-upstream origin copyright

Cette configuration fait que par la suite, si on a d’autres changements à pousser sur origin

echo 'AAAAAAH' >> README.md git add README.md git commit -m 'Panique à bord !' echo 'QQQQQQH' >> README.md git add README.md git commit -m 'Panique à bord en QWERTY !'

…on pourra utiliser la forme raccourcie de git push pour les mettre en ligne :

git push

Il est possible que la branche master du dépôt officiel évolue en parallèle de notre travail. On peut vérifier ce point en mettant à jour notre branche master locale :

git checkout master git pull --ff-only

Si la sortie de git pull signale des changements, alors il faudra mettre à jour nos branches de développement avec des outils comme git merge ou git rebase.

Pour conclure, mentionnons qu’un dépôt git distant sur lequel on pousse régulièrement nos commits est une copie de sauvegarde minimale de notre travail. Même si on supprimait malencontreusement une branche locale…

git branch -D copyright

…on pourrait toujours la récupérer à partir de la version sauvegardée sur le dépôt distant, via le raccourci désormais habituel :

git checkout copyright

De même, on pourrait remédier à une suppression accidentelle de branche distante en repoussant simplement la version locale de la branche. C’est le bon côté de la gestion de version distribuée : on a toujours au moins deux copies (plus ou moins à jour certes) de notre travail.