C1 — Culture et fondationsDans le dialogue d’impression, choisissez « Enregistrer au format PDF » comme destination.
Retour

Licence 3 · DevOps

Cours 1Culture et fondations

Comprendre quel problème d'organisation le DevOps résout, savoir le mesurer, et remettre à niveau les outils que tout le reste suppose.

2 chapitres · 8 h de travail estimé

  1. 1. Pourquoi le DevOps4 h
  2. 2. Rappels indispensables4 h

Chapitre 1 · 4 h

Pourquoi le DevOps

Le mur entre développement et exploitation, les blocages du cycle de livraison traditionnel, les trois voies, les indicateurs DORA, et le post-mortem sans blâme.

Une équipe de développement livre une version. L'équipe d'exploitation la refuse : elle n'a pas été prévenue, la configuration diffère, et la mise en production tombe un jeudi soir. Les développeurs répondent que « ça marche sur nos machines ». L'exploitation répond que sa mission est la stabilité, et que chaque livraison est un risque.

Les deux ont raison, et c'est le problème. On les a payés pour des objectifs contradictoires : livrer vite d'un côté, ne rien casser de l'autre. Le résultat est prévisible — des livraisons rares, grosses, redoutées, et d'autant plus risquées qu'elles sont rares.

Le DevOps n'est pas un outil, ni un métier, ni un logiciel qu'on installe. C'est une réponse à cette contradiction d'organisation, et tout le reste du semestre en découle.

Le mur, et ce qu'il produit

Le cycle traditionnel enchaîne des phases séparées par des remises de travail.

développement ──► recette ──► exploitation ──► production     3 mois        3 semaines     1 semaine        ?

Quatre conséquences, et elles s'aggravent mutuellement.

Les lots grossissent. Puisque livrer coûte cher, on livre rarement, donc chaque livraison contient trois mois de modifications. Une version qui change deux cents fichiers est impossible à relire, impossible à tester exhaustivement, et impossible à diagnostiquer quand elle échoue.

Le risque augmente avec la taille du lot. C'est le point contre-intuitif du chapitre : on livre rarement pour réduire le risque, et c'est précisément ce qui l'augmente. Quand quelque chose casse dans un lot de deux cents modifications, on ignore laquelle est en cause.

Le retour arrière devient impossible. Revenir à la version précédente, c'est annuler trois mois de travail — donc on ne le fait pas, et l'on répare en urgence en production.

L'apprentissage s'arrête. Une équipe qui livre quatre fois par an n'a que quatre occasions annuelles d'apprendre de ses erreurs. Une qui livre tous les jours en a deux cent cinquante.

Les trois voies

Le mouvement s'énonce classiquement en trois principes, et ils forment le plan du semestre.

Le flux. Optimiser le trajet complet, du commit à la production, et non chaque étape isolément. Une équipe de développement deux fois plus rapide ne sert à rien si la mise en production prend trois semaines : le goulot d'étranglement décide du tout — c'est la loi d'Amdahl du chapitre 8 d'architecture, appliquée à une organisation. Rendre le flux visible, réduire la taille des lots, automatiser ce qui est répété : c'est l'objet des blocs II à V.

La rétroaction. Raccourcir la boucle entre une erreur et sa détection. Un bogue trouvé à l'écriture coûte une minute ; trouvé en recette, une heure ; trouvé en production, une journée et un incident. Tests automatisés, pipeline, supervision : tout le cours consiste à déplacer la détection vers la gauche.

L'apprentissage continu. Faire de chaque incident une source d'amélioration plutôt que de sanction. C'est la partie culturelle, et c'est la plus difficile à installer — voir la dernière section.

Mesurer : les quatre indicateurs DORA

Un programme d'amélioration qui ne se mesure pas est une opinion. Le programme de recherche DevOps Research and Assessment a dégagé quatre indicateurs qui, ensemble, prédisent la performance d'une équipe — et ils ont l'avantage d'être difficiles à truquer.

IndicateurQuestionÉliteFaible
Fréquence de déploiementà quelle cadence livre-t-on ?à la demande, plusieurs fois par jourmoins d'une fois par mois
Délai de livraisondu commit à la production ?moins d'une heureplus d'un mois
Taux d'échec des changementsquelle part des livraisons cause un incident ?0 à 15 %40 à 60 %
Temps de rétablissementcombien de temps pour réparer ?moins d'une heureplus d'une semaine

Graphique

Délai entre le commit et la production, en heures

  • Élite : 1 h1
  • Haute : 24 h24
  • Moyenne : 168 h (une semaine)168
  • Faible : 720 h (un mois)720
Les trois premières barres sont écrasées par la dernière, et c'est le propos : entre une équipe élite et une équipe faible, l'écart n'est pas de 20 % mais d'un facteur sept cents. Ce n'est pas une différence de talent ni de rapidité de frappe — c'est une différence de FLUX, et tout le reste du semestre consiste à en supprimer les obstacles.

Les deux premiers indicateurs mesurent la vitesse, les deux derniers la stabilité. Le résultat central de ces travaux est contre-intuitif et vaut d'être retenu : les deux vont ensemble. Les équipes qui livrent le plus souvent sont aussi celles qui cassent le moins et réparent le plus vite. Le compromis supposé entre vitesse et stabilité n'existe pas — c'est l'accumulation de gros lots rares qui produit à la fois la lenteur et l'instabilité.

Deux mises en garde d'usage. Ces indicateurs mesurent une équipe et un système, jamais une personne — les employer pour évaluer quelqu'un les rend immédiatement inutiles. Et ils se prennent ensemble : améliorer la fréquence de déploiement en négligeant le taux d'échec ne fait que déplacer le problème.

Le post-mortem sans blâme

Un incident survient. Deux réactions possibles, et elles produisent des organisations opposées.

Chercher le responsable. Quelqu'un a fait une manipulation malheureuse, on le sait, on le dit. Le résultat est mécanique : la prochaine fois, personne ne signalera l'erreur, chacun retardera les livraisons risquées, et l'information cessera de circuler. L'organisation devient plus lente et moins sûre.

Chercher ce qui a rendu l'erreur possible. Pourquoi une commande manuelle pouvait-elle détruire la base ? Pourquoi n'y avait-il pas de confirmation, de sauvegarde testée, de séparation entre les environnements ? Ce sont des questions sur le système, et elles ont des réponses actionnables.

Le principe s'énonce ainsi : on suppose que chacun a agi au mieux compte tenu de ce qu'il savait à ce moment-là. L'erreur humaine n'est pas une explication, c'est un point de départ — elle demande pourquoi le système a permis, voire favorisé, cette erreur.

