Gestion de versions et collaborationDans le dialogue d’impression, choisissez « Enregistrer au format PDF » comme destination.
Retour

Génie logiciel · C5 Tests et outillage · Chapitre 2 · 4 h

Gestion de versions et collaboration

Git : dépôt, commit, historique ; branches et fusion ; résolution de conflits ; dépôt distant et travail à plusieurs ; suivi des tâches ; bonnes pratiques de messages de commit.

Un projet d'équipe pose un problème que le code seul ne résout pas : plusieurs personnes modifient les mêmes fichiers en même temps. Sans outil, c'est le chaos — on s'envoie des fichiers par courriel, on écrase le travail de l'autre, on ne sait plus quelle version est la bonne. La gestion de versions règle ce problème, et Git en est l'outil universel. Comme pour les tests (chapitre 8), sa valeur s'éprouve plutôt qu'elle ne se raconte : tant qu'on n'a pas perdu du travail faute de versionnage, ou résolu un conflit dans la panique, on croit pouvoir s'en passer.

Dans votre projet, Git s'utilise dès la première semaine — pas à la fin. C'est l'infrastructure de tout le reste.

Le dépôt, le commit, l'historique

Un dépôt (repository) est un dossier de projet dont Git suit l'histoire complète. À chaque étape stable de votre travail, vous créez un commit : un instantané de l'état du projet, daté, signé, accompagné d'un message qui décrit ce que vous avez changé.

L'ensemble des commits forme l'historique — une suite d'instantanés qui raconte la vie du projet. Cet historique n'est pas décoratif : il permet de revenir en arrière (annuler une modification qui casse tout), de comprendre pourquoi une ligne a été écrite (qui, quand, dans quel commit), et de retrouver l'état exact du projet à n'importe quelle date. Un projet versionné n'a jamais « perdu » de travail : tout état passé est récupérable.

Le message de commit mérite un soin particulier, car il s'adresse au futur — vos coéquipiers, et vous-même dans six mois. Un bon message dit ce qui a changé et pourquoi, en une ligne claire : Corrige le calcul de TVA sur les livres vaut infiniment mieux que modif, fix, ou ça marche enfin. L'historique est une documentation gratuite — à condition d'écrire les messages pour qu'on puisse les relire.

Quiz · 1 question

Qu'est-ce qu'un bon message de commit, et pourquoi cela compte-t-il ?

  • Un message court comme « modif » ou « fix » : l'important est de committer souventcourt peu importe le sens
  • Un message qui dit ce qui a changé ET pourquoi, en une ligne claire, car l'historique s'adresse au futur (coéquipiers, soi-même plus tard) et sert de documentationquoi + pourquoi, pour le futur
  • Un message très long qui recopie tout le code modifiérecopier le code

Réponse : L'historique Git est une documentation gratuite du projet — à condition d'être lisible. « modif » ou « fix » ne disent rien : dans six mois, personne ne saura ce que ce commit a changé ni pourquoi. Un bon message est une ligne claire indiquant le QUOI et le POURQUOI (« Corrige le calcul de TVA sur les livres »). Inutile d'y recopier le code (Git le montre déjà via le diff) : le message explique l'intention, que le code ne dit pas — même esprit que le commentaire utile du chapitre 6.

Branches et fusion

Une branche est une ligne de développement parallèle. Plutôt que de travailler tous sur la même version — au risque de se casser mutuellement le code —, chacun crée une branche pour sa tâche : développer une fonctionnalité, corriger un bug, sans perturber le travail des autres ni la version stable.

Quand la tâche est finie et testée, on fusionne (merge) la branche dans la branche principale : Git combine les modifications. La plupart du temps, la fusion est automatique — Git sait réconcilier des changements qui portent sur des lignes ou des fichiers différents. C'est ce qui permet à trois personnes de travailler en parallèle et de réunir leur travail sans effort.

