<< Retour à la page principale du cours


TD Outils - Préambule

Avant de commencer les TD Outils, vous devez télécharger le code disponible pour l'UE. Si vous connaissez déjà git ou sinon simplement en copiant/collant la ligne suivante dans un terminal :

git clone https://forge.univ-lyon1.fr/Alexandre.Meyer/L2_ConceptionDevApp.git

Sinon :




TD Outils - Partie 1 : éditeur de code, débogueur et diagramme

L'objectif de cette 1ère partie du TD est d'écrire un module (fichiers .h et .cpp) de gestion d'images. L'important est la manière de coder et les outils utilisés plus que la réalisation technique. Votre mini-programme comportera les fichiers Pixel.h/Pixel.cpp (le module Pixel), Image.h/Image.cpp (le module Image), les programmes principaux et un Makefile.
Ce TD outil est à réaliser sous Linux. ATTENTION, bien lire et respecter les consignes pour le rendu du module Image.


Le choix d'un éditeur de code

Un bon éditeur de code n'est pas un éditeur de texte. En effet, l'éditeur de code doit comporter les fonctionnalités suivantes :

  • Indentation automatique (on ne code pas tout aligné à gauche!)
  • Coloration du code
  • Compilation dans l'éditeur avec lien direct sur les erreurs. Le terminal est bien pour apprendre les commandes, le niveau suivant est de gagner en efficacité.
  • Les + quasiment indispensables d'un éditeur : auto-complétion lors de la frappe, recherche de définition de fonctions, renommage de variable ou de fonction (refactoring) dans tout le projet, etc.


Nous montrons principalement des copies d'écran de CodeBlocks mais donnons des liens vers d'autres outils qui sont tous aussi valables. L'objectif est que vous trouviez l'éditeur qui vous convient et surtout que vous soyez efficace avec. Choisissez parmi ces 6.

  • CodeBlocks : Linux/Windows 8-), bon compromis entre simple et complet :-o. Celui que nous recommandons et que vous avez déjà vu en LIFAP1. Déjà installé sur les machines de l'université.
  • CLion : Linux/Windows/Mac 8-), bon compromis entre simple et complet :-o. Gratuit pour les étudiants. Attention, il n'est pas installé sur les salles de l'université.
  • VisualStudioCode/VSCode très bien car multi-plateforme 8-) et avec de nombreux avantages (plugins, rapide, léger). L'éditeur qui monte, qui monte … il faut le configurer pour le C++ par exemple ici : https://code.visualstudio.com/docs/languages/cpp
  • Visual Studio : 8-) très bien, mais uniquement sous Windows. Si vous êtes Windows, il faut le connaitre (au moins pour votre CV) !
  • XCode 8-) : très bien mais seulement si vous êtes sous MAC. Si vous êtes sous Mac, il faut !
  • QtCreator : très bien si vous utilisez Qt mais pas que …


Les autres sont plus anecdotique pour du C++

  • CodeLite : une alternative à CodeBlocks
  • Emacs, Vim, Scite : si vous êtes prêt à passer du temps à les apprivoiser sinon passez votre chemin. Voici un turoriel Emacs
  • Sublimetext est un éditeur de code simple et léger. Il fait le job !
  • Eclipse : très complet, pas spécifique au langage C (parfois pénible à configurer). Tutorial1, Tutoria2, via CDT
  • NetBeans : il existe une version pour le C++
  • A éviter pour du code : Gedit, kate (etc.) sont de simples éditeurs de texte et ne sont pas bien adaptés au développement de code.


Remarques : Apprenez et utilisez les raccourcis clavier de votre éditeur de code. Il peut y avoir des questions là-dessus lors du contrôle :-) Vous devez rapidement ne plus toucher à votre souris 8-o, le gain de temps est considérable.



Présentation rapide de CodeBlocks