Un post-mortem tient en cinq parties : ce qui s'est passé, quand, quel a été l'impact mesuré, pourquoi cela a été possible, et quelles actions concrètes sont décidées avec un responsable et une échéance. Sans la dernière partie, c'est un rapport ; avec elle, c'est un apprentissage.

Quiz · 1 question

Une équipe livre une fois par trimestre pour « limiter les risques ». Que dit le résultat des travaux DORA ?

  • C'est cohérent : moins de livraisons signifie mécaniquement moins d'occasions de casser la productioncohérent
  • C'est l'inverse : livrer rarement produit de gros lots, où l'on ne sait plus quelle modification a cassé quoi, où le retour arrière est impraticable et où l'apprentissage est rare — vitesse et stabilité vont ensemblel'inverse
  • Cela dépend uniquement de la qualité des tests : la fréquence de livraison n'a pas d'effet propresans effet

Réponse : C'est le résultat central de ces travaux, et il est contre-intuitif : les équipes qui déploient le plus souvent ont AUSSI le plus faible taux d'échec et le plus court temps de rétablissement. Le compromis supposé entre vitesse et stabilité n'existe pas. Le mécanisme est la TAILLE DU LOT : livrer rarement ne réduit pas le nombre de modifications, cela les accumule. Un lot de trois mois change deux cents fichiers — impossible à relire, à tester exhaustivement, à diagnostiquer quand il échoue, et impossible à annuler puisque revenir en arrière signifierait perdre trois mois de travail. À l'inverse, une livraison quotidienne contient peu de changements : la cause d'un incident est presque évidente, et le retour arrière est indolore. Et l'équipe qui livre 250 fois par an a 250 occasions d'apprendre, contre quatre.

Quiz · 1 question

Après un incident, un responsable demande « qui a lancé cette commande ? ». Pourquoi est-ce contre-productif ?

  • Parce que l'information est difficile à retrouver dans les journauxdifficulté technique
  • Parce que la question porte sur la PERSONNE et non sur le SYSTÈME : elle pousse chacun à taire ses erreurs et à éviter les opérations risquées, ce qui rend l'organisation à la fois plus lente et moins sûreeffet sur le système
  • Parce que le responsable de l'incident est presque toujours le dernier à avoir déployé, donc la réponse est connue d'avanceréponse évidente

Réponse : La question est mécaniquement contre-productive, quelle que soit l'intention. Si signaler une erreur expose à une sanction, personne ne la signale : les incidents sont découverts plus tard et par d'autres, l'information cesse de circuler, et chacun retarde les opérations risquées — donc les lots grossissent, ce qui ramène au premier quiz. Le principe du post-mortem sans blâme est de SUPPOSER que chacun a agi au mieux compte tenu de ce qu'il savait, et de traiter l'erreur humaine non comme une explication mais comme un point de départ : pourquoi le système a-t-il permis, voire favorisé, cette erreur ? Pourquoi une commande manuelle pouvait-elle détruire la base sans confirmation, sans sauvegarde testée, sans séparation des environnements ? Ces questions-là ont des réponses actionnables — et c'est la cinquième partie du compte rendu, celle des actions avec responsable et échéance, qui distingue un apprentissage d'un rapport.

À vous

L'exercice calcule les quatre indicateurs à partir d'un journal de déploiements — dates, succès ou échec, heure de commit, heure de rétablissement — pour deux équipes fictives.

Vous verrez d'abord ce que chaque indicateur mesure réellement, puis vous éprouverez le résultat central : en faisant varier la taille des lots dans le simulateur fourni, vous obtiendrez mécaniquement l'un ou l'autre profil. Une même équipe, un même rythme de travail, et deux positions opposées dans le classement — parce que la seule chose qu'on a changée est la fréquence de livraison.

La dernière partie est un piège de mesure : une équipe qui améliore sa fréquence de déploiement en dégradant son taux d'échec n'a pas progressé, et l'exercice le rend visible.

Exercice de code

Calculez les quatre indicateurs DORA, puis montrez par simulation que vitesse et stabilité vont ensemble.

Point de départ

// ── Un journal de déploiements ────────────────────────────────────────────
// heure en heures depuis le début de l'observation (720 h = un mois).
const JOURNAL_A = [
  { t: 2,   commit: 1,   ok: true },
  { t: 6,   commit: 5,   ok: true },
  { t: 9,   commit: 8.5, ok: false, retabli: 9.7 },
  { t: 14,  commit: 13,  ok: true },
  { t: 20,  commit: 19,  ok: true },
  { t: 26,  commit: 25,  ok: true },
  { t: 31,  commit: 30,  ok: true },
  { t: 38,  commit: 37,  ok: true },
];
const JOURNAL_B = [
  { t: 200, commit: 20,  ok: false, retabli: 380 },
  { t: 500, commit: 260, ok: true },
  { t: 700, commit: 520, ok: false, retabli: 900 },
];

function indicateurs(journal, dureeObservation) {
  const n = journal.length;
  const echecs = journal.filter((d) => !d.ok);
  return {
    frequence: 0,        // ← à écrire : déploiements par semaine
    delai: 0,            // ← à écrire : moyenne de (t − commit), en heures
    tauxEchec: 0,        // ← à écrire : part des déploiements ayant échoué
    retablissement: 0,   // ← à écrire : moyenne de (retabli − t) sur les échecs
  };
}

function classer(i) {
  const note = (v, seuils) => seuils.findIndex((s) => v <= s);
  return "à écrire";     // ← élite / haute / moyenne / faible
}

// ── Simuler l'effet de la TAILLE DES LOTS ─────────────────────────────────
// Une même équipe, un même rythme de travail : 240 modifications par mois.
// Seule varie la fréquence de livraison.
function simuler(modificationsParMois, deploiementsParMois) {
  const parLot = modificationsParMois / deploiementsParMois;
  // Hypothèse empirique : la probabilité qu'un lot casse croît avec sa
  // taille, et le temps de diagnostic aussi — on ne sait pas quelle
  // modification est en cause parmi celles du lot.
  const probaEchec = Math.min(0.9, 1 - Math.pow(0.995, parLot));
  const diagnostic = 0.5 + parLot * 0.15;   // heures
  return { parLot, probaEchec, diagnostic };
}

// ── À VOUS ────────────────────────────────────────────────────────────────
// 1. Écrivez indicateurs() et classer(), puis comparez les deux équipes.
// 2. Faites varier deploiementsParMois de 1 à 240 : que deviennent le taux
//    d'échec et le temps de rétablissement ?
// 3. Une équipe passe de 4 à 30 déploiements par mois mais son taux d'échec
//    monte de 10 % à 45 %. A-t-elle progressé ?