Ce modèle — une branche par tâche, fusion une fois testée — est la manière standard de travailler à plusieurs. Il isole le travail en cours (une fonctionnalité à moitié faite ne casse pas la branche principale) et rend chaque contribution relisable avant d'être intégrée (la revue de code du chapitre 6).

Le conflit, et comment le résoudre

Reste le cas que Git ne peut pas résoudre seul : deux personnes ont modifié la même ligne à partir de la même version. Git ne peut pas deviner laquelle garder — c'est un conflit.

Il faut d'emblée corriger un contresens : un conflit n'est pas une erreur, ni une faute. C'est une situation normale du travail à plusieurs. Git ne bloque que là où il serait dangereux de choisir à votre place ; pour tout le reste, il fusionne seul. Face à un conflit, il affiche les deux versions entre des marqueurs et attend :

<<<<<<< votre version  return montant * 1.20;=======  return montant * 0.90;>>>>>>> version du coéquipier

Résoudre, c'est décider — en humain — de la version finale, puis supprimer les marqueurs. Et décider exige de comprendre les deux intentions : ici, l'un a ajouté la TVA, l'autre une remise ; la bonne résolution n'est ni l'une ni l'autre mais les deux combinées. C'est pourquoi aucun outil ne peut résoudre à votre place : il faudrait comprendre le sens du code.

Deux pièges du débutant, à éviter : paniquer et « prendre le sien » en écrasant le travail de l'autre ; et oublier un marqueur, qui laisse du code qui ne compile pas. La bonne attitude est calme et méthodique : lire les deux versions, comprendre, combiner, nettoyer les marqueurs, tester. L'exercice vous fait vivre exactement cette séquence.

Provoquer un conflit pour l'apprivoiser

C'est le point que le cours insiste à faire vivre en TP. Rencontré pour la première fois en pleine échéance de projet, un conflit affole : on résout n'importe comment, on perd du travail, on accuse l'outil. Provoqué délibérément — deux étudiants modifient volontairement la même ligne, puis fusionnent —, il devient une manipulation banale, apprise à froid.

C'est le même principe que l'exercice de régression du chapitre 8 : la valeur d'une pratique ne se croit pas, elle s'éprouve. Faites-le une fois en TP, calmement, et le conflit cesse d'être un épouvantail. On réduit d'ailleurs leur fréquence par de bonnes habitudes — commits petits et fréquents, communication (« je touche à prix.js cet après-midi »), découpage du travail en zones distinctes — mais on ne les élimine jamais totalement à plusieurs. Savoir les résoudre est une compétence, pas un échec.

Quiz · 1 question

Deux coéquipiers ont modifié la même ligne ; Git signale un conflit. Quelle est la bonne façon de le résoudre ?

  • C'est une erreur grave : il faut annuler l'un des deux commits et recommencererreur à annuler
  • Comprendre les deux intentions, écrire la version finale qui les concilie (ici garder les deux changements), puis supprimer les marqueurs de conflit et testercomprendre et concilier
  • Toujours garder sa propre version, car c'est la plus récente qu'on connaîtgarder la sienne

Réponse : Un conflit n'est pas une erreur mais une situation normale : Git ne peut pas deviner l'intention quand la même ligne a changé des deux côtés. La bonne résolution demande de COMPRENDRE les deux modifications et d'écrire la version finale voulue — souvent en les combinant (garder la TVA ET la remise), pas en sacrifiant l'une. Il faut ensuite retirer les marqueurs (<<<<, ====, >>>>) et tester. « Toujours garder la sienne » écrase le travail du coéquipier ; annuler un commit détruit du travail valable.

Dépôt distant et collaboration

Jusqu'ici, le dépôt vit sur une machine. Le dépôt distant (sur GitHub, GitLab…) en est une copie partagée, hébergée, qui sert de point de rendez-vous de l'équipe. Chacun envoie (push) ses commits vers le distant et récupère (pull) ceux des autres. Le distant est aussi une sauvegarde : si une machine tombe, le projet survit.

Autour du dépôt, ces plateformes offrent des outils de collaboration essentiels au projet :