CodeBlocks est plus qu'un éditeur de code. C'est un “environnement de développement intégré” (IDE en anglais). CodeBlocks va gérer votre programme comme un projet. Vous pourrez par exemple déboguer directement dans l'éditeur.
Pour créer, compiler et exécuter un projet sous CodeBlocks:

  1. cd LIFAP4_TD
  2. codeblocks
  3. Cliquez sur “Create a new project”, sélectionnez “Empty project”
  4. Project title=LIFAP4_TD et Folder=/home/…/ (le chemin vers le répertoire du projet)
  5. Une fois votre projet créé, cliquez avec le bouton droit sur “LIFAP4_TD” à gauche puis sur “Add file” et choisissez 'main.cpp' ou bien “New file” et donner lui le nom de 'main.cpp' si vous n'avez pas déjà de fichier principal.
  6. Explorez le menu “Build” (Alt-b) pour apprendre les raccourcis clavier
    • F9 pour “Compile & Run” (le plus important)
    • Ctrl-F9 pour “Compile”
    • Ctrl-F10 pour “Run”
    • Alt-F2 pour aller à une erreur (si Alt-F2 est pris par le système, sinon allez dans “Settings/editor/shortcut” pour configurer vos raccourcis clavier).
    • Ctrl-espace pour compléter un nom de fonction ou un nom de variable (essayez en tapant 'pr' 'Ctrl-espace' pour voir apparaître printf).
    • Shift-Ctrl-x , Shift-Ctrl-c pour dé/commenter du code
    • Ctrl-Tab , Ctrl-Shift-Tab pour naviguer dans les onglets

Voir également ce tutoriel si besoin.

Prenez le temps de bien choisir votre éditeur.


Le module Image

Une image est en quelque sorte un tableau à 2 dimensions de largeur dimx et de hauteur dimy, dont les éléments sont des pixels. En interne, nous allons allouer un tableau 1D de taille dimx*dimy. En externe (ie. le code utilisant le module Image) nous interpréterons l'image avec deux dimensions (x,y) en passant par les fonctions getPix (un accesseur) et setPix (un mutateur). Les définitions de classes vous sont données ci-dessous en langage algorithmique.

1. Créez les fichiers Pixel.h, Pixel.cpp, Image.h et Image.cpp, et traduisez et implémentez les classes en C++. N'oubliez pas de compiler AU FUR ET A MESURE. N'attendez pas d'avoir écrit toutes les fonctions membres pour compiler. Ne modifiez pas les noms des classes, membres, paramètres, etc.

Classe Pixel

 privé :

   r,g,b : entier(0..255)   // les composantes du pixel, unsigned char en C++

 public :

   // Constructeur par défaut de la classe: initialise le pixel à la couleur noire
   Constructeur Pixel ()

   // Constructeur de la classe: initialise r,g,b avec les paramètres
   Constructeur Pixel (nr, ng, nb : donnée entier(0..255) )

   // Accesseur : récupère la composante rouge du pixel
   Fonction getRouge () -> entier(0..255)

   // Accesseur : récupère la composante verte du pixel
   Fonction getVert () -> entier(0..255)

   // Accesseur : récupère la composante bleue du pixel
   Fonction getBleu () -> entier(0..255)

   // Mutateur : modifie la composante rouge du pixel
   Procédure setRouge (nr : donnée entier(0..255))

   // Mutateur : modifie la composante verte du pixel
   Procédure setVert (ng : donnée entier(0..255))

   // Mutateur : modifie la composante bleue du pixel
   Procédure setBleu (nb : donnée entier(0..255))

FinClasse
Classe Image

 privé :

   tab : tableau de Pixel     // le tableau 1D de pixel
   dimx, dimy : entier        // les dimensions de l'image

 public :

   // Constructeur par défaut de la classe: initialise dimx et dimy à 0
   // ce constructeur n'alloue pas de pixel
   Constructeur Image ()

   // Constructeur de la classe: initialise dimx et dimy (après vérification)
   // puis alloue le tableau de pixel dans le tas (image noire)
   Constructeur Image (dimensionX, dimensionY : donnée entier);

   // Destructeur de la classe: déallocation de la mémoire du tableau de pixels
   // et mise à jour des champs dimx et dimy à 0
   Destructeur Image ()

   // Accesseur : récupère le pixel original de coordonnées (x,y) en vérifiant leur validité
   // la formule pour passer d'un tab 2D à un tab 1D est tab[y*dimx+x]
   Fonction getPix (x,y : donnée entier) -> 'Pixel' (l'original, pas une copie)

   // Mutateur : modifie le pixel de coordonnées (x,y)
   Procédure setPix (x,y : donnée entier; couleur : donnée Pixel)

   // Dessine un rectangle plein de la couleur dans l'image (en utilisant setPix, indices en paramètre compris)
   Procédure dessinerRectangle (Xmin,Ymin,Xmax,Ymax : donnée entier; couleur : donnée Pixel)

   // Efface l'image en la remplissant de la couleur en paramètre
   // (en appelant dessinerRectangle avec le bon rectangle)
   Procédure effacer (couleur : donnée Pixel)

   // Effectue une série de tests vérifiant que le module fonctionne et
   // que les données membres de l'objet sont conformes
   Procédure testRegression ()

FinClasse

dessinerRectangle allume les pixels de l'image qui sont compris dans le rectangle défini par le coin en haut à gauche (Xmin,Ymin) jusqu'au point en bas à droite (Xmax,Ymax), comme ceci :


2. Ecrivez la procédure testRegression qui teste votre module Image dans tous les cas possibles d'utilisation. Soyez le plus exhaustif possible.

3. Créez un programme principal nommé mainTest.cpp qui contient le code suivant (simple appel à la procédure de test de regréssion).
mainTest.cpp (produisant l'exécutable bin/test):

#include "Image.h"
 
int main() {
   Image monImage;
   monImage.testRegression();
   return 0;
}

Voici quelques règles de bonne programmation à respecter :

  • Écrivez des accesseurs get et des mutateurs set pour accéder à vos données et surtout utilisez les. Ils doivent faire des vérifications importantes
  • A part les fonctions de Image.cpp, aucune autre partie du code accède directement aux données membres de la classe
  • Les paramètres sont souvent passés par référence
  • Faites des vérifications de dimension dimx, dimy, x, y avec des assert
  • Mettez des const partout où vous pouvez (paramètres et fonctions membres)

Il est important de comprendre la différence entre la pile et le tas. De comprendre que l'allocation se fait sur un tableau 1D car c'est la seule solution qu'offre new, mais que de l'extérieur à la classe Image les codeurs veulent travailler avec des informations 2D. Les accesseurs font donc la conversion pour gérer les données internes.

Debug (GDB)

Trois fonctions d'entrée/sortie sauver (sauver une image dans un fichier), ouvrir (ouvrir une image depuis un fichier) et afficherConsole (afficher les valeurs des pixels sur la console) sont données dans le fichier TD_moduleImage/IOimage.cpp de l'archive fournie.

Vous devez tout d'abord les incorporer dans votre code (ie. les ajouter au module Image). Des bugs ont été placés intentionnelement dans ces trois fonctions :-? !!Vous devez les trouver et les corriger en utilisant GDB. Pour ceci vous pouvez tester votre programme avec une petite image (ex. de taille 3×2) et dérouler le code pas à pas.

  1. D'abord directement dans un terminal
  2. Puis en utilisant le débugueur intégré de CodeBlocks

Une fois ces trois fonctions corrigées, dans votre module Image, créez un deuxième exécutable nommé mainExemple.cpp qui contient le code suivant. Attention, vous devez lancer l'exécutable à partir du dossier racine avec la commande bin/exemple. Ceci est valable pour les trois exécutables du module Image.
mainExemple.cpp (produisant l'exécutable bin/exemple):

#include "Image.h"
 
int main() {
 
    Pixel rouge (120, 15, 10);
    Pixel vert (20, 202, 15);
    Pixel bleu (4, 58, 218);
 
    Image image1 (64,48);
    image1.effacer(bleu);
    image1.dessinerRectangle(5, 20, 30, 40, rouge);
    image1.setPix(51,4,vert);
    image1.setPix(20,30,vert);
    image1.sauver("./data/image1.ppm");
 
    Image image2;
    image2.ouvrir("./data/image1.ppm");
    image2.dessinerRectangle(29, 10, 48, 15, rouge);
    image2.dessinerRectangle(25, 24, 40, 45, vert);
    image2.sauver("./data/image2.ppm");
 
    return 0;
}

Diagramme des classes UML

UML est un langage graphique d'analyse et de conception de logiciel ou de système complexe. UML est standardisé et largement utilisé. UML vise plutôt une conception orientée objet que vous avez pu commencer à appréhender en LIFAP3 et LIFAP4. Voir le cours de LIFAP4, ainsi qu'une explication à propos des diagrammes de classes sur Wikipédia.

Vous aurez à plusieurs moments de ce cours à réaliser des diagrammes des classes de vos programmes. Pour l'édition de ce diagramme des classes UML, nous vous proposons plusieurs outils dans la section "Doc, outils et tuto". Vous avez par exemple Umbrello ou Dia installé sur les ordinateurs de l'Université. Par exemple avec Dia :

  • sélectionnez l'outil UML (liste déroulante sur la gauche)
  • définissez vos Class et ajoutez tous leurs membres
  • le passage de paramètres est in pour donnée et inout pour donnée-résultat
  • ajoutez les flèches de relation entre les classes (outil ligne): les flèches pleines pour indiquer qu'une classe instancie un objet d'une autre classe, et les flèches pointillées pour indiquer qu'une classe à besoin d'une autre classe.

Remarque : sur les machines du Nautibus si Umbrello ou Dia ne sont pas installé, utilisez alors un outil en ligne comme ceux proposez dans la section UML de "Doc, outils et tuto".


A Faire. Réalisez le diagramme des classes UML du programme comportant les classes Image et Pixel : ce travail n'aura pas besoin d'être rendu mais il constitue un bon entrainement pour la réalisation de votre future diagramme des classes UML de projet.



Documentation de code (doxygen)

Pour générer la documentation de votre code au format HTML :

   # créez le fichier doxygen en tapant:
   doxygen -g doc/image.doxy
   # personnalisez le fichier doxygen (au minimum INPUT et OUTPUT_DIRECTORY) en tapant :
   gedit doc/image.doxy
   # generez la documentation en tapant:
   doxygen doc/image.doxy
   # ouvrez la page principale générée avec Firefox (ou autre browser) en tapant:
   firefox doc/html/index.html

Remarques :


A faire : réaliser la documentation doxygen du code de Pixel et de Image.



TD Outils - Partie 2 : Gestion de mémoire/Optimisation de code

  • Compilez le code présent dans le répertoire TD_valgrind de l'archive fournie
  • Exécutez le
  • Regardez le code de main.cpp pour comprendre ce qui est calculé
  • Ce code a différents problèmes : lenteur, et deux types de mauvaises gestions de la mémoire.

Question : En utilisant valgrind qui va nous donner des informations sur l'exécution du programme, vous devez résoudre les problèmes de lenteur et de mémoire : fuite de mémoire (memory leak), accès invalide dû à des débordements, etc.

Mémoire perdu (memory leak) et accès mémoire non autorisé

Par défaut, valgrind permet de vérifier si les allocations mémoires se passent bien. En particulier, de savoir si vous ne débordez pas d'un tableau (ex: int t[10]; t[12]=14;), de savoir si tous les new correspondent à des delete dans le programme, etc.

$> valgrind --tool=memcheck --leak-check=full ./prog

==20689== Invalid write of size 4
==20689==    at 0x804859D: main (main.cpp:23)
==20689==  Address 0x4286FA0 is 0 bytes after a block of size 24 alloc'd
==20689==    at 0x4022A55: operator new[](unsigned int)
==20689==    by 0x8048541: main (main.cpp:18)

Ceci indique qu'il y a des problèmes d'écriture mémoire non autorisée dans main.cpp à la ligne 23, ce qui est sûrement dû à un problème de taille d'allocation ou d'indice de tableau. Pour cela valgrind vous indique la ligne d'allocation mémoire de la variable mise en cause (ici le tableau f1) à la ligne 18. Faites la correction nécessaire pour résoudre ce problème, ainsi que celles nécessaires pour résoudre d'autres problèmes d'allocation et d'accès.

De plus, dans la rubrique “LEAK SUMMARY” à la fin vous trouverez que 24 octets sont perdus car ce programme ne fait pas le bon nombre de delete. Faites le bon nombre de libérations mémoire et vérifiez que votre programme est propre en relançant valgrind. Faites la même chose pour votre module Image afin de vérifier si vous n'avez pas de fuite mémoire.

Optimisation de code

Pour optimiser votre code vous devez savoir où votre programme passe le plus de temps :

$> valgrind --tool=callgrind ./prog
$> callgrind_annotate callgrind.out.20092

La 1ère ligne a produit un fichier de statistique : callgrind.out.20092 (nom automatiquement généré, change à chaque exécution). La 2ème ligne permet de visualiser les statistiques du fichier :

--------------------------------------------------------------------------------
         Ir  file:function
--------------------------------------------------------------------------------
2,028  Calcul.cpp:intAdd(int, int) [/home/.../prog]
  570  Calcul.cpp:intMul(int, int) [/home/.../prog]

Ce programme passe 2028 fois dans intAdd et 570 fois dans intMul. C'est donc la fonction intAdd qu'il faut optimiser en priorité. Regardez et changez le code de intAdd pour avoir un programme plus efficace. Relancer valgrind pour voir le gain de performance obtenue. Faire éventuellement d'autres modifications du code pour gagner encore plus. Pour vous rendre compte du gain apporté, vous pouvez refaire l'expérience avec une valeur MAX plus grande.

Pour aller plus loin avec valgrind



TD Outils - Partie 3 : Bibliothèques

TXT et SDL2

Vous trouverez le code d'un embryon du jeu Pacman dans le répertoire du même nom dans l'archive fournie. Le projet Pacman peut être compilé sous Linux ou sous Windows à l'aide du Makefile ou du projet CodeBlocks qui utilise le Makefile. Si vous compilez sous Windows sur votre portable les bibliothèques Windows sont incluses dans le répertoire extern. Sous Linux à l'université toutes les bibliothèques nécessaires sont installées par défaut sur les machines. Sous Linux sur votre portable vous devez installer SDL2, SDL2_image , SDL2_ttf et SDL2_mixer comme ceci:

$> sudo apt-get install libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsdl2-mixer-dev

L'objectif du TD est de vous familiariser avec SDL2, et de l'intégrer à votre module Image. Prenez donc du temps pour explorer le code, et plus particulièrement les modules Jeu, sdlJeu et txtJeu.

SDL2 dans le module Image

Dans votre module Image, créez un troisième programme principal nommé mainAffichage.cpp qui contient impérativement le code suivant, sans le modifier pour le script de notation.
mainAffichage.cpp (produisant l'exécutable bin/affichage):

#include "Image.h"
 
int main (int argc, char** argv) {
 
   Image image (11,11);
 
   Pixel gris (226, 226, 226);
   Pixel vert (1, 130, 0);
   Pixel noir (0, 0, 0);
   Pixel beigeC (210, 188, 154);
   Pixel beigeF (168, 105, 8);
   Pixel marron (102, 65, 8);
 
   image.effacer(gris);
   image.dessinerRectangle(3,0,7,10,vert);
   image.dessinerRectangle(0,1,10,1,vert);
   image.setPix(2,2,vert);
   image.setPix(8,2,vert);
   image.setPix(3,2,gris);
   image.setPix(7,2,gris);
   image.setPix(4,2,noir);
   image.setPix(6,2,noir);
   image.dessinerRectangle(1,5,9,6,vert);
   image.setPix(5,10,gris);
   image.dessinerRectangle(9,7,9,10,marron);
   image.dessinerRectangle(2,5,8,6,beigeC);
   image.dessinerRectangle(3,7,7,9,beigeC);
   image.dessinerRectangle(4,5,6,6,beigeF);
   image.setPix(5,7,beigeF);
 
   image.afficher();
 
   return 0;
}

La procédure afficher() du module Image est à ajouter dans votre classe Image et est la suivante:

 // Affiche l'image dans une fenêtre SDL2
 Procédure afficher ()

Vous devez vous inspirez du code du Pacman pour implémenter cette procédure (module sdlJeu). Vous aurez probablement à créer des fonctions membres intermédiaires qui seront privées à la classe (ex. afficherInit, afficherBoucle et afficherDetruit). L'image sera placée au centre d'une fenêtre SDL2 de taille 200×200 pixels de fond gris clair et vous devrez permettre de zoomer/dézoomer sur votre image grâce aux touches T et G et quitter la procédure afficher() grâce à la touche ESCAPE.

Valgrind et les bibliothèques : SDL2

Si vous lancez valgrind sur un exécutable utilisant une bibliothèque comportant des fuites mémoire, vous obtiendrez ces fuites même si votre code libère bien toute la mémoire allouée que vous allouez. Elles apparaissent pour la plupart en still reachable, ce qui correspond à des zones de mémoire sur lesquelles on dispose encore de pointeurs et que l'on aurait pu désallouer si on l'avait voulu. Ces fuites (qui n'en sont pas vraiment…) relèvent du fonctionnement interne des bibliothèques et sont indépendantes de votre volonté. Elles ne risquent pas de faire planter votre programme mais gênent la recherche de vrais bugs.
Heureusement, pour ne voir que vos fuites mémoire, il est possible d'indiquer à valgrind d'ignorer ces erreurs, en utilisant le fichier de suppression valgrind_lif7.supp fourni dans l'archive, et en spécifiant les options adéquates lors de l'exécution de valgrind :

$> valgrind --leak-check=full --num-callers=50 --suppressions=./valgrind_lif7.supp --show-reachable=yes -v NOM_DE_L'EXECUTABLE

Les fuites mémoire propres à SDL2 sont toujours dénombrées mais apparaissent désormais en suppressed. Documentez vous sur valgrind pour comprendre le sens des options.



TD Outils - Partie 4 : Gestionnaire de version (Git)

Créer un projet
L'université a mise en place une forge (lien) que vous utiliserez pour gérer les versions de votre TP projet. Pour créer un nouveau dépôt forge pour votre projet, un des membres du groupe doit suivre la procédure ci-dessous (il est nécessaire d'avoir un compte actif à l'université).

  • Se connecter à la forge (sign in with CAS) avec votre identifiant et mot de passe Lyon 1
  • Cliquer sur “New project”
  • Donner un nom à votre projet dans la case “Project name” (ex. le nom de votre application/jeu ou de votre groupe)
  • Cliquer sur “Create project”
  • Votre projet est prêt, un résumé des commandes s'affiche

Ensuite vous devez ajouter les autres membres du groupe en tant que contributeur:

  • Naviger dans la barre de gauche dans “Settings > Members”
  • Rechercher et sélectionner les membres du groupe dans la case de sélection (par numéro d'étudiant ou nom)
  • Choisir le rôle de “Developer” ou “Master”
  • Cliquer sur “Add to project”

Pour le TP projet (mais pas pour le module Image), n'oubliez que vous aurez à ajouter votre encadrant de TP (qui sera indiqué sur Tomuss) en tant que “Reporter” avant la fin du semestre.

Pour créer votre version locale:

  • Récupérer l'URL HTTPS git de votre projet dans la page d'accueil du projet, sous le titre après avec avoir basculé de SSH en HTTPS. L'adresse doit être de la forme https://forge.univ-lyon1.fr/NUMERO_ETU/NOM_PROJET.git où NUMERO_ETU est le numéro étudiant de celui qui a créé le projet (namespace en terme git) et NOM_PROJET est le nom du projet indiqué à la phase de création
  • Vous pouvez aussi maintenant accéder directement à la page de votre projet forge à l'adresse https://forge.univ-lyon1.fr/NUMERO_ETU/NOM_PROJET
  • Dans un terminal placez vous dans le dossier où vous souhaitez développer votre projet (votre copie de travail locale)
  • Clôner le dépôt (pour l'instant vide) pour créer cette copie de travail locale (login et mot de passe Lyon 1) en tapant:
git clone https://forge.univ-lyon1.fr/NUMERO_ETU/NOM_PROJET.git

Tous les étudiants membres du projet doivent éxecuter cette commande sur leur propre compte pour pouvoir travailler sur le projet (après qu'ils aient été ajoutés en tant que membres). Cette opération n'est à faire qu'une seule fois pour chaque étudiant.

Travailler avec git
Une fois le répertoire de travail mis en place, vous pouvez effectuer des modifications (ajout de fichiers, suppression, modification etc.).

  • Pour ajouter un fichier (fichier déjà ajouté localement) : git add nom_fichier
  • Pour supprimer un fichier (fichier encore présent localement) : git rm nom_fichier
  • Pour déplacer un fichier : git mv nom_fichier_origine nom_fichier_cible
  • Pour valider les modifications : git commit -a -m “un message pour expliquer les modifications”
  • Pour envoyer les modifications sur le dépôt : git push
  • Pour récupérer des modifications depuis le dépôt : git pull
  • La réconciliation des changements peut nécessiter une fusion que git tentera de faire automatiquement (remplacer pull par fetch pour fusionner manuellement ensuite via git merge ou git rebase). S'il y a des conflits, git laissera un marquage directement dans le fichier, contenant le code de la branche courante, et celui de la branche que vous voulez fusionner. Vous devrez alors corriger le problème manuellement et finir avec un commit.

Sous Windows vous pouvez remplacer les commandes du terminal par les outils suivants : TortoiseGit et Git for Windows.