Aller au contenu
Développement medium

Git worktree : plusieurs branches en même temps

15 min de lecture

git worktree attache plusieurs répertoires de travail à un même dépôt. Chacun est positionné sur sa propre branche, dans son propre dossier, et tous partagent le même historique. Vous traitez une urgence sur hotfix/timeout-api pendant que votre travail en cours reste intact sur main, sans stash et sans second clone. Ce guide montre comment créer un worktree, ce qu'il contient réellement, pourquoi Git refuse la même branche deux fois, et ce que deux worktrees ne partagent pas, qui est la source de la plupart des mauvaises surprises.

Prérequis : Les branches en bref et Enregistrer des modifications.

  • Créer un second répertoire de travail avec git worktree add
  • Distinguer ce que les worktrees partagent de ce qu'ils dupliquent
  • Diagnostiquer les deux refus les plus fréquents de Git
  • Supprimer, déplacer et réparer un worktree proprement
  • Choisir entre un worktree, un git stash et un second clone

Un worktree, ou répertoire de travail, est le dossier dans lequel vous voyez et modifiez vos fichiers. Par défaut, un dépôt en possède exactement un, créé par git init ou git clone. Changer de branche y transforme les fichiers sur place, ce qui explique pourquoi Git refuse de basculer quand vous avez des modifications en cours.

git worktree lève cette contrainte. La commande crée un worktree lié, un second dossier rattaché au même dépôt, positionné sur une autre branche. Les deux dossiers partagent l'historique, les branches, les tags et les remotes, mais possèdent chacun leur HEAD, leur index et leurs fichiers. Aucun git push ni git fetch n'est nécessaire entre eux : un commit créé dans l'un est immédiatement visible depuis l'autre, puisqu'il n'y a qu'un seul dépôt.

Les trois répondent au même besoin de départ, travailler ailleurs sans perdre l'état courant, mais avec des coûts très différents.

ApprocheCe qu'elle coûteQuand la préférer
git stashMet le travail en pile, le dossier revient à un état propreInterruption courte, quelques minutes, sur la même base de dépendances
Second cloneDuplique l'historique complet, exige push/fetch pour échangerMachine différente, ou besoin d'un dépôt réellement indépendant
git worktreeUn dossier de plus, historique partagé, commits visibles des deux côtésTravail parallèle prolongé, ou branches aux dépendances incompatibles

Le cas qui tranche vraiment en faveur du worktree est celui des dépendances incompatibles. Migrer un projet vers une version majeure de framework change tout le contenu de node_modules. Avec un seul dossier, chaque aller-retour entre la branche de production et la branche de migration impose une réinstallation complète et une purge des caches. Avec deux worktrees, les deux environnements coexistent, chacun installé une fois, et vous passez de l'un à l'autre par un simple cd.

Comment créer un worktree pour un correctif urgent ?

Section intitulée « Comment créer un worktree pour un correctif urgent ? »

Le scénario est celui d'un dépôt api-meteo où une modification est en cours, non committable en l'état, quand un correctif urgent devient prioritaire.

  1. Constater le travail en cours : le dossier principal n'est pas propre.

    Fenêtre de terminal
    git status --short
    M api.py
  2. Créer le worktree avec sa branche, en une commande. L'option -b crée la branche, le dernier argument est le chemin du nouveau dossier, ici un dossier voisin.

    Fenêtre de terminal
    git worktree add -b hotfix/timeout-api ../api-meteo-hotfix
    Preparing worktree (new branch 'hotfix/timeout-api')
    HEAD is now at 04de30c feat: premiere version de l'api meteo
  3. Vérifier la liste des répertoires de travail attachés au dépôt. Le principal apparaît toujours en premier.

    Fenêtre de terminal
    git worktree list
    /home/dev/projets/api-meteo 04de30c [main]
    /home/dev/projets/api-meteo-hotfix 04de30c [hotfix/timeout-api]
  4. Constater que le travail en cours est intact dans le dossier principal : rien n'a été déplacé ni mis en pile.

    Fenêtre de terminal
    git status --short
    M api.py
  5. Corriger et committer depuis le nouveau dossier, comme dans n'importe quel dépôt.

    Fenêtre de terminal
    cd ../api-meteo-hotfix
    git commit -am "fix: augmente le timeout de l'api"
  6. Retrouver le commit depuis le dossier principal, sans aucune synchronisation. Le dépôt est commun.

    Fenêtre de terminal
    cd ../api-meteo
    git log --oneline hotfix/timeout-api -1
    4bbf040 fix: augmente le timeout de l'api

Sans -b, git worktree add ../api-meteo-hotfix crée automatiquement une branche portant le nom du dernier segment du chemin, ici api-meteo-hotfix. Nommer explicitement la branche avec -b évite ces branches involontaires.

