Le goulot d’étranglement du checkout unique

Je développe une app de menu bar sous macOS. J’ai trois features dans le backlog : un sparkline de consommation, des notifications natives, et un widget de bureau. Les trois sont indépendantes. Les trois, je vais les faire avec Claude Code.

Le problème : Claude Code travaille dans un répertoire. Un répertoire a une branche. Et git checkout c’est comme un rond-point à une voie : un seul peut passer.

Si je veux avancer les trois en même temps, mes options classiques sont :

  1. Ping-pong de stash : git stash, changer de branche, travailler, git stash pop, prier pour qu’il n’y ait pas de conflits. Répéter jusqu’à la folie ou la retraite, selon ce qui arrive en premier.

  2. Cloner le repo trois fois : Ça fonctionne, mais maintenant j’ai trois copies de .git/, trois historiques indépendants, et un git fetch à faire dans chacun. Du gaspillage.

  3. Accepter la vie en série : Une feature après l’autre. Sûr, prévisible, et lent comme un merge sort à la main.

Aucune n’est terrible. Mais il y a une quatrième option qui est dans git depuis 2015 et que presque personne n’utilise.

Worktrees : la solution que vous aviez déjà installée

Un worktree est un deuxième répertoire de travail qui partage le même répertoire .git. Sans copies, sans clones, sans magie noire.

L’analogie : votre repo est une bibliothèque. Jusqu’à maintenant vous aviez une table où vous ne pouviez avoir qu’un livre ouvert. Un worktree, c’est ajouter d’autres tables. Chacune avec un livre différent ouvert, mais toutes puisant dans la même étagère.

~/code/monapp/                    ← table 1 (main)
     .git/                        ← la bibliothèque (une seule)

~/code/monapp-sparkline/          ← table 2 (feature/sparkline)
     .git  ← fichier, pas dossier (pointeur vers la bibliothèque)

~/code/monapp-notifications/      ← table 3 (feature/notifications)
     .git  ← autre pointeur

Chaque répertoire est un checkout complet avec tous les fichiers. Vous pouvez compiler dans l’un, lancer les tests dans l’autre, et avoir votre agent IA qui travaille dans le troisième. En même temps.

Le créer, c’est une ligne

Depuis votre repo principal :

git worktree add ../monapp-sparkline -b feature/sparkline
git worktree add ../monapp-notifications -b feature/notifications

C’est tout. Deux nouveaux répertoires, chacun sur sa branche, partageant toute la base de données git. Pas de clonage, pas de configuration de remotes, pas de duplication d’historique.

Ce qu’ils partagent et ce qu’ils ne partagent pas

C’est important. Les worktrees partagent tout le repo : commits, branches, tags, remotes, hooks, configuration. Si vous faites un commit dans le worktree du sparkline, vous pouvez le voir immédiatement depuis celui des notifications sans faire fetch ni rien, parce que c’est la même base de données.

Ce qu’ils ne partagent pas :

  • Les fichiers sur disque (chaque table a sa copie de travail)
  • La staging area (chacun a son propre git add)
  • Le HEAD (chacun pointe vers sa branche)

En termes plus simples : l’état de “sur quoi je travaille” est privé à chaque worktree. Tout le reste est commun.

Le workflow avec les coding agents

C’est là que ça devient intéressant. Avec les worktrees, vous pouvez avoir littéralement plusieurs agents qui travaillent en parallèle sur le même projet :

# Terminal 1 : Claude Code sur sparkline
cd ~/code/monapp-sparkline
claude

# Terminal 2 : Claude Code sur notifications
cd ~/code/monapp-notifications
claude

# Terminal 3 : main intact, l'app qui tourne
cd ~/code/monapp
make run

Chaque instance de Claude a son propre répertoire, sa propre branche, son propre .build/. Ils ne se marchent pas dessus. Ils ne se disputent pas l’index. Ils n’ont pas besoin de faire stash de quoi que ce soit.

Et comme ils partagent la base de données git, quand l’un des agents termine et fait push, les autres voient déjà cette branche.

Merger : exactement pareil qu’avant

Les worktrees ne changent rien au flux de merge. Ce sont des branches normales dans des répertoires séparés :

# Option A : merge local
cd ~/code/monapp
git merge feature/sparkline
git merge feature/notifications

# Option B : PRs (l'habituel)
cd ~/code/monapp-sparkline
git push -u origin feature/sparkline
# Créer PR sur GitHub/Gitea, review, merge

Quand vous avez terminé, vous nettoyez :

git worktree remove ../monapp-sparkline
git branch -d feature/sparkline  # si déjà mergé

Les pitfalls que personne ne vous dit

1. Une branche, un worktree

Vous ne pouvez pas avoir main checkée dans deux worktrees en même temps. C’est par design : ça évite que deux répertoires modifient le même HEAD et se corrompent. Si vous avez besoin d’un deuxième checkout de main, créez une branche temporaire.

2. Le premier build part de zéro

Chaque worktree a son propre répertoire de build. La première compilation va être lente. Après, chaque worktree maintient son cache indépendant, ce qui est précisément l’avantage par rapport au git checkout classique (qui vous invalide le cache chaque fois que vous changez de branche).

3. Fichiers locaux non trackés

Votre .env.local, configurations d’éditeur, fichiers qui ne sont pas dans git… ne se copient pas dans le nouveau worktree. Il faudra les recréer ou faire des symlinks.

4. Apps avec état partagé sur disque

Si votre app écrit des données dans ~/Library/Application Support/ ou similaire, deux instances de l’app depuis différents worktrees vont se disputer le même fichier. Ce n’est pas un problème du worktree, c’est un problème de faire tourner deux instances de la même app. La solution : ne pas en faire tourner deux en même temps, ou paramétrer le répertoire de données par build.

5. Ne supprimez pas le répertoire à la main

Si vous faites rm -rf du worktree au lieu d’utiliser git worktree remove, git continue de penser que la branche est occupée. Exécutez git worktree prune pour nettoyer les références orphelines.

6. Le remote ne sait rien

Les worktrees sont 100% locaux. Gitea, GitHub, GitLab… aucun remote ne sait qu’ils existent. Ils ne voient que des git push normaux avec des branches normales. C’est comme demander si votre serveur a des problèmes avec le fait que vous utilisiez Vim ou VS Code : il ne le sait pas, ça ne l’affecte pas.

Bonnes pratiques

Convention de nommage : mettez les worktrees comme frères du repo original, avec un suffixe descriptif :

~/code/monapp/                    ← main
~/code/monapp-sparkline/          ← feature
~/code/monapp-notifications/      ← feature
~/code/monapp-hotfix-login/       ← hotfix

Ainsi un ls ~/code/monapp* vous montre tout d’un coup d’œil.

Un worktree par feature, pas par caprice : créez des worktrees pour du travail qui va vraiment être en parallèle. Si vous allez faire une chose après l’autre, une branche normale avec checkout suffit.

Nettoyez quand vous terminez : les worktrees abandonnés sont comme les branches que personne ne supprime — ils s’accumulent et créent de la confusion. git worktree list est votre ami.

N’éditez pas le même fichier depuis deux worktrees : techniquement vous pouvez, chacun a sa copie. Mais si les deux modifient le même fichier, vous aurez des conflits au merge. Essayez que les features touchent des zones distinctes du code.

Proposition de workflow complète

Pour ceux qui veulent un flux de travail ordonné, voici celui que j’utilise :

# 1. Créer worktrees pour les features du sprint
cd ~/code/monapp
git worktree add ../monapp-feat-a -b feature/feat-a
git worktree add ../monapp-feat-b -b feature/feat-b

# 2. Lancer un agent dans chacun
cd ~/code/monapp-feat-a && claude    # terminal 1
cd ~/code/monapp-feat-b && claude    # terminal 2

# 3. Merger au fur et à mesure qu'ils terminent
cd ~/code/monapp-feat-a
git push -u origin feature/feat-a   # créer PR

# 4. Nettoyer ce qui a déjà été mergé
git worktree remove ../monapp-feat-a
git branch -d feature/feat-a

# 5. Voir ce qui reste vivant
git worktree list

Le cycle est : créer → travailler en parallèle → push/PR → merge → nettoyer. Chaque worktree vit ce que vit la feature, ni plus ni moins.

Pour conclure

Les worktrees sont dans git depuis la version 2.5 (juillet 2015). Plus de dix ans. Et la plupart des gens continuent de faire git stash comme si on était en 2010.

Avec l’arrivée des coding agents, le goulot d’étranglement n’est plus la vitesse à laquelle vous écrivez du code — c’est la vitesse à laquelle vous pouvez changer de contexte. Et les worktrees éliminent complètement ce changement de contexte : vous ne changez pas de branche, vous changez de répertoire. cd au lieu de checkout.

Ce qui est, au final, ce qu’on aurait toujours dû faire.


TL;DR : git worktree add ../nom -b branche crée un deuxième répertoire de travail sur le même repo. Sans copies, sans stash, sans invalider les caches. Parfait pour avoir plusieurs coding agents qui travaillent en parallèle. Nettoyez avec git worktree remove quand vous terminez.

Cet article a été rédigé en espagnol et traduit avec l’aide de l’IA.