Nouvelle semaine, nouvelle colle ! Qui n’a jamais eu besoin de tester deux fonctionnalités proposées par deux branches différentes, au même moment ou presque… A part cloner 2 fois le projet en question, lancer ses tests et faire d’éventuelles corrections qu’on ne manquera pas d’oublier de remonter au serveur ou bien qui vont donner lieu à confusion entre les branches… Bref à fuir ! Et  tout ça pourquoi ? Parce que par défaut, git ne propose qu’une seule zone de travail, quel que soit le nombre de branches existantes sur le dépot. Ca rend le truc assez souple mais du coup dans notre cas, il y a de quoi s’arracher quelques cheveux.

Et là tu tombes sur une commande planquée dans un coin de la doc officielle : git worktree ! Et c’est la révélation !

Créer un nouvel espace de travail

 

Prenons l’exemple d’un projet simple avec les branches suivantes :

[ennael@zarafa web-training (master=)]$ git branch
devel
feature/1
feature/2
* master

Je vais travailler sur feature/1 et feature/2 en simultané. L’idée ici est de disposer d’une zone de travail pour chacune de ces 2 branches. Je commence par me déplacer dans la branche feature/1 par exemple. Le contenu du répertoire courant correspondant à la zone de travail mise à jour pour cette branche précisément.

 

[ennael@zarafa web-training (master=)]$ git checkout feature/1

[ennael@zarafa web-training (feature/1=)]$ ls -a
.  ..  .git  .gitlab-ci.yml  img  index.html  README.md

On va maintenant créer la zone de travail spécifique à la branche feature/2 en utilisant la commande suivante :

 

git worktree add <répertoire> <branche>

La commande va créer une zone de travail dans le répertoire <répertoire> à positionner en dehors du dépot pour la branche <branche>.

 

[ennael@zarafa web-training (feature/1=)]$ git worktree ../work-feature2 feature/2
Preparing worktree (checking out ‘feature/2’)
HEAD is now at a14e0c6 Update .gitlab-ci.yml
[ennael@zarafa web-training (feature/1=)]$ cd ../work-feature2/
[ennael@zarafa work-feature2 (feature/2)]$ ls -a
.  ..  fic1 .git  .gitlab-ci.yml  img  index.html  README.md

Le contenu du répertoire ainsi créé correspond à la zone de travail mise à jour pour feature/2. On a donc bien 2 zones de travail distinctes dans deux répertoires différents : web-training pour la branche feature/1 (répertoire du dépot) et ../work-feature2 pour la branche feature/2.

Au passage on remarquera la présence d’un fichier .git qui contient le chemin du répertoire permettant de gérer les meta-données de cette nouvelle zone de travail, dans le dépot local de web-training .

 

[ennael@zarafa work-feature2 (feature/2=)]$ cat .git
gitdir: /home/ennael/Bureau/git/lab/web-training/.git/worktrees/work-feature2

Vous pouvez maintenant travailler dans cette nouvelle zone de travail sans crainte de perdre quoique ce soit. Tout ce qui y sera committé fera partie de l’historique de feature/2 uniquement.

[ennael@zarafa work-feature2 (feature/2=)]$ touch fic2
[ennael@zarafa work-feature2 (feature/2=)]$ git add fic2
[ennael@zarafa work-feature2 (feature/2=)]$ git commit -m “Add fic2 file”
feature/2 d03dc44 Add fic2
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 fic2
[ennael@zarafa work-feature2 (feature/2=)]$ git branch –contains d03dc44
* feature/2

Vous pouvez aussi créer une nouvelle branche ET une zone de travail associée.

git worktree add -b <nouvelle_branche> <répertoire> [SHA1|tag|branche]

Lister les zones de travail existantes

Pour vérifier les zones de travail en cours vous pouvez les lister simplement :

git worktree list

Et voilà le résultat, impossible de se tromper !

Pour la plomberie ça se passe dans le dépot local du dépot, dans un sous-répertoire worktree :

[ennael@zarafa .git (feature/1=)]$ tree worktrees/
worktrees/
└── work-feature2
├── COMMIT_EDITMSG
├── commondir
├── gitdir
├── HEAD
├── index
├── logs
│   └── HEAD
└── ORIG_HEAD
 

Supprimer une zone de travail

Là encore les commandes sont simples. Pour supprimer une zone de travail dont vous n’avez plus l’utilité (et éviter ainsi des bêtises), utiliser l’option remove depuis le dépot initial :

git worktree remove [-f] <répertoire>

La commande supprime le répertoire de la zone de travail ainsi désignée et les métadonnées qui lui sont liées. Et si vous avez oublié de committer vos modifications ?

[ennael@zarafa web-training (feature/1=)]$ git worktree remove ../work-feature2/
fatal: ‘../work-feature2/’ contains modified or untracked files, use –force to delete it

Git est sympa, il vous prévient et refuse la suppression, sauf si vous utilisez l’option -f. Et comme on aime bien garder des arborescences “propres”, si vous supprimez comme un sauvage le répertoire de la dite zone de travail,vous pouvez nettoyer tout ça avec la commande git worktree prune :

[ennael@zarafa web-training (feature/1=)]$ rm -rf ../work-feature2/
[ennael@zarafa web-training (feature/1=)]$ git worktree prune
[ennael@zarafa web-training (feature/1=)]$ git worktree list
/home/ennael/Bureau/git/lab/web-training  a14e0c6

  • Cool non ? Allez on récapitule !

    Créer une nouvelle zone de travail à partir d’une branche existante

    git worktree add <répertoire> <branche>

    Créer une nouvelle branche et sa zone de travail associée

    git worktree add -b <nouvelle_branche> <répertoire> <SHA1|tag|branche>

    Lister les zones de travail existantes

    git worktree list

    Supprimer une zone de travail

    git worktree remove [-f] <répertoire>

    Nettoyer les metadonnées des zones de travail

    git worktree prune