Un worktree lié ne contient pas de dossier .git, mais un fichier .git de quelques dizaines d'octets. C'est la différence la plus visible avec un clone, et elle explique le coût quasi nul de l'opération.

Fenêtre de terminal
ls -la ../api-meteo-hotfix/.git
cat ../api-meteo-hotfix/.git
-rw-rw-r-- 1 dev dev 154 juil. 28 13:42 ../api-meteo-hotfix/.git
gitdir: /home/dev/projets/api-meteo/.git/worktrees/api-meteo-hotfix

Ce fichier est un simple pointeur vers un sous-dossier de métadonnées créé dans le dépôt principal. C'est là que vivent le HEAD et l'index propres à ce worktree, pendant que les objets, les branches et les tags restent partagés.

  • Répertoireapi-meteo/
    • Répertoire.git/
      • Répertoireworktrees/
        • Répertoireapi-meteo-hotfix/
          • HEAD
          • index
          • gitdir
          • commondir
    • api.py
  • Répertoireapi-meteo-hotfix/
    • .git
    • api.py

Conséquence pratique : l'historique n'est jamais dupliqué. Sur un dépôt dont le dossier .git pèse plusieurs centaines de mégaoctets, un worktree supplémentaire ne coûte que la taille des fichiers réellement présents dans la branche, là où un second clone recopierait tout.

Pourquoi Git refuse la même branche dans deux worktrees ?

Section intitulée « Pourquoi Git refuse la même branche dans deux worktrees ? »

Une branche ne peut être active que dans un seul worktree à la fois. Tenter d'ouvrir un second dossier sur une branche déjà utilisée échoue immédiatement.

Fenêtre de terminal
git worktree add ../api-meteo-copie main
Preparing worktree (checking out 'main')
fatal: 'main' is already used by worktree at '/home/dev/projets/api-meteo'

Ce refus est une protection, pas une limitation arbitraire. Deux dossiers positionnés sur la même branche pourraient committer chacun de leur côté et faire diverger silencieusement le même pointeur. Le message indique le chemin exact du worktree fautif, ce qui suffit en général à comprendre la situation.

Depuis n'importe quel worktree, git branch -v marque d'un + les branches occupées par un autre répertoire de travail, en plus de l'astérisque habituel pour la branche courante.

Fenêtre de terminal
git branch -v
+ hotfix/timeout-api 4bbf040 fix: augmente le timeout de l'api
* main 04de30c feat: premiere version de l'api meteo

Si vous avez réellement besoin de la même branche deux fois, --force passe outre, mais c'est un aveu d'organisation bancale : préférez une branche par worktree.

Comment supprimer, déplacer et réparer un worktree ?

Section intitulée « Comment supprimer, déplacer et réparer un worktree ? »

git worktree remove efface le dossier et ses métadonnées. La commande refuse de détruire du travail non committé.

Fenêtre de terminal
git worktree remove ../api-meteo-hotfix
fatal: '../api-meteo-hotfix' contains modified or untracked files, use --force to delete it

Après un --force assumé, ou une suppression sur un dossier propre, la branche survit : seul le répertoire de travail disparaît, le travail committé reste dans le dépôt.

Fenêtre de terminal
git worktree remove --force ../api-meteo-hotfix
git branch -v
hotfix/timeout-api 4bbf040 fix: augmente le timeout de l'api
* main 04de30c feat: premiere version de l'api meteo

Supprimer le dossier avec rm -rf sans prévenir Git laisse une entrée obsolète. Elle apparaît alors annotée prunable dans la liste.

Fenêtre de terminal
git worktree list
/home/dev/projets/api-meteo 04de30c [main]
/home/dev/projets/api-meteo-audit 04de30c (detached HEAD) prunable

git worktree prune fait le ménage, avec un mode simulation qui explique ce qu'il retirerait.

Fenêtre de terminal
git worktree prune --dry-run --verbose
Removing worktrees/api-meteo-audit: gitdir file points to non-existent location

Déplacer, et réparer après un déplacement manuel

Section intitulée « Déplacer, et réparer après un déplacement manuel »

git worktree move déplace un worktree en mettant à jour les métadonnées. Un mv fait à la main casse le lien : le dossier continue de fonctionner, mais le dépôt principal ne sait plus où il est et le marque prunable, ce qui l'expose à être purgé au prochain prune. La réparation tient en une commande, lancée depuis le dépôt principal avec le nouveau chemin en argument.

Fenêtre de terminal
git worktree repair ../api-meteo-cache-final
repair: gitdir incorrect: /home/dev/projets/api-meteo/.git/worktrees/api-meteo-cache/gitdir

Un worktree stocké sur un disque amovible ou un montage réseau disparaît quand le support est détaché, et Git le considère alors comme purgeable. git worktree lock l'en protège, avec une raison consultable.