console.log(JSON.stringify(indicateurs(JOURNAL_A, 720)));

Solution

const JOURNAL_A = [
  { t: 2, commit: 1, ok: true }, { t: 6, commit: 5, ok: true },
  { t: 9, commit: 8.5, ok: false, retabli: 9.7 }, { t: 14, commit: 13, ok: true },
  { t: 20, commit: 19, ok: true }, { t: 26, commit: 25, ok: true },
  { t: 31, commit: 30, ok: true }, { t: 38, commit: 37, ok: true },
];
const JOURNAL_B = [
  { t: 200, commit: 20, ok: false, retabli: 380 },
  { t: 500, commit: 260, ok: true },
  { t: 700, commit: 520, ok: false, retabli: 900 },
];

const moyenne = (t) => t.reduce((s, x) => s + x, 0) / (t.length || 1);

function indicateurs(journal, dureeObservation) {
  const echecs = journal.filter((d) => !d.ok);
  return {
    frequence: (journal.length / dureeObservation) * 168,          // par semaine
    delai: moyenne(journal.map((d) => d.t - d.commit)),            // heures
    tauxEchec: echecs.length / journal.length,
    retablissement: moyenne(echecs.map((d) => d.retabli - d.t)),   // heures
  };
}

function classer(i) {
  // Seuils simplifiés d'après les paliers DORA.
  const niveau = (v, s) => (v <= s[0] ? "élite" : v <= s[1] ? "haute" : v <= s[2] ? "moyenne" : "faible");
  const inverse = (v, s) => (v >= s[0] ? "élite" : v >= s[1] ? "haute" : v >= s[2] ? "moyenne" : "faible");
  return {
    frequence: inverse(i.frequence, [7, 1, 0.25]),
    delai: niveau(i.delai, [1, 24, 168]),
    tauxEchec: niveau(i.tauxEchec, [0.15, 0.3, 0.45]),
    retablissement: niveau(i.retablissement, [1, 24, 168]),
  };
}

console.log("— 1. deux équipes, un mois d'observation —");
for (const [nom, j] of [["équipe A", JOURNAL_A], ["équipe B", JOURNAL_B]]) {
  const i = indicateurs(j, 720), c = classer(i);
  console.log("   " + nom);
  console.log("      fréquence      " + i.frequence.toFixed(1).padStart(6) + " /semaine   " + c.frequence);
  console.log("      délai          " + i.delai.toFixed(1).padStart(6) + " h          " + c.delai);
  console.log("      taux d'échec   " + (i.tauxEchec * 100).toFixed(0).padStart(6) + " %          " + c.tauxEchec);
  console.log("      rétablissement " + i.retablissement.toFixed(1).padStart(6) + " h          " + c.retablissement);
}
console.log("   L'équipe A n'est pas « meilleure » : elle a un FLUX différent, et");
console.log("   les quatre indicateurs basculent ENSEMBLE. C'est le point à vérifier.");

console.log("");
console.log("— 2. la taille des lots explique tout —");
function simuler(modificationsParMois, deploiementsParMois) {
  const parLot = modificationsParMois / deploiementsParMois;
  const probaEchec = Math.min(0.9, 1 - Math.pow(0.995, parLot));
  const diagnostic = 0.5 + parLot * 0.15;
  return { parLot, probaEchec, diagnostic };
}
console.log("   déploiements/mois | modifs/lot | taux d'échec | rétablissement");
for (const d of [1, 2, 4, 12, 30, 120, 240]) {
  const s = simuler(240, d);
  console.log("   " + String(d).padStart(17) + " | " + String(s.parLot).padStart(10) +
    " | " + (s.probaEchec * 100).toFixed(0).padStart(11) + " %" +
    " | " + s.diagnostic.toFixed(1).padStart(11) + " h");
}
console.log("   Même équipe, même volume de travail, même rythme de frappe : on n'a");
console.log("   changé QUE la fréquence de livraison, et les deux indicateurs de");
console.log("   STABILITÉ suivent la vitesse. Le compromis supposé entre les deux");
console.log("   n'existe pas — c'est l'accumulation en gros lots qui produit à la");
console.log("   fois la lenteur et l'instabilité.");

console.log("");
console.log("— 3. le piège de mesure —");
const avant = { frequence: 4 / 4.3, delai: 300, tauxEchec: 0.10, retablissement: 40 };
const apres = { frequence: 30 / 4.3, delai: 40, tauxEchec: 0.45, retablissement: 40 };
for (const [nom, i] of [["avant", avant], ["après", apres]]) {
  const c = classer(i);
  console.log("   " + nom + " : fréquence " + c.frequence.padEnd(8) +
    " | délai " + c.delai.padEnd(8) + " | échec " + c.tauxEchec);
}
console.log("   La vitesse a bondi, la stabilité s'est effondrée : l'équipe a");
console.log("   déplacé le problème, pas amélioré son flux. Les quatre indicateurs");
console.log("   se lisent ENSEMBLE, jamais un seul — et jamais pour évaluer");
console.log("   quelqu'un, sous peine de les rendre immédiatement inutiles.");

En travaux pratiques

Le fil rouge du semestre est une petite application web de suivi de tickets — tickets — qu'on empaquettera, testera, déploiera, orchestrera et supervisera. Cette première séance ne touche pas encore au code : elle installe le vocabulaire de mesure sur lequel tout le reste s'appuiera.

Travaux pratiques 1 · 1 h

Mesurer avant de changer quoi que ce soit

Calculer les quatre indicateurs DORA sur un dépôt réel, puis rédiger un post-mortem sans blâme à partir d'un incident fourni.

Avant de commencer

  • Git installé, et un dépôt public actif de votre choix cloné en local
  • Un tableur ou un langage de script pour les calculs

Énoncé

  1. Extraire l'historique des livraisonsClonez un dépôt public qui publie des versions étiquetées, et sortez la liste de ses étiquettes avec leur date. Vous voulez une ligne par livraison. Indice : git tag --sort=creatordate --format='%(creatordate:short) %(refname:short)' donne exactement cela.
  2. Calculer la fréquence de déploiementSur les six derniers mois, combien de livraisons par semaine ? Situez le résultat dans les paliers du cours : élite, haute, moyenne, faible.
  3. Calculer le délai de livraisonPour cinq étiquettes prises au hasard, mesurez l'écart entre la date du commit le plus ancien qu'elles contiennent et la date de l'étiquette. C'est une approximation du délai entre l'écriture et la mise à disposition. Indice : git log --format=%ci v1.2.0..v1.3.0 | tail -1 donne la date du premier commit de l'intervalle.
  4. Estimer les deux indicateurs de stabilitéCherchez les versions correctives publiées moins de 48 h après une version : ce sont vos candidats « échec de changement ». Le délai entre les deux approxime le temps de rétablissement.
  5. Rédiger un post-mortemÀ partir de l'incident fourni ci-dessous, écrivez un compte rendu en cinq parties. INCIDENT : le 14 mars à 10 h 04, un déploiement fait passer le taux d'erreur de 0,1 % à 4 %. L'alerte part à 10 h 31. La cause est comprise à 10 h 44 : une migration a renommé une colonne, et l'ancienne version des travailleurs de fond, non redéployée, échouait. Retour arrière à 10 h 46 — sans effet, la colonne étant déjà renommée. Correctif appliqué à 11 h 20. Indice : Les cinq parties : ce qui s'est passé, la chronologie, l'impact MESURÉ, pourquoi c'était possible, et les actions avec responsable et échéance.

C'est réussi quand

  • Vos quatre indicateurs sont chiffrés, et vous savez dire dans quel palier se situe le dépôt
  • Votre post-mortem ne nomme personne
  • Chacune de vos actions correctives est vérifiable et porte une échéance

Correction

Extraction des livraisonsterminal
git tag --sort=creatordate \
--format='%(creatordate:short) %(refname:short)' | tail -40

# Délai de livraison pour une étiquette donnée
git log --format=%ci v1.2.0..v1.3.0 | tail -1   # premier commit
git log -1 --format=%ci v1.3.0                   # publication

Le calcul est approximatif, et c'est acceptable : ces indicateurs servent à situer une tendance, pas à produire un chiffre à la décimale. Ce qui compte est de les recalculer de la même façon chaque mois.

Ce que révèle presque toujours le calcul

Les quatre indicateurs vont dans le même sens. Un dépôt qui publie une fois par trimestre affiche aussi un délai de plusieurs semaines et des correctifs d'urgence fréquents — c'est le résultat central du chapitre, et le voir sur un vrai dépôt vaut mieux que de le lire.

Post-mortem — les quatre premières parties

CE QUI S'EST PASSÉ : une migration renommant une colonne a été déployée avec l'application web, mais les travailleurs de fond sont restés sur la version précédente et ont échoué sur chaque tâche. CHRONOLOGIE : panne 10 h 04, alerte 10 h 31 (27 min de détection), diagnostic 10 h 44, retour arrière inefficace 10 h 46, rétablissement 11 h 20. IMPACT : 4 % des requêtes en erreur pendant 76 minutes, environ 3 000 tâches de fond perdues. POURQUOI C'ÉTAIT POSSIBLE : la migration était destructive et déployée en une seule étape ; les deux composants ne sont pas déployés ensemble ; le retour arrière n'avait jamais été testé avec une migration.

Post-mortem — les actions, et ce qui les distingue d'un vœu

Chaque action nomme un responsable, une échéance et un critère de vérification. Par exemple : « les migrations destructives passent en trois étapes, règle vérifiée automatiquement dans le pipeline — équipe plateforme, 30 avril, critère : une migration DROP COLUMN fait échouer la vérification ». Comparez avec « être plus vigilant sur les migrations », qui n'engage rien et ne se vérifie pas.

La faute à ne pas commettre

Aucune phrase du compte rendu ne doit désigner une personne, même implicitement — « le développeur qui a écrit la migration » en désigne une. La question n'est pas qui a fait la migration mais pourquoi le système a permis qu'une migration destructive parte en une seule étape, sans que rien ne l'en empêche.

Ce que la suite en fait

Le chapitre 2 remet à niveau les outils que tout le reste suppose — la ligne de commande, le réseau, et surtout Git, dont la stratégie de branchement décide directement de la taille des lots dont ce chapitre vient de parler.

Les blocs II à V construisent ensuite le flux, dans l'ordre où une modification le parcourt : empaquetée, vérifiée, livrée, déployée sur une infrastructure décrite, orchestrée. Et le bloc VI y ajoute ce sans quoi rien n'est mesurable — c'est là que les indicateurs de ce chapitre cessent d'être un tableau pour devenir un graphique qu'on regarde.

À retenir

Flashcards · 5 cartes

Quel problème le DevOps résout-il, et pourquoi les deux camps ont-ils raison ?
Une contradiction d'ORGANISATION : le développement est payé pour livrer vite, l'exploitation pour ne rien casser. Les deux objectifs sont légitimes et opposés, d'où des livraisons rares, grosses et redoutées. Le DevOps n'est ni un outil ni un métier : c'est la réponse à cette contradiction, et l'outillage n'en est que la conséquence.
Pourquoi livrer rarement augmente-t-il le risque au lieu de le réduire ?
Parce que la TAILLE DU LOT augmente. Un lot de trois mois change deux cents fichiers : impossible à relire, à tester exhaustivement, à diagnostiquer quand il échoue, et impossible à annuler puisque revenir en arrière signifierait perdre trois mois. En prime, une équipe qui livre quatre fois par an n'a que quatre occasions annuelles d'apprendre, contre deux cent cinquante pour une livraison quotidienne.
Énoncez les trois voies du DevOps.
LE FLUX : optimiser le trajet complet du commit à la production, pas chaque étape isolément — le goulot d'étranglement décide du tout, comme dans la loi d'Amdahl. LA RÉTROACTION : raccourcir la boucle entre une erreur et sa détection, un bogue coûtant une minute à l'écriture, une heure en recette, une journée en production. L'APPRENTISSAGE CONTINU : faire de chaque incident une amélioration plutôt qu'une sanction.
Quels sont les quatre indicateurs DORA, et que faut-il en savoir ?
VITESSE : fréquence de déploiement, et délai entre le commit et la production. STABILITÉ : taux d'échec des changements, et temps de rétablissement. Résultat central : les deux vont ENSEMBLE — les équipes qui livrent le plus souvent cassent le moins et réparent le plus vite. Deux mises en garde : ils mesurent une ÉQUIPE et un système, jamais une personne, et ils se prennent ENSEMBLE — améliorer la fréquence en dégradant le taux d'échec n'est pas un progrès.
Qu'est-ce qu'un post-mortem sans blâme, et que contient-il ?
Le principe : SUPPOSER que chacun a agi au mieux compte tenu de ce qu'il savait. L'erreur humaine n'est pas une explication mais un point de départ — pourquoi le système a-t-il permis, voire favorisé, cette erreur ? Chercher le responsable a un effet mécanique : plus personne ne signale ses erreurs, chacun évite les opérations risquées, les lots grossissent. Cinq parties : ce qui s'est passé, quand, l'impact MESURÉ, pourquoi c'était possible, et les ACTIONS avec responsable et échéance — sans la dernière, c'est un rapport, pas un apprentissage.

