Aller au contenu

Atelier 03

Dans cette séance de laboratoire, vous pratiquerez les bases de la ligne de commande de git et une stratégie pour garder le dépôt sans encombrement. Vous n'avez pas besoin de télécharger de nouveau code pour cette séance de laboratoire.

Commandes Git

L'outil en ligne de commande git vous permet d'initialiser ou de répliquer des dépôts, de consulter et modifier l'état du graphe git, et de résoudre des commits concurrents en conflit.

  • Lors du dernier cours, vous avez appris la théorie et les commandes de base pour les situations les plus élémentaires.
  • C'est maintenant à votre tour de développer vos compétences pratiques avec l'outil en ligne de commande git.

Configuration d'un dépôt en ligne

Les dépôts peuvent être initialisés localement ou côté serveur. Dans ce premier exercice, vous allez initialiser un dépôt localement, puis transférer l'état complet de votre dépôt à une copie côté serveur.

À vous de jouer

  • Configurez un dépôt d'exemple local
    • Créez un nouveau dossier de projet, par exemple lab04.
    • Allez dans votre dossier et créez un nouveau fichier texte, par exemple lapin.txt.
    • Copiez votre animal ascii-art commun préféré dans le fichier texte. Vous pouvez aussi utiliser cet exemple :

             ,\
             \\\,_
              \` ,\
         __,.-" =__)
       ."        )
    ,_/   ,    \/\_
    \_|    )_-\ \_-`
       `-----` `--`
* Initialisez votre dépôt local avec la commande git init. * Utilisez la séquence de add et commit vue en classe pour créer un premier commit contenant votre fichier d'art ascii. * Préparez un dépôt côté serveur * Connectez-vous au serveur GitLab de l'UQÀM * Créez un nouveau projet avec une visibilité privée * Utilisez les commandes vues lors du dernier cours pour lier votre dépôt local préalablement créé au projet côté serveur * Synchronisez le dépôt serveur (distant) * Poussez votre premier commit local vers le serveur (n'oubliez pas l'option origin pour le premier commit) * Actualisez la page du projet et vérifiez que votre art ascii est bien stocké côté serveur

Diagnostics

Git utilise un modèle de graphe en interne, où les commits sont des nœuds du graphe. Il est essentiel de connaître l'état du graphe et les changements dans les fichiers locaux qui sont en attente d'être ajoutés au graphe. En classe, vous avez appris deux commandes git pour obtenir des diagnostics.

À vous de jouer

  • Utilisez la commande git log pour inspecter les commits dans votre dépôt.
    • Lors du dernier cours, nous avons vu une extension de la commande git log, qui vous permet d'afficher une représentation textuelle de la façon dont les commits sont connectés. Utilisez cette extension et comparez la sortie. Qu'est-ce qui a changé ?
    • git log n'affiche que des informations sur les commits, mais pas sur les modifications récentes des fichiers, qui pourraient être ajoutées aux commits suivants. Quelle commande est utilisée pour inspecter comment les fichiers locaux se rapportent au dernier commit ?
  • Utilisez git status et lisez attentivement la sortie.
  • Modifiez l'état local de votre dépôt :
    • Créez un nouveau fichier, par exemple quoiquecesoit.txt.
    • Modifiez également un peu votre animal ascii, par exemple ajoutez une ligne avec "<3 <3 <3".
  • Relancez git status, puis lisez attentivement la sortie.
    • Quelle est la sémantique de "Changes to be committed"? Expliquez la sortie.
    • Quelle est la sémantique de "Changes not staged to commit"? Expliquez la sortie.

Vous devriez maintenant avoir au moins deux commits dans votre graphe. En classe, vous avez vu une commande pour naviguer entre les commits, c'est-à-dire changer l'état visible de votre répertoire en fonction de l'état d'un commit précédent.

À vous de jouer

  • Trouvez la ligne de commande pour naviguer dans le graphe et utilisez-la pour revenir à l'état de l'animal ascii avant d'avoir ajouté "<3 <3 <3". Faites-le sans modifier l'animal ascii manuellement.
  • Inspectez
    • Inspectez le fichier pour vérifier que vous avez bien rétabli les changements.
    • Utilisez les commandes de diagnostic vues ci-dessus pour inspecter le graphe de commits git.
Qu'est-il arrivé au commit le plus récent ? A-t-il été définitivement supprimé ?

Non, votre dernier commit est toujours là. Cependant, en utilisant la commande checkout, vous êtes passé en mode "detached head", c'est-à-dire que votre graphe n'affiche que les commits jusqu'au commit que vous avez consulté.

  • Enfin, restaurez le "<3 <3 <3" que vous avez retiré.
    • Ne modifiez pas manuellement l'animal ascii pour restaurer le "<3 <3 <3".
    • Utilisez la commande git correspondante pour rattacher votre head, c'est-à-dire revenir au dernier commit du graphe.

Clonage du dépôt local

Jusqu'à présent, vous avez créé un dépôt local et l'avez lié à un dépôt côté serveur. La tâche suivante consiste à créer une autre copie du dépôt sur une deuxième machine locale. Associez-vous avec la personne à côté de vous et créez un deuxième clone de dépôt local sur leur machine.

À vous de jouer

  • Créez une deuxième copie locale en suivant les étapes ci-dessous :
    • Connectez-vous au serveur GitLab de l'UQÀM, trouvez les paramètres du projet et ajoutez votre voisin en tant que développeur.
    • Demandez à votre voisin d'ouvrir un terminal et de cloner votre dépôt en utilisant l'adresse unique du dépôt.
    • Une fois le dépôt répliqué sur la machine de votre voisin, ouvrez le fichier ascii et vérifiez que le contenu est correct.
  • Apportez une modification sur la copie de dépôt de votre voisin.
    • Modifiez à nouveau l'art ascii, par exemple ajoutez un autre "<3" sous l'animal ascii.
    • Créez un nouveau commit avec les modifications et poussez-le sur le serveur gitlab.
  • Connectez-vous à l'interface web de GitLab et vérifiez que les dernières modifications ont bien été prises en compte.
  • Sur votre propre ordinateur, "synchronisez-vous" avec les dernières modifications en récupérant le dernier commit depuis le serveur GitLab.
  • Inspectez le graphe git et vérifiez que les deux machines affichent le même historique de commits.

Création de conflits

Les conflits git se produisent lorsque deux développeurs créent des commits divergents.

  • Dans l'exemple suivant, vous allez vous associer avec votre voisin pour chacun apporter des modifications conflictuelles à l'art ascii, et créer des commits divergents.
  • Ensuite, lorsque vous tenterez tous les deux d'envoyer vos commits au serveur, le second commit sera rejeté. Vous verrez un message d'erreur similaire à :

À vous de jouer

  • Sur chacun de vos clones locaux, faites un changement différent à votre animal ascii.
    • Sur la première machine : remplacez les yeux de l'animal par des symboles @.
    • Sur la deuxième machine : remplacez les yeux de l'animal par des symboles *.
  • Chacun créez un nouveau commit avec vos modifications et tentez de le pousser vers le serveur GitLab.
    • GitLab acceptera le premier commit, mais rejettera le second avec un message d'erreur indiquant que votre dépôt local manque des commits distants et que vous devez résoudre manuellement le conflit en premier.
  $ git push
  To gitlab.info.uqam.ca:max/mytestrepo.git
  ! [rejected]        main -> main (fetch first)
  error: failed to push some refs to 'gitlab.info.uqam.ca:max/mytestrepo.git'
  hint: Updates were rejected because the remote contains work that you do
  hint: not have locally. This is usually caused by another repository pushing
  hint: to the same ref. You may want to first integrate the remote changes
  hint: (e.g., 'git pull ...') before pushing again.
  hint: See the 'Note about fast-forwards' in 'git push --help' for details.
  • Le message d'erreur vous indique déjà comment vous préparer à résoudre l'état de conflit : git pull, pour récupérer tous les commits côté serveur qui vous manquent actuellement localement.
    • Lors du git pull, votre état local doit être fusionné avec le commit en conflit sur le serveur.
    • La première fois que vous rencontrez ce conflit, git vous demandera quelle stratégie appliquer pour résoudre le conflit.
  $ git pull
  warning: no common commits
  remote: Enumerating objects: 3, done.
  remote: Counting objects: 100% (3/3), done.
  remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
  Unpacking objects: 100% (3/3), 202 bytes | 67.00 KiB/s, done.
  From gitlab.info.uqam.ca:max/mytestrepo
   * [new branch]      main       -> origin/main
  hint: You have divergent branches and need to specify how to reconcile them.
  hint: You can do so by running one of the following commands sometime before
  hint: your next pull:
  hint:
  hint:   git config pull.rebase false  # merge
  hint:   git config pull.rebase true   # rebase
  hint:   git config pull.ff only       # fast-forward only
  hint:
  hint: You can replace "git config" with "git config --global" to set a default
  hint: preference for all repositories. You can also pass --rebase, --no-rebase,
  hint: or --ff-only on the command line to override the configured default per
  hint: invocation.
  fatal: Need to specify how to reconcile divergent branches.

Sélection d'une stratégie de fusion

Il existe plusieurs façons de résoudre les états conflictuels, que nous approfondirons dans une future leçon. La première fois que vous rencontrez un conflit, git vous demandera quelle stratégie appliquer. Configurez git pour utiliser "merge", avec la commande : git config pull.rebase false.

  • Notez que dans tous les cas, vous devrez résoudre manuellement les modifications conflictuelles apportées au même fichier.
    • Après la commande pull, git vous indiquera que la fusion automatique de vos deux commits est impossible, car vous avez modifié le même fichier (les yeux de l'animal ascii : @ vs *) :
Auto-merging rabbit.txt
CONFLICT (content): Merge conflict in rabbit.txt
Automatic merge failed; fix conflicts and then commit the result.

Résolution des conflits

Les commits conflictuels surviennent dans tous les projets. Dans cet exercice, vous apprendrez à résoudre le problème manuellement.

À vous de jouer

               ,\
               \\\,_
<<<<<<< HEAD
                \` @\
=======
                \` *\
>>>>>>> 9966a96a57cee347939c2026c34d9823be7a56ad
           __,.-" =__)
         ."        )
      ,_/   ,    \/\_
      \_|    )_-\ \_-`
         `-----` `--`
  • Les lignes marquées commençant par <<<, === et >>> indiquent où les différents commits divergent :
    • Les lignes entre <<<<<<< HEAD et ======= indiquent les modifications que vous avez effectuées.
    • Les lignes entre ======= et >>>>>>> 9966a96a... indiquent les modifications récupérées du commit en conflit.
  • Pour résoudre le conflit, vous devez décider quelle version doit être conservée :
    • Supprimez toutes les lignes marquées et ne gardez qu'une des versions en conflit, par exemple \ *`.
  • Enfin, partagez la solution du conflit avec votre partenaire :
    • Ajoutez le fichier à un nouveau commit, mettez "fixed merge conflict" comme commentaire et poussez-le sur le serveur.
    • Récupérez le commit depuis l'autre ordinateur. Vous ne devriez pas voir de conflit cette fois, car le commit de fusion que vous venez de créer a déjà résolu le conflit.
Inspectez le graphe git, qu'est-il arrivé aux commits en conflit ?

git log montrera une bifurcation où le commit pour "* comme yeux" a pris un autre chemin que "@ comme yeux". Ensuite, il y a un commit supplémentaire réunissant les chemins. Ceci est une représentation graphique de ce qui s'est passé dans la réalité : vous et votre partenaire êtes partis du même état de code (commit), vous avez tous les deux apporté des modifications divergentes, et ensuite vous vous êtes réunis sur un terrain d'entente.

Exclusions de fichiers

Dans l'exercice précédent, vous avez pu résoudre manuellement des conflits dans un fichier en modifiant les versions conflictuelles dans un éditeur de texte.

  • La résolution manuelle des conflits fonctionne bien pour les fichiers sources (ou tout autre type de fichier pouvant être modifié dans un éditeur de texte), mais absolument pas pour les fichiers binaires.
  • Imaginez simplement que vous deviez décider quelle version est correcte entre deux fichiers de bytecode marqués ( CAFEBABE...).

Gardez les fichiers binaires hors de votre dépôt

Il est important de garder les fichiers binaires hors de votre dépôt, car il n'existe aucun moyen raisonnable de gérer les conflits. Cela vaut également pour les fichiers générés, car ils ont tendance à être longs et difficiles à lire. Les exemples incluent les fichiers .class, les fichiers PDF, les images JPG/PNG, mais aussi la documentation JavaDoc générée (html) et les fichiers jar. Le dépôt ne doit contenir que ce qui est nécessaire pour construire (compiler) le projet, jamais la version compilée.

Gitignore

Les fichiers binaires ou générés sont facilement ajoutés par accident. Il est donc conseillé de configurer git pour rejeter certains types de fichiers dès le départ. Lors de la dernière unité de cours, vous avez vu comment un fichier .gitignore peut être utilisé pour configurer cela.

À vous de jouer

  • Créez un nouveau projet Hello-World dans un dossier dédié.
    • Vous pouvez ajouter ce projet comme sous-dossier de votre projet existant d'animaux ASCII.
  • Utilisez le compilateur Java pour compiler votre programme.
    • Utilisez la commande de diagnostic pour interroger les nouveaux fichiers détectés par git.
    • Vous devriez voir de nouveaux fichiers class générés, que git liste comme des "fichiers non suivis".
  • Créez un fichier .gitignore qui exclut les fichiers binaires, par exemple les fichiers class.
    • Utilisez le générateur toptal pour générer le contenu du fichier .gitignore.
    • Inspectez la sortie et copiez-la dans votre fichier .gitignore.
  • Exécutez à nouveau git status, comment la sortie a-t-elle changé ? Que signifie la sortie modifiée ?
  • Exécutez la commande dangereuse git add . qui ajoute tout dans votre dépôt.
    • Inspectez à nouveau le statut de git, lorsque vous jugez que la sortie est propre, validez et poussez vers le serveur.
    • Inspectez le statut côté serveur et vérifiez qu'il n'y a pas de fichiers class sur le serveur.

Bonus Fiche-mémo

Les commandes que vous avez utilisées jusqu'à présent sont assez basiques et vous en aurez régulièrement besoin.

Créez une fiche-mémo et des cartes flash

Vous pouvez accélérer considérablement votre développement de TP en développant vos compétences avec les commandes git appropriées pour les situations standard ci-dessus. Créez une fiche-mémo et des cartes flash, et entraînez-vous régulièrement pour mémoriser les commandes les plus courantes. Plus tard, vous utiliserez des outils graphiques pour interagir avec git, mais il est toujours utile de connaître les commandes, par exemple pour résoudre un problème sur un serveur où vous n'avez accès qu'à la ligne de commande. Cela portera ses fruits, garanti.