Pour votre projet, l'essentiel tient en une routine : committer souvent avec des messages clairs, pousser régulièrement vers le distant, récupérer avant de commencer à travailler. Cette discipline, prise dès la première semaine, évite l'immense majorité des drames de coordination.

À vous

L'exercice fait vivre le moment redouté, mais à froid : deux coéquipiers modifient la même ligne, Git lève un conflit, et vous le résolvez. Vous lisez les marqueurs, vous comprenez les deux intentions — une TVA, une remise —, vous écrivez la version qui les concilie, et vous nettoyez les marqueurs.

C'est exactement la manipulation qui, apprise ici calmement, vous évitera la panique le jour où elle surviendra en pleine échéance de projet. Un conflit résolu proprement est un non-événement.

Exercice de code

Deux coéquipiers modifient la même ligne : provoquez le conflit Git, lisez les marqueurs (<<<<, ====, >>>>), puis résolvez-le en combinant les deux intentions et en supprimant les marqueurs. Apprenez à le faire à froid, avant de le rencontrer en pleine échéance.

Point de départ

// Deux membres de l'équipe partent de la MÊME version (la « base ») et
// modifient CHACUN la même ligne, sur leur branche. À la fusion, Git ne peut
// pas deviner laquelle garder : c'est un CONFLIT.

const base = [
  "function prix(montant) {",
  "  return montant;",              // <- la ligne que les DEUX vont changer
  "}",
];

// Amina ajoute la TVA :
const amina = [
  "function prix(montant) {",
  "  return montant * 1.20;",       // sa version de la ligne 2
  "}",
];

// Bakary ajoute une remise :
const bakary = [
  "function prix(montant) {",
  "  return montant * 0.90;",       // sa version de la ligne 2
  "}",
];

// Ce que Git AFFICHE quand il ne peut pas trancher (marqueurs de conflit) :
function fusionner(base, a, b) {
  const res = [];
  for (let i = 0; i < base.length; i++) {
    if (a[i] === b[i]) { res.push(a[i]); }          // personne n'a changé, ou même changement
    else if (a[i] === base[i]) { res.push(b[i]); }  // seul b a changé -> on prend b
    else if (b[i] === base[i]) { res.push(a[i]); }  // seul a a changé -> on prend a
    else {                                          // les DEUX ont changé -> CONFLIT
      res.push("<<<<<<< amina", a[i], "=======", b[i], ">>>>>>> bakary");
    }
  }
  return res;
}

console.log("Ce que Git affiche à la fusion :");
console.log(fusionner(base, amina, bakary).join("\n"));

// ── À VOUS : résoudre le conflit ────────────────────────────────────────────
// Git ne choisit pas : c'est à un HUMAIN de décider, en COMPRENANT les deux
// intentions. Ici, il faut la TVA (Amina) ET la remise (Bakary) : les deux.
// Écrivez la version résolue, SANS marqueur de conflit.
const resolu = [
  "function prix(montant) {",
  // à compléter : la ligne qui combine les deux intentions
  "}",
];

console.log("\nVotre résolution :");
console.log(resolu.join("\n"));
console.log("\nContient encore des marqueurs de conflit ?",
  resolu.some((l) => /^(<<<<|====|>>>>)/.test(l)));

Solution

const resolu = [
  "function prix(montant) {",
  "  return montant * 1.20 * 0.90;",   // TVA (Amina) ET remise (Bakary)
  "}",
];
// Aucun marqueur ne subsiste : le conflit est résolu.