Chapitre 2 · 4 h

Rappels indispensables

Linux en ligne de commande, processus et permissions ; ports, DNS et HTTP ; Git avancé — branches, fusion, rebase, GitFlow contre trunk-based — et revue de code.

Trois choses bloquent un TP de DevOps dès la première séance, et aucune n'est du DevOps.

Le serveur n'a pas d'interface graphique : tout se fait en ligne de commande, et un étudiant qui hésite sur chmod ou sur un pipe perd son temps sur autre chose que le sujet. L'application ne répond pas, et il faut savoir où regarder : le processus écoute-t-il ? le port est-il ouvert ? le nom se résout-il ? Et le dépôt Git compte huit branches divergentes, parce que personne n'a décidé d'une stratégie.

Ce chapitre remet ces trois outils à niveau. Il ne remplace pas les cours de systèmes et de réseaux — il en extrait ce dont on se sert tous les jours, et il ajoute la partie de Git que l'usage individuel ne demande jamais.

Linux, ce qui sert vraiment

Le cours de systèmes a tout posé ; voici ce qu'on emploie sans y penser.

CommandeUsage quotidien en exploitation
ps aux, top, htopqu'est-ce qui tourne, et qui consomme
kill -TERM, kill -9arrêter proprement, puis brutalement
df -h, du -sh *le disque est plein — où ?
tail -f fichier.logsuivre un journal en direct
grep, awk, sort | uniq -cfouiller ces journaux
chmod, chowndroits et propriétaire
systemctl status, journalctl -ul'état d'un service et ses journaux
ssh, scpatteindre la machine, y déposer un fichier

Deux rappels du cours de systèmes qui reviendront constamment.

Les droits. rwx pour le propriétaire, le groupe et les autres, notés en octal — 755, 644. Un conteneur qui refuse de démarrer parce qu'un script n'est pas exécutable est le grand classique du chapitre 3.

Les processus et les signaux. SIGTERM demande de s'arrêter proprement, SIGKILL tue sans préavis. Cette distinction n'est pas théorique : Docker et Kubernetes envoient un SIGTERM, attendent quelques secondes, puis un SIGKILL. Une application qui n'écoute pas SIGTERM perd ses requêtes en cours à chaque déploiement — et personne ne comprend pourquoi.

Réseau, le minimum pour diagnostiquer

Quand « ça ne répond pas », la question se décompose en quatre, et il faut les poser dans cet ordre.

Le nom se résout-il ? dig monsite.fr ou nslookup. Un DNS mal propagé se manifeste comme une panne d'application.

Le port est-il ouvert et écouté ? ss -tlnp liste ce qui écoute localement ; curl -v ou nc -zv hôte port teste depuis l'extérieur. La distinction compte : un service qui écoute sur 127.0.0.1 fonctionne en local et est injoignable de partout ailleurs — c'est l'erreur la plus fréquente du chapitre 3, où un conteneur doit écouter sur 0.0.0.0 pour être atteignable.

La requête arrive-t-elle ? Les journaux du serveur le disent. Si rien n'apparaît, le problème est en amont : pare-feu, routage, groupe de sécurité.

Que répond-elle ? Les codes HTTP suffisent à orienter : 2xx succès, 3xx redirection, 4xx la faute vient du client — 404 introuvable, 401 non authentifié, 403 interdit — et 5xx la faute vient du serveur, 500 erreur interne, 502 la passerelle n'a pas obtenu de réponse, 503 service indisponible.

Cette dernière ligne est celle qu'on emploie le plus : un 502 accuse le service en amont, un 500 accuse l'application. Savoir lequel des deux on regarde fait gagner une heure.

Git au-delà de l'usage individuel

Un étudiant arrive avec commit, push, pull. Le travail en équipe demande trois choses de plus.

Les branches. Une branche est un simple pointeur mobile sur un commit. La créer ne copie rien — c'est ce qui rend l'opération instantanée, et ce qui explique qu'on en crée sans compter.

La fusion contre le rebasage. Les deux intègrent le travail d'une branche dans une autre, et produisent des historiques de formes différentes.

merge                              rebase                                   A───B───C───────M                  A───B───C───D'──E'     \         /                         D───────E                    les commits sont REJOUÉS                                   au-dessus de C

merge préserve l'histoire telle qu'elle s'est produite, au prix d'un graphe qui se ramifie. rebase réécrit les commits pour donner une ligne droite, plus lisible — mais il crée de nouveaux commits, ce qui donne la seule règle absolue du chapitre : on ne rebase jamais une branche déjà partagée avec d'autres. Les commits d'origine disparaissent, et les collègues qui les avaient récupérés se retrouvent avec un historique incompatible.

L'usage courant : rebaser sa branche locale sur la principale avant de proposer sa contribution, puis fusionner. On obtient un historique lisible sans réécrire ce que d'autres ont déjà.

Les conflits. Ils surviennent quand deux branches modifient les mêmes lignes. Git ne peut pas trancher et vous laisse le fichier avec les deux versions marquées. Le point important est statistique : la probabilité de conflit croît avec la durée de vie de la branche. Une branche fusionnée le jour même entre rarement en conflit ; une branche de trois semaines touche des fichiers qui ont bougé entre-temps.

Deux stratégies de branchement

C'est le lien direct avec le chapitre 1, et le choix a des conséquences mesurables.

GitFlow organise le travail autour de branches durables : main, develop, une branche par fonctionnalité, des branches de version et de correctif. C'est structuré, adapté à des versions livrées — un logiciel installé chez des clients, avec plusieurs versions maintenues en parallèle.

Trunk-based ne garde qu'une branche principale, dans laquelle chacun intègre au moins une fois par jour, à l'aide de branches de très courte durée. Les fonctionnalités inachevées sont masquées par des drapeaux de fonctionnalité plutôt que par des branches.

GitFlowTrunk-based
Durée de vie d'une branchesemainesheures à un jour
Taille des lotsgrossepetite
Conflitsfréquents et largesrares et étroits
Compatible livraison continuedifficilementoui
Adapté àversions installées chez des clientsservice en ligne

Le rapprochement avec le chapitre 1 est immédiat : une branche de trois semaines est un lot de trois semaines. Toute la logique DORA — petits lots, rétroaction courte, retour arrière facile — pousse vers le trunk-based dès qu'on livre en continu. Ce n'est pas une question de mode mais de cohérence : un pipeline qui déploie plusieurs fois par jour ne peut pas cohabiter avec des branches qui vivent un mois.

La revue de code

