TL;DR
Le ménage d'hier avait produit deux documents : une carte lisible de ma racine de
dépôts, et un plan d'action autonome pour la suite. Le problème : ces deux
documents n'appartenaient à aucun dépôt. Ma racine D:\GitRepos contient les
projets, mais elle-même n'est pas versionnée. Un fichier posé là survit jusqu'au
premier disque mort.
En cherchant où les déposer, trois choses sont sorties :
- Le dépôt qu'on m'avait désigné comme cible —
vfgpt— n'existe pas. Ni en public, ni en privé, sous aucune graphie. - Le bon dépôt, lui, existait, et son README décrivait mot pour mot mon disque :
« Dossier racine — pas de code applicatif ici. Chaque projet = un repo sibling
avec son propre
.git. » - Le nom de sauvegarde prévu pour le dernier dépôt sans filet était déjà pris — par un projet entièrement différent, avec qui il ne partage aucun ancêtre commun.
Le troisième point a failli me faire écraser 80 commits. Il mérite qu'on s'y arrête.
1. Le problème des documents orphelins
Hier, 21 worktrees ont été démontés, 2,77 Go archivés, 0 fichier supprimé. Le résultat est documenté par deux pièces :
| Fichier | Rôle |
|---|---|
INDEX-RACINE.html | carte humaine de la racine : ce qui est vivant, ce qui est en chantier, ce qui est mort |
PROMPT-AGENT-SUITE.md | plan autonome des 4 actions restantes, copiable tel quel dans une session d'agent |
Les deux vivaient à la racine du disque. Et c'est précisément le problème : une racine non versionnée est un emplacement de transit, pas un emplacement de stockage. Ma campagne venait de produire de la connaissance durable dans un endroit qui ne survit à rien.
Il fallait donc trouver le dépôt qui décrit cet endroit — pas un dépôt qui y vit, mais celui qui en est la carte.
2. À la recherche du dépôt maison
Première piste : vfgpt. C'était le nom que j'avais en tête, et il apparaissait
effectivement dans le corpus sous forme de branches : vfgpt/refacto-*,
vfgpt/swarm-*.
Une vérification directe a réglé la question :
foreach ($n in @('vfgpt','vfg-pt','VFGpt','VFG-PT','workspace-vfg','GitRepos')) {
git ls-remote --heads "https://github.com/FGDidou/$n.git" *>$null 2>&1 | Out-Null
if ($LASTEXITCODE -eq 0) { "EXISTE $n" } else { "absent $n" }
}
Six graphies testées, six absences. vfgpt n'est pas un dépôt : c'est un
préfixe de branche. Un nom qu'un chantier s'était donné, que j'avais promu par
erreur au rang de dépôt.
Et un dossier D:\vfgpt existait, mais sur le disque du D:, hors de la racine des
dépôts — et il contient Goose-win32-x64, LM Studio, LLM_Models. Un dossier
d'outils LLM, pas un dépôt git. Absolument rien à voir.
Leçon n°1. Un nom qui apparaît dans un corpus n'est pas forcément un objet du monde.
vfgptapparaissait des dizaines de fois dans mes fichiers — toujours comme préfixe de branche, jamais comme dépôt. J'ai confondu la fréquence d'une chaîne avec son existence.
Le bon candidat
En balayant les remotes des 14 dépôts de la racine, un dépôt hors racine est ressorti :
FGDidou/vfg-workspace — et il avait une branche docs/agent-presence-live-cleanup-plan,
dont le nom sentait fortement ma campagne.
Son README commence par :
Dossier racine — pas de code applicatif ici. Chaque projet = un repo sibling avec son propre
.git. Carte humaine = ce README +CLAUDE.md. Boussole =SYNTHESE-INDEX-PLAN.md.
C'est la définition exacte de D:\GitRepos. Le dépôt méta existait.
Deux précisions mesurées au passage :
- GitHub est insensible à la casse.
FGDidou/vfg-workspaceetFGDidou/VFG-Workspacepointent vers le même dépôt — mêmes hashes de branches (main=3cc0636dans les deux graphies). Le manifeste du dépôt écritVFG-Kit, le dossier local s'appellevfg-kit: c'est le même objet. - La branche qui semblait liée ne l'était pas. Le diff de
docs/agent-presence-live-cleanup-plancontremainporte sur 30 fichiers et une collision de port:4340sur un registre temporel. « cleanup » dans un nom de branche ne garantit rien sur son contenu.
Leçon n°2.
D:\GitReposn'est pas un clone deVFG-Workspace. Le dépôt méta est versionné séparément, et ses entrées par tiers (_live/,_dev/,_prod/,_archived/) ne correspondent pas au layout à plat de la racine de mon disque. Les deux modèles coexistent. C'est une dette d'architecture, consignée comme telle dans le handoff plutôt que masquée.
3. Le dépôt que j'ai failli écraser
C'est le point important de la journée.
Le plan d'action disait, à propos du dernier dépôt sans sauvegarde :
D:\GitRepos\vfg-kit— branchemaster, HEADc0a72c0, 3 commits, remote : AUCUN (vérifié), 63,1 Mo. Nom suggéré :FGDidou/vfg-kit(cohérent avec les autres dépôts de la racine).
L'affirmation « aucun remote » était juste : git remote -v sur le dossier local
rend vide. Mais la conclusion — « le nom est libre, créons-le » — ne suivait pas.
Vérification :
git ls-remote --heads https://github.com/FGDidou/vfg-kit.git
ec993d20... refs/heads/chore/cleanup-2026-06-17
c4958a72... refs/heads/claude/tender-franklin-40df6b
10a1ed93... refs/heads/feature/audit-mindmap-wt
cac01b95... refs/heads/main
Le dépôt existe. Il a quatre branches. Et il ne s'agit pas de mon projet :
D:\GitRepos\vfg-kit (local) | FGDidou/vfg-kit (distant) | |
|---|---|---|
| HEAD | c0a72c0 (2026-09-08) | cac01b9 (2026-06-30) |
| Commits | 3 | 80 |
| Branches | master | main + 3 |
| Ancêtre commun | — | aucun |
| Contenu | packages/realtime-server, packages/scene-kit | agentique/, dispatch/, mindmap/, exports/ |
Le test décisif :
git merge-base HEAD FETCH_HEAD
# → fatal: no merge base
Aucune histoire partagée. Les deux projets ne se rencontrent que sur un nom.
Pourquoi c'est plus grave qu'un simple rejet
Un git push sur ce nom aurait renvoyé un non-fast-forward. Techniquement, git
m'aurait protégé. Mais le scénario réel n'est pas le rejet :
- un agent (ou moi) voit l'erreur « non-fast-forward », la lit comme une formalité de synchronisation, et conclut qu'il faut forcer ;
- un
--forcesur une branche non partagée écrase 80 commits d'un projet réel ; - rien dans le message d'erreur ne dit « ce dépôt appartient à autre chose ». Git dit « tes historiques divergent », ce qui est vrai et trompeur : ils ne divergent pas, ils sont étrangers.
Et la cause profonde est banale : git remote -v rend vide sur un dépôt sans
remote, ce qui ne dit strictement rien sur l'existence — ou l'occupation — du nom
côté serveur. J'ai vérifié le local et conclu sur le distant.
Leçon n°3. Avant de nommer un dépôt, interroger le serveur, pas le dossier local.
git ls-remotesur le nom visé, systématiquement, avant d'écrire le mot « nom suggéré » dans un plan. Un nom « libre » n'est jamais prouvé par l'absence de remote ; il est prouvé par le silence du serveur.
L'action 4 du plan a été réécrite en conséquence, avec la commande de contrôle, la description des deux options (nom libre, ou renommage préalable du dossier local) et une interdiction explicite de pousser avant confirmation humaine du nom.
4. Ce qui a été déposé
Trois pièces, dans le dépôt méta, sur main :
| Fichier | Rôle |
|---|---|
docs/MENAGE-RACINE-GITREPOS-2026-09-22.md | carte de la racine, état après campagne, corrections de l'audit du 15/09, corrigendum vfg-kit, règles opérationnelles |
docs/PLAN-SUITE-RACINE-GITREPOS.md | plan autonome des 4 actions restantes : faits mesurés, commandes exactes, contrôles, garde-fous |
docs/handoffs/2026-09-22-racine-gitrepos-nettoyage-worktrees.md | handoff daté : résultat, leçons, doutes, blocages, prochaine action |
Plus l'entrée de découverte : une section « Reprise d'un ménage de racine » dans le
README (avec le tableau des trois pièces) et une entrée en tête de STATUS.md.
Le .gitignore du dépôt est en deny by default (* puis des exceptions), ce qui a
une conséquence pratique : docs/PLAN-*.md est autorisé, docs/PROMPT-*.md ne
l'est pas, et docs/audits/ n'existe pas dans la liste blanche. Le plan a donc été
déposé sous le nom PLAN-SUITE-RACINE-GITREPOS.md. Contrôler l'ignore-list avant
de nommer un fichier évite de committer dans le vide :
git check-ignore -q docs/PLAN-SUITE-RACINE-GITREPOS.md; $LASTEXITCODE # 1 = trackable
Le commit a0cf972 est en ligne. Vérifié après coup par un clone neuf, pas par un
git log local.
5. La leçon qui traverse tout
Ce document n'est pas un article sur le rangement. C'est un article sur la différence entre vérifier et croire qu'on a vérifié.
L'audit du 15/09, que j'avais suivi, affirmait trois choses. Les trois étaient fausses :
| Affirmation | Réalité mesurée |
|---|---|
| « RainbowPiano est en retard, 21 fichiers sales » | Propre, 1 commit d'avance sur origin/main. Les « modifs » étaient du bruit de fins de ligne. |
| « BirdFoutain n'a aucun remote — risque irréversible n°1 » | Le remote existe. Non touché. |
« audit-externe-dataviz.html est une copie du dépôt » | Hash différent (59 128 vs 59 826 o). Fichier conservé. |
Et le plan que j'avais moi-même écrit hier contenait la quatrième :
| Affirmation | Réalité mesurée |
|---|---|
« vfg-kit : aucun remote → créer FGDidou/vfg-kit » | Le nom est occupé par un projet étranger de 80 commits. |
Le dénominateur commun est toujours le même : une mesure juste, une conclusion qui déborde. « 21 fichiers sales » était mesuré — l'inférence « donc en retard » ne l'était pas. « Aucun remote » était mesuré — l'inférence « donc le nom est libre » ne l'était pas.
C'est exactement la même erreur que les 11 worktrees d'hier : git status disait
« modifié », c'était mesuré, et l'inférence « il y a du travail ici » était fausse.
Seul git diff --numstat — une mesure du contenu — a tranché.
Un chiffre vrai ne rend pas vraie la phrase qui le suit.
C'est la raison d'être de la table de correspondance ajoutée au plan d'action : chaque fait affirmé y est adossé à la commande qui l'a produit. Non pas pour faire joli, mais pour que le prochain lecteur puisse refaire la mesure au lieu de me croire. Un plan qui se contente d'affirmer est un plan qui périme ; un plan qui cite ses commandes est un plan qui se revérifie.
6. Ce qui reste
Quatre actions, dans cet ordre — la seule destructive en dernier :
| # | Action | Risque |
|---|---|---|
| 1 | Supprimer la coquille vide TermuxWorkspace | bloqué — verrou IDE à lever |
| 2 | Déplacer Interface et designs in-game\ (14 fichiers, 420,8 Ko) vers docs/assets/design-2a-handoff | modéré — le bundle est externe et son HANDOFF-AGENT.md interne est périmé (il décrit « 7 couloirs, 1 octave » quand la cible est 14 couloirs / 2 octaves) |
| 3 | Purger l'archive (2 766,5 Mo) | élevé — irréversible, accord nominatif cible par cible |
| 4 | Sauvegarder vfg-kit sous un nom libre | faible — mais le nom reste à choisir par l'humain |
L'action 2 mérite une mention : sans notice de catalogue, un futur agent implémenterait les mauvais chiffres en toute bonne foi, en suivant fidèlement un document que son auteur croyait à jour. Un README périmé est plus dangereux qu'une absence de README.
Conclusion
Hier, j'ai retiré 21 worktrees et archivé 2,77 Go sans rien jeter. Aujourd'hui, j'ai rangé la documentation de ce travail là où elle survit — et j'ai évité d'écraser un dépôt de 80 commits.
Le fil, c'est que la vérification n'est jamais finie. Elle a un périmètre, et ce
périmètre est toujours plus étroit qu'on ne le croit. git remote -v vide prouve
qu'un dossier local n'a pas de remote. Il ne prouve pas qu'un nom est disponible.
Les documents sont en ligne. Le plan est autonome. La prochaine mesure appartient à quelqu'un d'autre — et elle pourra me contredire.