3. La synchro et le lockfile
C’est ici que tout s’éclaire. Tu as un haw.toml du chapitre précédent. Maintenant tu vas lancer haw sync pour cloner la flotte pour de vrai, lire le lockfile qui la fige sur des commits exacts, prouver qu’elle est reproductible et — délibérément — casser quelque chose pour voir haw détecter la dérive.
Tout se clone ici en HTTPS sans authentification, donc tu peux vraiment lancer chaque commande au fil de ta lecture. Garde ouvert l’espace de travail my-first-stack du chapitre 2.
La synchro clone la flotte ; le lockfile la fige sur des commits exacts — toute l’astuce de la reproductibilité.
🎯 Dans ce chapitre, tu vas apprendre à…
- Lancer
haw syncpour cloner la flotte et générerhaw.lock. - Lire la flotte avec
haw treeethaw status, et comprendre chaque colonne. - Lire les vrais champs du lockfile —
rev(le SHA résolu),source-revetbranch. - Resynchroniser et confirmer que c’est idempotent — le lock, pas la branche, fait désormais foi.
- Provoquer une dérive exprès et la détecter avec
haw verify(exit 3), puis restaurer.
La boucle de composition complète que tu vas lancer : sync clone la flotte, puis tree / status la lisent et le lock l’épingle.
🔄 1. Sync — tout cloner et écrire le lock
Une seule commande matérialise l’arbre :
haw sync
haw résout le rev de chaque dépôt en un commit exact, le clone et — parce qu’il n’y a pas encore de lockfile — en écrit un. Tu verras la progression par dépôt et un récapitulatif. Ensuite, jette un œil autour de toi :
$ ls
haw.lock haw.toml hello-world/ spoon-knife/
Les voilà : deux clones Git réels et complets, plus un haw.lock tout neuf. Pas de sous-modules, pas de liens symboliques — tu pourrais faire cd hello-world && git log et c’est juste du Git.
Astuce : haw sync est idempotent. Relance-le et, comme le lock épingle déjà des SHA exacts, haw s’assure simplement que ton arbre correspond — aucune surprise, sans risque à répéter dans les scripts et la CI.
🔍 2. Explorer la flotte
Maintenant les commandes de lecture. D’abord, la forme des choses :
haw tree
haw.toml
└─ site
├─ hello-world master (https://github.com/octocat/Hello-World.git)
└─ spoon-knife main (https://github.com/octocat/Spoon-Knife.git)
Voilà ton arbre stack → dépôt : la stack site, les deux dépôts en dessous, chacun avec son rev déclaré et son origine.
Maintenant le bilan de santé :
haw status
REPO BRANCH HEAD DIRTY DRIFT
hello-world master 7fd1a60b - -
spoon-knife main d0dd1f61 - -
Lis les colonnes de gauche à droite : le dépôt, la branche sur laquelle il se trouve, son SHA HEAD court, si l’arbre de travail a des changements non committés (DIRTY) et si HEAD diffère du SHA verrouillé (DRIFT). Pour l’instant tout est propre et synchronisé — les tirets signifient « tout va bien ».
Astuce : Dans un terminal, tout est codé par couleur — noms de dépôts en cyan, revs en jaune, vert pour propre, rouge pour la dérive. Redirige la sortie n’importe où et elle bascule automatiquement en texte brut (elle respecte NO_COLOR), donc c’est compatible avec les scripts par défaut.
🔒 3. Lire le lockfile
Ouvre haw.lock dans ton éditeur. Chaque dépôt est épinglé à un SHA complet de 40 caractères dans son champ rev — le commit exact, pas le nom de branche — tandis que source-rev consigne ce que tu as demandé et branch consigne la branche d’où vient ce SHA :
# extrait — tes SHA seront différents
[[repo]]
name = "hello-world"
url = "https://github.com/octocat/Hello-World.git"
path = "hello-world"
rev = "7fd1a60b01f91b314f59955a4e4d4e80d8edf11d" # le commit résolu — voici l'épingle
source-rev = "master" # ce que tu as déclaré dans haw.toml
branch = "master" # la branche d'où ce SHA a été résolu
groups = ["core"]
Voilà toute l’astuce de la reproductibilité. Ton manifeste disait « master » (une cible mouvante), mais le lock a figé le commit exact que master pointait au moment où tu as synchronisé — c’est le SHA qui est maintenant dans rev. source-rev se souvient de ton intention (master) et branch se souvient d’où ça venait, donc haw peut plus tard re-résoudre si tu le demandes. Committe haw.lock aux côtés de haw.toml, et quiconque clone et lance haw sync obtient précisément ces commits — pas ce que master se trouve être aujourd’hui.
Ne l’édite pas à la main. haw.lock est généré. Tu le committes, mais tu changes l’intention dans haw.toml et tu laisses haw lock / haw sync régénérer le lock.
♻️ 4. Prouve que c’est reproductible — relance sync
haw sync
Parce que le lock existe, haw synchronise vers les SHA épinglés, pas vers là où les branches ont bougé. Relance haw status et tu verras la même flotte propre. C’est tout l’intérêt de l’idempotence : le lock, pas la branche, est désormais la source de vérité.
🧭 5. Vois la dérive de tes propres yeux
La reproductibilité n’est utile que si tu peux détecter quand l’arbre s’écarte de la référence. Provoquons cela exprès. Déplace un dépôt vers un commit différent à la main :
cd hello-world
git checkout HEAD~1 # recule d'un commit — maintenant HEAD ≠ le SHA verrouillé
cd ..
Demande à haw ce qu’il en pense :
haw status
REPO BRANCH HEAD DIRTY DRIFT
hello-world (detached) 553c2077 - YES
spoon-knife main d0dd1f61 - -
La voilà — DRIFT: YES sur hello-world. Faire un checkout d’un commit précis détache aussi HEAD (d’où (detached) dans la colonne BRANCH), et son HEAD ne correspond plus au SHA verrouillé. haw status l’a signalé, mais pour la CI tu veux une commande qui échoue en cas de dérive. C’est verify :
haw verify
verify vérifie que l’arbre sur disque correspond à haw.lock et sort avec le code 3 quand ce n’est pas le cas — un garde-fou de dérive propre et scriptable. Vérifie le code de sortie :
haw verify; echo "code de sortie : $?"
✗ hello-world drift (head != lock)
verify failed: 1 repo(s) diverge from haw.lock
exit code: 3
Ce code de sortie 3 est ce sur quoi un pipeline CI se cale : « l’arbre a dérivé du lock — arrête le build. » (Quand tout correspond, verify affiche verified: tree matches haw.lock (2 repos) et sort avec 0.)
haw verify détectant la dérive dans la CI juste avant une release.
Maintenant remets-le en place. haw sync restaure chaque dépôt à son SHA verrouillé :
haw sync
haw verify; echo "code de sortie : $?"
verified: tree matches haw.lock (2 repos)
exit code: 0
Propre à nouveau. Tu viens de voir la boucle complète : déclarer → synchroniser → épingler → détecter la dérive → restaurer.
Tu viens de faire la boucle fondamentale. Déclarer l’intention, l’épingler, détecter la dérive et restaurer la référence — les quatre mêmes mouvements passent à l’échelle de deux dépôts octocat à une flotte de cent dépôts.
🙌 À toi de jouer
Prouve que le lockfile est vraiment la source de vérité :
- Ouvre
haw.locket trouve le SHA épinglé de chaque dépôt dans son champrev. Confirme que c’est un commit de 40 caractères, pas un nom de branche, et quesource-revmontre toujours ce que tu as déclaré. - Fais dériver un dépôt exprès (
cd hello-world && git checkout HEAD~1 && cd ..), lancehaw verify; echo $?, et confirme que tu obtiens le code de sortie3. - Lance
haw syncpour restaurer, puishaw verify; echo $?à nouveau — retour à exit0. Cet aller-retour, c’est la garantie de reproductibilité.
✅ Récapitulatif
haw syncclone chaque dépôt et écrithaw.lock— de vrais clones Git, sans sous-modules/liens symboliques. C’est idempotent.haw treemontre la forme stack→dépôt ;haw statusmontre branche/HEAD/dirty/drift par dépôt.haw.locképingle chaque dépôt à un SHA exact de 40 caractères dansrev, avecsource-rev(ton intention déclarée) etbranchà côté — committe-le pour des rebuilds identiques octet pour octet.- Drift = HEAD diffère du lock.
haw statusle signale ;haw verifysort avec le code 3 en cas de dérive (ton garde-fou CI).haw syncrestaure la référence.
👉 La suite
Tu sais composer et épingler une flotte — maintenant vivons dedans. Découvre le cockpit qui pilote tout ça au clavier → 4. Le cockpit TUI.