Une demande de fusion (pull request) n'est pas une formalité administrative : c'est le point où trois choses se produisent — un second regard sur la correction, une diffusion de la connaissance dans l'équipe, et le déclenchement automatique du pipeline du chapitre 5.

Trois règles d'usage, et la première explique les deux autres.

Petit. Une demande de deux cents lignes est relue sérieusement ; une de deux mille est approuvée sans être lue. Le taux de détection s'effondre au-delà de quelques centaines de lignes, et c'est encore un argument pour les petits lots.

Rapide. Une demande qui attend deux jours bloque son auteur et se désynchronise de la branche principale — donc conflits.

Sur le code, pas sur la personne. « Cette boucle relit la base à chaque tour » plutôt que « tu n'as pas réfléchi ». C'est le post-mortem sans blâme du chapitre 1, appliqué à la relecture.

Quiz · 1 question

Pourquoi ne rebase-t-on jamais une branche déjà poussée et partagée ?

  • Parce que le rebasage est plus lent que la fusion sur un dépôt distantlenteur
  • Parce que rebase RÉÉCRIT les commits : les originaux disparaissent, et les collègues qui les avaient récupérés se retrouvent avec un historique incompatibleréécriture de l'historique
  • Parce que Git refuse techniquement de rebaser une branche distanterefus technique

Réponse : Rebase ne déplace pas les commits : il les REJOUE au-dessus d'une autre base, ce qui produit de NOUVEAUX commits, avec de nouveaux identifiants. Les originaux deviennent inatteignables. Tant que la branche est locale, cela n'a aucune conséquence — c'est même l'usage recommandé, rebaser sa branche sur la principale avant de proposer sa contribution, pour obtenir un historique lisible. Mais si un collègue avait déjà récupéré les commits d'origine, son dépôt contient une histoire que le vôtre ne connaît plus : au prochain échange, Git voit deux lignées divergentes, et la résolution est pénible. Git ne l'interdit pas techniquement — il l'autorise, et c'est bien le problème, la protection étant une règle d'équipe et non un garde-fou de l'outil. La formule à retenir : on réécrit ce qu'on n'a pas encore partagé, jamais ce que d'autres ont déjà.

Quiz · 1 question

Une équipe qui déploie plusieurs fois par jour maintient des branches de fonctionnalité vivant trois semaines. Où est l'incohérence ?

  • Nulle part : les branches longues et le déploiement fréquent sont deux sujets indépendantsindépendants
  • Une branche de trois semaines EST un lot de trois semaines : conflits larges, intégration risquée, retour arrière coûteux — exactement ce que la fréquence de déploiement était censée supprimerla branche est le lot
  • L'incohérence est technique : Git ne sait pas fusionner une branche de plus de deux semaineslimite de Git

Réponse : La fréquence de DÉPLOIEMENT ne dit rien à elle seule : ce qui compte est la fréquence d'INTÉGRATION. Une équipe qui déploie dix fois par jour la branche principale, mais dont chaque contribution y arrive après trois semaines d'isolement, subit exactement les maux du chapitre 1 : gros lots, conflits larges, incapacité à savoir quelle modification a cassé quoi. Le déploiement fréquent ne fait que rendre visible plus tôt un problème constitué depuis longtemps. C'est le raisonnement qui pousse au trunk-based : des branches de quelques heures, une intégration au moins quotidienne, et des drapeaux de fonctionnalité pour masquer l'inachevé plutôt que des branches pour l'isoler. Git n'a par ailleurs aucune limite de durée — la difficulté est statistique, la probabilité de conflit croissant avec le temps pendant lequel les fichiers bougent des deux côtés.

À vous

L'exercice simule un dépôt et rend visible ce que la ligne de commande cache.

D'abord la forme de l'historique : les mêmes contributions intégrées par fusion puis par rebasage, avec le graphe affiché dans les deux cas. Vous constaterez que le contenu final est identique et que les identifiants de commits, eux, ont changé — d'où la règle.

Ensuite un simulateur de stratégie de branchement : vous faites varier la durée de vie des branches et le nombre de contributeurs, et le programme compte les conflits, la taille des lots intégrés et le délai moyen d'intégration. Les chiffres de GitFlow et du trunk-based se séparent nettement, et ils se relient directement aux indicateurs DORA du chapitre 1.

Exercice de code

Comparez fusion et rebasage sur le même historique, puis chiffrez l'effet de la durée de vie des branches.

Point de départ

// ── 1. Fusion contre rebasage ─────────────────────────────────────────────
// Un commit : identifiant, message, parents.
let compteur = 0;
const commit = (msg, parents) => ({ id: "c" + (++compteur), msg, parents });

function creerDepot() {
  const a = commit("A : socle", []);
  const b = commit("B : lecture config", [a]);
  const c = commit("C : correctif principal", [b]);      // sur main
  const d = commit("D : début fonctionnalité", [b]);     // sur la branche
  const e = commit("E : fin fonctionnalité", [d]);
  return { a, b, c, d, e };
}

function fusionner(depot) {
  // La fusion CONSERVE d et e tels quels, et crée un commit à deux parents.
  const m = commit("M : fusion de la branche", [depot.c, depot.e]);
  return [depot.a, depot.b, depot.c, depot.d, depot.e, m];
}

function rebaser(depot) {
  // ← à écrire : rejouer d et e AU-DESSUS de c. Ce sont de NOUVEAUX commits.
  return [];
}

function afficher(nom, commits) {
  console.log("   " + nom);
  for (const c of commits) {
    const p = c.parents.map((x) => x.id).join(", ") || "—";
    console.log("      " + c.id.padEnd(4) + c.msg.padEnd(28) + "parents : " + p);
  }
}

// ── 2. Effet de la durée de vie des branches ──────────────────────────────
// Modèle simple : chaque jour, chaque contributeur produit une modification.
// Une branche accumule ses modifications jusqu'à son intégration. Le risque
// de conflit croît avec le nombre de modifications faites AILLEURS pendant
// qu'elle vivait.
function simuler({ contributeurs, jours, dureeBranche }) {
  const modifsParJour = contributeurs;
  const integrations = Math.floor(jours / dureeBranche) * contributeurs;
  const tailleLot = dureeBranche;                    // modifications par lot
  const modifsAilleurs = 0;                          // ← à écrire
  const probaConflit = 0;                            // ← à écrire
  return { integrations, tailleLot, modifsAilleurs, probaConflit,
           delaiIntegration: dureeBranche / 2 };
}

// ── À VOUS ────────────────────────────────────────────────────────────────
// 1. Écrivez rebaser(). Comparez les identifiants : que constate-t-on, et
//    pourquoi ne rebase-t-on pas une branche partagée ?
// 2. Complétez simuler() : pendant qu'une branche vit d jours, les autres
//    contributeurs produisent (contributeurs − 1) × d modifications.
//    La probabilité de conflit croît avec ce nombre.
// 3. Comparez GitFlow (branches de 15 jours) et trunk-based (0,5 jour) sur
//    six contributeurs et trois mois. Reliez aux indicateurs DORA.

const d = creerDepot();
afficher("après fusion", fusionner(d));

Solution

let compteur = 0;
const commit = (msg, parents) => ({ id: "c" + (++compteur), msg, parents });

function creerDepot() {
  const a = commit("A : socle", []);
  const b = commit("B : lecture config", [a]);
  const c = commit("C : correctif principal", [b]);
  const d = commit("D : début fonctionnalité", [b]);
  const e = commit("E : fin fonctionnalité", [d]);
  return { a, b, c, d, e };
}

function fusionner(depot) {
  const m = commit("M : fusion de la branche", [depot.c, depot.e]);
  return [depot.a, depot.b, depot.c, depot.d, depot.e, m];
}

function rebaser(depot) {
  // On ne DÉPLACE pas d et e : on les REJOUE au-dessus de c, ce qui produit
  // deux commits neufs. Les originaux deviennent inatteignables.
  const dPrime = commit("D' : début fonctionnalité (rejoué)", [depot.c]);
  const ePrime = commit("E' : fin fonctionnalité (rejoué)", [dPrime]);
  return [depot.a, depot.b, depot.c, dPrime, ePrime];
}

function afficher(nom, commits) {
  console.log("   " + nom);
  for (const c of commits) {
    const p = c.parents.map((x) => x.id).join(", ") || "—";
    console.log("      " + c.id.padEnd(5) + c.msg.padEnd(36) + "parents : " + p);
  }
}

console.log("— 1. deux façons d'intégrer le même travail —");
const d1 = creerDepot();
afficher("FUSION : l'histoire est conservée, le graphe se ramifie", fusionner(d1));
console.log("");
const d2 = creerDepot();
const apres = rebaser(d2);
afficher("REBASAGE : une ligne droite, mais des commits NEUFS", apres);
console.log("");
console.log("   Le contenu final est le même. Les identifiants, non : D et E");
console.log("   n'existent plus, remplacés par D' et E'. Tant que la branche est");
console.log("   locale, personne ne s'en aperçoit — c'est l'usage recommandé. Si");
console.log("   un collègue avait déjà récupéré D et E, son dépôt contient une");
console.log("   histoire que le vôtre ne connaît plus, et Git voit deux lignées");
console.log("   divergentes. On réécrit ce qu'on n'a pas partagé, jamais l'inverse.");

console.log("");
console.log("— 2 et 3. l'effet de la durée de vie des branches —");
function simuler({ nom, contributeurs, jours, dureeBranche }) {
  const integrations = Math.round((jours / dureeBranche) * contributeurs);
  const tailleLot = dureeBranche;
  // Pendant qu'une branche vit d jours, les AUTRES produisent leurs propres
  // modifications sur la même base : c'est là que naissent les conflits.
  const modifsAilleurs = (contributeurs - 1) * dureeBranche;
  const probaConflit = Math.min(0.95, 1 - Math.pow(0.97, modifsAilleurs));
  return { nom, integrations, tailleLot, modifsAilleurs, probaConflit,
           delaiIntegration: dureeBranche / 2 };
}

const scenarios = [
  { nom: "GitFlow (branches de 15 j)", contributeurs: 6, jours: 90, dureeBranche: 15 },
  { nom: "intermédiaire (3 j)",        contributeurs: 6, jours: 90, dureeBranche: 3 },
  { nom: "trunk-based (0,5 j)",        contributeurs: 6, jours: 90, dureeBranche: 0.5 },
];
console.log("   stratégie                  | intégrations | modifs/lot | conflit | délai");
for (const s of scenarios) {
  const r = simuler(s);
  console.log("   " + r.nom.padEnd(26) + " | " + String(r.integrations).padStart(12) +
    " | " + String(r.tailleLot).padStart(10) +
    " | " + (r.probaConflit * 100).toFixed(0).padStart(6) + " %" +
    " | " + r.delaiIntegration.toFixed(1).padStart(4) + " j");
}
console.log("   Six contributeurs, trois mois, même volume de travail. Seule change");
console.log("   la durée de vie des branches — et l'on retrouve exactement les");
console.log("   quatre indicateurs du chapitre 1 : la taille des lots gouverne le");
console.log("   délai d'intégration, la fréquence, et le risque.");
console.log("   Une branche de trois semaines EST un lot de trois semaines : un");
console.log("   pipeline qui déploie dix fois par jour n'y change rien, il rend");
console.log("   seulement visible plus tôt un problème constitué depuis longtemps.");

En travaux pratiques

Travaux pratiques 2 · 2 h

Mise en place du dépôt et diagnostic réseau

Lancer l'application du fil rouge à la main, diagnostiquer une erreur de réseau, puis installer la stratégie de branchement qui servira tout le semestre.

Avant de commencer

  • Une machine Linux ou un WSL, avec Git, Node et curl
  • L'archive de l'application tickets fournie par l'enseignant

Énoncé

  1. Lancer l'application, et échouerDémarrez l'application fournie, puis tentez de l'atteindre depuis un autre terminal avec curl. Elle ne répond pas. Ne modifiez rien tant que vous n'avez pas suivi les quatre questions du diagnostic. Indice : Le nom se résout-il ? Le port est-il écouté, et sur quelle interface ? La requête arrive-t-elle jusqu'au service ? Que répond-elle ?
  2. Identifier l'interface d'écouteListez ce qui écoute sur la machine et comparez l'adresse d'écoute à celle que vous interrogez. Corrigez la configuration, sans toucher au code métier. Indice : ss -tlnp montre l'adresse ET le port. Une application liée à 127.0.0.1 est injoignable de l'extérieur.
  3. Vérifier les droitsLe script de démarrage fourni n'est pas exécutable. Rendez-le exécutable pour son seul propriétaire, sans donner de droit d'écriture au groupe ni aux autres. Écrivez la valeur octale que vous employez et justifiez-la.
  4. Créer le dépôt et sa stratégieInitialisez un dépôt, poussez-le, protégez la branche principale, et écrivez un fichier CONTRIBUTING.md qui fixe la stratégie de branchement : durée de vie maximale d'une branche, taille maximale d'une demande de fusion, et délai maximal de relecture.
  5. Fusion contre rebasage, sur un vrai conflitÀ deux, modifiez la même ligne du même fichier sur deux branches. Intégrez la première par fusion, la seconde par rebasage. Comparez les deux historiques obtenus, puis dites laquelle des deux opérations vous vous interdiriez si la branche avait déjà été poussée. Indice : git log --graph --oneline --all rend la différence de forme immédiatement visible.

