ARTICLES
git worktree - Un seul repo, plusieurs dossiers
By Valentin Bremond
Un problème pas très intéressant mais récurrent
Vous êtes-vous déjà retrouvés dans une situation où vous devez fixer un bug sur master mais vous êtes en plein dev sur
une feature et vous devez tout stasher pour changer de branche ; sauf que vous avez des fichiers pas encore trackés et
que vous voulez éviter de les tracker pour le moment parce que vous préféreriez les commiter plus tard (vous faites
partie des gens qui font des commits propres, bravo), tout votre environnement de dev et de debug tourne sur votre
branche courante et votre IDE est également configuré pour votre branche courante (et vous voudriez éviter que tout parte
en cacahuète lorsque le code va changer) ?
Ou bien avez-vous déjà lancé des tests / un build qui dure un bon moment et vous vous rendez compte au beau milieu que vous avez besoin de checkout une autre branche pour fixer quelque chose, mais que vous ne pouvez pas sinon vos tests / votre build se vautre lamentablement ?
Ah, vous avez résolu ça avec un second git clone dans un autre dossier. Vous aussi. Vous savez que c’est moche, mais
ça marche.
Découvrez : les worktrees
Mettons que vous ayiez une branche feat/new-users :
1$ cd /home/val/Projects/myrepo # le repository de mon projet
2$ git worktree add ../feat-new-users feat/new-users
3$ cd ..
4$ tree -aFL 2 --noreport
5.
6├── feat-new-users/
7│ ├── back/
8│ ├── common.mk
9│ ├── front/
10│ ├── .git
11│ ├── .gitignore
12│ ├── infra/
13│ └── Jenkinsfile
14└── myrepo/
15 ├── back/
16 ├── common.mk
17 ├── front/
18 ├── .git/
19 ├── .gitignore
20 ├── infra/
21 └── JenkinsfileVoilà. Vous avez 2 dossiers avec chacun l’intégralité du code de la branche choisie, mais vous n’avez qu’une seule fois
tout l’historique git (le dossier .git dans feat-new-users/ est en réalité un fichier qui fait pointer Git sur le
dossier .git/ dans myrepo/).
La syntaxe est simple :
1$ git worktree add <path> <branch>pathétant là où vous voulez stocker votre worktree (chemins relatifs acceptés)branchétant la branche que vous voulez checkout dans votre nouveau worktree- sans
branch, Git créé une nouvelle branche du nom du worktree - avec
-bdevant la branche, Git créé une nouvelle branche avec le nom donné
- sans
Pour supprimer votre worktree :
1$ cd /home/val/Projects/
2$ rm -rf feat-new-users/
3$ cd myrepo/
4$ git worktree prune -vBonne pratique : un dossier master et des dossiers pour les branches
Une “bonne” pratique (du moins, une pratique pratique) c’est de ne pas cloner votre code dans myrepo/ mais dans un
sous dossier nommé master, sur lequel vous restez toujours sur master. Ça vous permet d’avoir toujours accès à
master pour les cas urgents où il faut fixer un bug critique y’a 10 minutes.
Ensuite, vous créez des worktrees pour vos branches qui vivent longtemps (des branches de feature par exemple).
Pour les petites branches qui vivent quelques jours, j’aime avoir un dossier generic qui n’a pas de branche attitrée
et sur lequel je vais quand je veux faire un changement rapide.
Exemple :
1$ cd /home/val/Projects/myrepo
2$ tree -aFL 2 --noreport
3.
4├── feat-new-users
5│ ├── back
6│ ├── common.mk
7│ ├── front
8│ ├── .git
9│ ├── .gitignore
10│ ├── infra
11│ └── Jenkinsfile
12├── generic
13│ ├── back
14│ ├── common.mk
15│ ├── front
16│ ├── .git
17│ ├── .gitignore
18│ ├── infra
19│ └── Jenkinsfile
20└── master
21 ├── back
22 ├── common.mk
23 ├── front
24 ├── .git/
25 ├── .gitignore
26 ├── infra
27 └── Jenkinsfilemyrepo/master/est mon clone initial, surmaster(notez le dossier.git/)myrepo/generic/est un worktree, sur n’importe quelle branche, selon le besoin du momentmyrepo/feat-new-users/est aussi un worktree, surfeat/new-users, une feature branch sur laquelle je travaille depuis plusieurs semaines
Pourquoi ?
Avantages (par rapport à un clone classique) :
- un seul historique Git :
- moins d’espace disque utilisé
- un
fetchsur n’importe lequel des worktree met à jour remote pour tous les worktrees => pas besoin depulldans tous les clones
- la création d’un nouveau worktree prend quelques secondes tout au plus, contrairement à plusieurs minutes pour un clone d’un gros repo
- pas possible d’être sur la même branche dans 2 worktrees différents (ce qui pourrait porter à confusion si vous faites un peu de dev d’un côté et un peu de dev de l’autre sans faire attention)
- évite les temps de changement de branche très longs sur certains repos très gros
Inconvénients :
- il faut apprendre une commande
- lorsque vous voulez supprimer un worktree, il faut, en plus de supprimer le dossier, lancer
git wotktree prunesi vous êtes pressé (sinon Git finira par le détecter et faire le ménage tout seul, mais pendant ce temps il refusera de supprimer la branche qui était checkout dans le worktree - vous verrez, ça vous arrivera un jour)
Bref, faites des worktrees.