// ── Ce que l'exercice enseigne ──────────────────────────────────────────────
//
// 1. UN CONFLIT N'EST PAS UNE ERREUR, c'est une SITUATION NORMALE : deux
//    personnes ont modifié la même ligne à partir de la même base. Git sait
//    fusionner automatiquement les changements sur des lignes DIFFÉRENTES ;
//    il ne bloque QUE lorsqu'il ne peut pas deviner l'intention — sur la MÊME
//    ligne.
//
// 2. GIT NE CHOISIT PAS À VOTRE PLACE. Il affiche les deux versions entre des
//    marqueurs (<<<<<<< / ======= / >>>>>>>) et attend qu'un HUMAIN décide,
//    parce que résoudre exige de COMPRENDRE les deux intentions — ce qu'aucun
//    outil ne peut faire. Ici : garder la TVA ET la remise, pas l'une OU
//    l'autre.
//
// 3. RÉSOUDRE = éditer le fichier pour obtenir la version voulue, PUIS
//    SUPPRIMER les trois marqueurs. Un marqueur oublié, c'est du code qui ne
//    compile pas — l'erreur classique du débutant paniqué.
//
// 4. Se former À FROID change tout. Rencontré pour la première fois en pleine
//    échéance de projet, un conflit affole et on résout n'importe comment (on
//    « prend le sien », on écrase le travail de l'autre). Provoqué
//    délibérément en TP, il devient une manipulation banale.
//
// 5. On RÉDUIT la fréquence des conflits par de bonnes pratiques : commits
//    petits et fréquents, communication (« je touche à prix.js »), et
//    découpage du travail en fichiers/zones distincts. Mais on ne les
//    supprime jamais totalement à plusieurs : savoir les résoudre calmement
//    est une compétence, pas un échec.

Ce que la suite en fait

Vous disposez maintenant de tout l'outillage : spécifier, concevoir, écrire proprement, tester, versionner. Le dernier bloc assemble le tout — car un projet, ce n'est pas la somme de ces techniques, c'est leur conduite dans le temps, à plusieurs.

Le chapitre 10 traite la conduite de projet : constituer l'équipe, découper en tâches, suivre l'avancement, documenter, et présenter le résultat en soutenance. C'est le bloc qui donne son sens à tous les autres — et qui décrit, en réalité, ce que votre projet de semestre a fait vivre depuis la première semaine.

À retenir

Flashcards · 4 cartes

Qu'est-ce qu'un dépôt, un commit et un historique Git, et à quoi servent-ils ?
Le DÉPÔT est un projet dont Git suit toute l'histoire. Un COMMIT est un instantané daté de l'état du projet, avec un message décrivant le changement. L'HISTORIQUE est la suite des commits : il permet de revenir en arrière, de comprendre pourquoi une ligne existe, et de retrouver n'importe quel état passé. Un projet versionné ne perd jamais de travail. Un bon message de commit dit le QUOI et le POURQUOI, pas « modif ».
Qu'est-ce qu'une branche et une fusion, et pourquoi ce modèle facilite le travail à plusieurs ?
Une BRANCHE est une ligne de développement parallèle : chacun crée la sienne pour sa tâche, sans perturber les autres ni la version stable. Une fois la tâche finie et testée, on FUSIONNE (merge) dans la branche principale. La plupart des fusions sont automatiques (changements sur des lignes/fichiers différents). Ce modèle isole le travail en cours et rend chaque contribution relisable avant intégration.
Qu'est-ce qu'un conflit Git, et comment le résout-on correctement ?
Un conflit survient quand deux personnes modifient la MÊME ligne depuis la même base : Git ne peut pas deviner laquelle garder. Ce n'est PAS une erreur, mais une situation normale. Il affiche les deux versions entre marqueurs (<<<<, ====, >>>>). Résoudre : comprendre les deux intentions, écrire la version finale qui les concilie (souvent les deux combinées), supprimer les marqueurs, tester. Ne jamais « prendre la sienne » en écrasant l'autre.
À quoi sert un dépôt distant, et quelle routine adopter en projet d'équipe ?
Le dépôt DISTANT (GitHub, GitLab) est la copie partagée qui sert de point de rendez-vous et de sauvegarde : chacun pousse (push) ses commits et récupère (pull) ceux des autres. Il offre le suivi des tâches/bugs (issues = le backlog), les demandes de fusion avec revue, et l'historique partagé. Routine : committer souvent avec des messages clairs, pousser régulièrement, récupérer avant de travailler — dès la première semaine.