Fenêtre de terminal
git worktree lock --reason "disque externe" ../api-meteo-cache-final
git worktree remove ../api-meteo-cache-final
fatal: cannot remove a locked working tree, lock reason: disque externe
use 'remove -f -f' to override or unlock first

C'est ici que se logent les mauvaises surprises. Git partage tout ce qui vit dans le dépôt, et rien de ce qui vit dans le répertoire de travail. Or l'essentiel d'un environnement de développement moderne est justement dans le répertoire de travail, et souvent ignoré par Git.

ÉlémentPartagéConséquence concrète
Historique, branches, tags, remotesOuiUn commit est visible des deux côtés, sans push
StashOuiLa pile de stash est commune au dépôt
Hooks (.git/hooks/)OuiAucun hook par worktree, ils s'appliquent partout
node_modules, venv, vendorNonRéinstallation complète dans chaque nouveau worktree
Fichiers non versionnés (.env)NonAbsents du nouveau dossier, à recopier à la main
Caches de buildNonPremière compilation à froid dans chaque worktree

Les fichiers non versionnés sont le piège le plus courant. Un .env exclu par le .gitignore n'existe pas dans le nouveau worktree, et l'application y échoue sur une variable manquante, sans rapport apparent avec la manipulation Git qui vient d'être faite. Le coût disque vient juste après : un dossier de dépendances de plusieurs centaines de mégaoctets est payé autant de fois qu'il y a de worktrees.

Les hooks, à l'inverse, surprennent parce qu'ils sont partagés. Comme ils vivent dans .git/hooks/, un hook de pre-commit s'applique dans tous les worktrees, sans possibilité native d'en définir un par dossier.

  • Une branche, un worktree : ne forcez pas le partage d'une branche, la contrainte de Git protège de la divergence silencieuse.
  • Nommez la branche avec -b plutôt que de laisser Git la déduire du nom du dossier.
  • Placez les worktrees hors du dépôt principal, dans un dossier voisin (../projet-hotfix) et non à l'intérieur, sinon les fichiers du worktree apparaissent comme non suivis dans le dossier parent.
  • Copiez les fichiers d'environnement dès la création du worktree, c'est l'oubli le plus fréquent.
  • Préférez git worktree move à mv, et gardez git worktree repair en réserve quand le déplacement manuel a déjà eu lieu.
  • Supprimez avec git worktree remove, pas avec rm -rf, pour éviter les entrées obsolètes.
  • Méfiez-vous des commandes destructrices lancées depuis le mauvais dossier : deux répertoires quasi identiques invitent à la confusion. Un script de déploiement qui travaille sur le dossier courant doit vérifier où il tourne.
SymptômeCauseSolution
fatal: 'main' is already used by worktree at ...La branche est active dans un autre worktreeUtiliser une autre branche, ou fermer l'autre worktree
fatal: ... contains modified or untracked filesLe worktree n'est pas propreCommitter, ou assumer git worktree remove --force
Entrée annotée prunable dans git worktree listDossier supprimé ou déplacé à la maingit worktree prune si supprimé, git worktree repair avec le nouveau chemin si déplacé
fatal: cannot remove a locked working treeLe worktree est verrouillégit worktree unlock ../api-meteo-cache-final puis relancer la suppression
L'application échoue sur une variable d'environnementLes fichiers non versionnés n'ont pas suiviRecopier .env et réinstaller les dépendances
Une branche a disparu de git switchElle est occupée par un autre worktreegit branch -v et repérer la marque +
  • Un worktree est un répertoire de travail supplémentaire attaché au même dépôt, pas une copie du dépôt.
  • Le .git d'un worktree lié est un fichier pointeur, pas un dossier : l'historique n'est jamais dupliqué.
  • Une branche ne peut être active que dans un seul worktree, et git branch -v marque d'un + celles qui sont occupées ailleurs.
  • Un commit fait dans un worktree est immédiatement visible depuis les autres, sans push ni fetch.
  • Supprimer un worktree ne supprime pas sa branche, le travail committé reste dans le dépôt.
  • Ce qui n'est pas versionné n'est pas partagé : dépendances, .env et caches sont à refaire dans chaque worktree.
  • Les hooks sont partagés puisqu'ils vivent dans le dépôt commun.
  • git worktree repair demande Git 2.30, l'option --orphan demande Git 2.42.

Cinq questions qui reviennent quand on découvre les worktrees, à commencer par celle qui décide de l'adoption : la différence réelle avec un second clone. Les réponses reprennent en format court les points du guide sur le partage de l'historique, la contrainte d'une branche par worktree et le nettoyage.

  • Git stash et git clean : l'alternative pour une interruption courte, quand créer un dossier serait disproportionné.
  • HEAD détaché : comprendre l'état dans lequel se trouve un worktree créé avec --detach.
  • Submodules : la combinaison la plus délicate avec les worktrees.
  • Gestion des branches : nommer, lister et nettoyer les branches que vos worktrees occupent.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn