Empêcher la suppression automatique du worktree de Claude Code avec git worktree lock
Cet article analyse la logique de nettoyage interne de Claude Code (v2.1.263) pour les worktrees créés avec l'option `--worktree`. Lorsqu'une session se termine sans modification en attente et sans nouveau commit, le worktree et sa branche sont supprimés silencieusement. En examinant le code source fourni, l'auteur révèle les conditions exactes déclenchant cette suppression et explique comment Claude Code utilise `git worktree lock` avec un format de raison spécifique pour suivre ses sessions. Tout verrou avec une raison ne correspondant pas à ce motif sera considéré comme un verrou externe et donc protégé du nettoyage. Des solutions pratiques incluent le déverrouillage et reverrouillage manuels, ou l'automatisation via un hook `SessionStart`.
Contexte et problématique
Le mode `--worktree` de Claude Code offre aux développeurs la possibilité d'exécuter des sessions dans un worktree Git isolé, évitant ainsi toute interférence avec le répertoire de travail principal. Cependant, une situation pour le moins déconcertante se produit lorsqu'on lance `claude --worktree feature-x`, que l'on effectue des explorations de code ou des modifications expérimentales, puis que l'on quitte la session via `/exit` : le worktree et sa branche associée sont supprimés silencieusement, sans aucune invite de confirmation. Nombreux sont les développeurs qui pensent à tort qu'une session « suffisamment propre » préservera leur worktree, pour découvrir ensuite que tout le contexte de travail accumulé a disparu.
La documentation officielle reconnaît explicitement ce comportement comme une fonctionnalité délibérée : en l'absence de modifications non commitées et lorsque la session n'est pas nommée, le worktree et la branche sont automatiquement retirés ; une session nommée déclenche quant à elle une boîte de dialogue « Keep/Remove ». Mais la documentation ne fournit aucune option de configuration pour désactiver globalement ce mécanisme. Cela signifie que tous les scénarios d'exploration « lecture seule » ou de modifications annulées sont exposés à ce nettoyage furtif. Plusieurs rapports de la communauté (issues #27753, #46444, #58432) ont été fermés avec la mention « comportement attendu », révélant les controverses que cette conception suscite dans la pratique du génie logiciel.
Ce problème touche directement la productivité des équipes qui adoptent Claude Code comme assistant de codage. Le worktree, en tant qu'environnement de travail éphémère mais structuré, sert de conteneur pour l'ensemble du contexte de la session : historique des commandes, état du terminal, discussions avec l'agent. Sa suppression sans préavis représente une perte d'information bien plus conséquente que la simple disparition d'une branche Git.
Architecture et mécanisme
La logique de nettoyage de Claude Code réside dans le code JavaScript empaqueté de l'application. Par rétro-ingénierie, on peut reconstituer l'algorithme de décision. Au moment de `/exit`, Claude Code évalue deux indicateurs d'état Git. D'abord, il exécute `git status --porcelain` pour détecter les modifications non staging ou les fichiers non suivis. Ensuite, il calcule le nombre de nouveaux commits depuis le début de la session avec `git rev-list --count <session-start-HEAD>..HEAD`. Trois cas se présentent selon la combinaison de ces métriques : si les deux sont nuls et que la session n'est pas nommée, suppression silencieuse ; si les deux sont nuls mais la session est nommée, affichage d'une boîte de dialogue Keep/Remove ; si l'un des deux indicateurs est non nul, la boîte de dialogue s'affiche quoi qu'il arrive.
Le problème majeur réside dans le troisième cas (zéro modification, zéro commit, session non nommée). C'est précisément le scénario typique de l'exploration sans suite ou des modifications annulées. Ce qui rend la situation encore plus subtile, c'est que Claude Code utilise lui-même `git worktree lock` pour gérer le verrouillage de ses sessions. Au lancement, il écrit un motif de verrouillage au format fixe : `claude session <nom> (pid <PID> start <timestamp>)`. À la sortie, une expression régulière `/^claude (?:agent|session) .{1,255} \( pid (\d{1,10})(?: start (.{1,255}))? \)$/` valide si le verrou appartient bien à la session en cours. Si le motif ne correspond pas (par exemple après une modification manuelle), le code considère que le worktree est « verrouillé par un autre processus » et saute l'étape de nettoyage. Git fournit ici un filet de sécurité : comme le précise la documentation officielle, « sweep ne libère jamais les verrous que vous avez posés vous-même ».
La clé de la protection réside donc dans la manipulation de ce mécanisme de verrouillage. Puisque Claude Code vérifie uniquement la conformité du motif de verrouillage à son format interne, un verrou avec un motif personnalisé — par exemple `"pinned by ryan"` — empêche toute suppression automatique. La séquence d'opérations est la suivante : d'abord `git worktree unlock .claude/worktrees/<nom>` pour libérer le verrou de Claude Code, puis `git worktree lock --reason "pinned by ryan" .claude/worktrees/<nom>` pour le remplacer par un verrou personnalisé. Il est impératif de déverrouiller avant de reverrouiller, faute de quoi Git retourne une erreur de conflit.
Performances et impact pratique
Dans un dépôt de test, il est possible de reproduire précisément le phénomène de suppression silencieuse. Après avoir exécuté `claude --worktree wt-clean` pour créer une session dans un worktree vide, un simple `/exit` immédiat provoque l'affichage éphémère du message `Cleaning up worktree (no pending changes)…`, puis le worktree et sa branche disparaissent. La commande `git worktree list` ne montre alors plus que le worktree principal. L'ensemble de l'opération prend moins d'une seconde, ne laissant pratiquement aucune fenêtre de réaction.
La stratégie de protection fondée sur le verrouillage s'avère d'une efficacité redoutable. Durant l'exécution d'une session, il suffit d'ouvrir un autre terminal (ou d'utiliser `!` dans Claude Code pour exécuter une commande shell) et d'enchaîner les deux commandes `git worktree unlock` et `git worktree lock` avec un motif personnalisé. Après cette opération, un `/exit` ne déclenche plus la suppression : Claude Code constate que le motif du verrou ne correspond pas à son format attendu et abandonne le nettoyage. La vérification par `git worktree list` confirme que le worktree est toujours présent, marqué `locked`. Une session ultérieure avec `claude --worktree wt-lock` peut le réutiliser normalement.
Pour les équipes qui recherchent une solution automatisée, l'approche la plus élégante consiste à créer un hook `SessionStart` dans le répertoire `.claude/hooks/` du projet. Ce script shell, par exemple `pin-worktree.sh`, utilise `git rev-parse --git-dir` et `git --git-common-dir` pour détecter si l'on se trouve dans un linked worktree (à l'exclusion du dépôt principal), puis exécute la séquence unlock/lock. Cette méthode garantit qu'à chaque démarrage de session, le worktree est automatiquement verrouillé et donc préservé à la sortie, sans aucune intervention humaine. Le surcoût en temps d'exécution est négligeable : les deux commandes Git s'exécutent en quelques millisecondes.
Perspectives et implications
Ce problème révèle un décalage fondamental entre la conception du « nettoyage automatique » dans les outils d'assistance au codage par intelligence artificielle et le modèle mental des développeurs. Lorsqu'un ingénieur utilise `--worktree`, il perçoit le worktree comme un conteneur de développement autonome, doté d'une valeur intrinsèque même en l'absence de traces Git : l'environnement de recherche, l'historique des commandes, le contexte de la conversation avec l'agent constituent un capital informationnel précieux. En prenant l'absence de modifications comme unique critère de suppression, Claude Code ignore complètement cette dimension.
D'un point de vue architectural, le mécanisme de verrouillage de Claude Code offre à la communauté une interface de défense flexible. Bien que l'éditeur n'ait pas prévu d'interrupteur de configuration, les utilisateurs peuvent exploiter les capacités natives de Git pour obtenir un résultat équivalent. Cette situation illustre un principe de conception plus large : les outils les plus robustes sont ceux qui laissent un espace de personnalisation entre la « commodité automatisée » et le « contrôle utilisateur ». L'introduction d'un indicateur explicite `--keep-worktree` ou d'une option `worktreeCleanupPolicy` dans le fichier de configuration résoudrait le problème à la racine. Par ailleurs, la proposition communautaire d'un hook `WorktreeRemove`, qui permettrait d'exécuter des vérifications personnalisées avant la suppression, mérite une attention particulière.
Pour toute équipe utilisant intensivement Claude Code, l'intégration du script de verrouillage dans le modèle d'initialisation du projet constitue une pratique standard à recommander. Cette mesure protège non seulement les espaces de travail temporaires, mais évite aussi les confusions de collaboration qui surviennent lorsqu'une branche disparaît sans explication. Les améliorations techniques apparemment mineures — comme la modification d'un motif de verrouillage — peuvent avoir un impact considérable sur l'efficacité collective d'une équipe de développement. En définitive, la maîtrise fine de ces mécanismes distingue une adoption superficielle d'une intégration profonde et professionnelle des outils d'IA générative dans le cycle de développement logiciel.
Sources
FAQ
Comment le mécanisme de nettoyage automatique de worktree est-il déclenché dans Claude Code ?
Lors de la sortie d'une session --worktree sans modification, sans nouveau commit et sans nom de session, le worktree et la branche sont supprimés silencieusement.
Comment empêcher la suppression du worktree ?
Utilisez `git worktree lock` pour verrouiller le worktree, ou utilisez le hook SessionStart pour déverrouiller puis verrouiller automatiquement.
Existe-t-il une option de configuration pour désactiver le nettoyage automatique ?
La documentation officielle reconnaît cela comme une fonctionnalité et ne propose pas d'interrupteur de configuration ; seules des solutions externes sont possibles.