C'est réussi quand

  • curl obtient une réponse depuis un autre terminal, et vous savez dire quelle question du diagnostic a révélé la cause
  • Le script démarre et ses droits sont justifiés
  • La branche principale refuse un push direct
  • Vous savez énoncer la règle sur le rebasage d'une branche partagée

Correction

Le diagnostic, dans l'ordreterminal
dig +short localhost           # 1. le nom se résout
ss -tlnp | grep 3000           # 2. LISTEN 127.0.0.1:3000  <-- la cause
curl -v http://localhost:3000  # 3. la requête n'arrive pas
# rien dans les journaux du service : le problème est en amont

L'écoute sur 127.0.0.1 est le premier bogue de tout le monde, et il ressemble à une panne de pare-feu. La correction est de lier le service à 0.0.0.0, c'est-à-dire toutes les interfaces — ce qui sera indispensable dès le conteneur du chapitre 3.

Droits du scriptterminal
chmod 744 demarrer.sh
# 7 = rwx pour le propriétaire
# 4 = r-- pour le groupe et les autres : lecture seule

700 conviendrait aussi si personne d'autre n'a besoin de lire le script. Ce qu'il faut savoir justifier, c'est pourquoi on n'écrit pas 777 : donner le droit d'écriture à tout le monde sur un fichier exécuté permet à n'importe qui d'y placer ce qu'il veut.

Stratégie de branchementCONTRIBUTING.md
## Branches
- Une branche par tâche, DURÉE DE VIE MAXIMALE : 1 jour ouvré.
- Intégration dans main au moins une fois par jour.
- Le travail inachevé est masqué par un drapeau de fonctionnalité,
jamais isolé dans une branche longue.

## Demandes de fusion
- 400 lignes modifiées au maximum ; au-delà, découper.
- Relecture sous 4 h ouvrées.
- Rebasage sur main AVANT la demande, jamais après partage.

Les trois nombres sont des décisions d'équipe, pas des vérités : ce qui compte est qu'ils soient écrits et tenus. Une branche d'un jour rend les conflits rares et étroits, et c'est le seul moyen de tirer parti du pipeline du chapitre 5.

Ce que montrent les deux historiquesterminal
git log --graph --oneline --all

*   9f2a1c4 (main) Merge branch 'ajout-filtre'     <-- fusion : le graphe fourche
|\
| * 3d8e7b1 ajout du filtre
* | 7c4b9a2 correctif du tri
|/
* 1a2b3c4 socle

* 5e6f7a8 (main) ajout du filtre (rejoué)          <-- rebasage : ligne droite
* 7c4b9a2 correctif du tri
* 1a2b3c4 socle

Le contenu final est identique ; seule la forme diffère. Le commit rejoué porte un nouvel identifiant : les anciens sont devenus inatteignables, et c'est pourquoi on ne rebase jamais une branche que d'autres ont déjà récupérée. La pratique courante est de rebaser sa branche locale sur main avant de proposer, puis de fusionner.

Ce que la suite en fait

Le bloc II attaque le premier vrai sujet : empaqueter l'application avec tout ce dont elle a besoin, pour que « ça marche sur ma machine » cesse d'être une excuse. Les droits Unix et les signaux de ce chapitre y reviennent dès le premier Dockerfile, et la question du port écouté y devient le premier bogue de tout le monde.

Et la revue de code retrouvera son sens au chapitre 5 : une demande de fusion est ce qui déclenche le pipeline, et le pipeline est ce qui rend la revue supportable — le relecteur n'a plus à vérifier que le code compile et que les tests passent.

À retenir

Flashcards · 5 cartes

Quelle est la différence entre SIGTERM et SIGKILL, et pourquoi compte-t-elle en DevOps ?
SIGTERM demande de s'arrêter PROPREMENT, SIGKILL tue sans préavis et sans possibilité d'y réagir. Docker et Kubernetes envoient un SIGTERM, attendent quelques secondes, puis un SIGKILL : une application qui n'écoute pas SIGTERM perd donc ses requêtes en cours à CHAQUE déploiement, et personne ne comprend d'où viennent les erreurs sporadiques.
Dans quel ordre diagnostique-t-on un « ça ne répond pas » ?
1) LE NOM SE RÉSOUT-IL ? (dig, nslookup) — un DNS mal propagé ressemble à une panne applicative. 2) LE PORT EST-IL ÉCOUTÉ ? (ss -tlnp en local, curl -v ou nc depuis l'extérieur) — un service qui écoute sur 127.0.0.1 marche en local et est injoignable ailleurs. 3) LA REQUÊTE ARRIVE-T-ELLE ? les journaux du serveur le disent ; sinon le problème est en amont (pare-feu, routage). 4) QUE RÉPOND-ELLE ? — et un 502 accuse le service en amont quand un 500 accuse l'application.
Fusion ou rebasage : que produisent-ils, et quelle est la règle absolue ?
MERGE préserve l'histoire telle qu'elle s'est produite, au prix d'un graphe ramifié. REBASE rejoue les commits au-dessus d'une autre base pour donner une ligne droite, plus lisible — mais il crée de NOUVEAUX commits. D'où la règle : on ne rebase JAMAIS une branche déjà partagée, les originaux devenant inatteignables pour ceux qui les avaient récupérés. Usage courant : rebaser sa branche LOCALE sur la principale avant de proposer sa contribution, puis fusionner.
Opposez GitFlow et trunk-based, et reliez au chapitre 1.
GITFLOW : branches durables (main, develop, fonctionnalité, version, correctif), semaines de vie, gros lots, conflits larges — adapté aux versions INSTALLÉES chez des clients, avec plusieurs versions maintenues. TRUNK-BASED : une branche principale, intégration au moins quotidienne, branches de quelques heures, inachevé masqué par des drapeaux de fonctionnalité — adapté au service en ligne. Le lien : une branche de trois semaines EST un lot de trois semaines, avec tous les maux du chapitre 1.
Quelles sont les trois règles d'une demande de fusion, et pourquoi la première commande les autres ?
PETITE : au-delà de quelques centaines de lignes, le taux de détection s'effondre — une demande de deux mille lignes est approuvée sans être lue. RAPIDE : une demande qui attend bloque son auteur et se désynchronise, donc produit des conflits. SUR LE CODE, PAS SUR LA PERSONNE : c'est le post-mortem sans blâme appliqué à la relecture. La taille commande le reste : petite, elle est relue vite et sérieusement.