ARTICLES
git worktree - One repo, multiple folders
By Valentin Bremond
A not so interesting yet recurring problem
Did you ever end up in a situation where you have to fix a bug on master but you are currently developing a new feature
and you have to stash everything to change branches; but you have files not yet tracked and you don’t want to track them
yet because you’d prefer to commit them later (you are one of the people who do clean commits, bravo), all your dev and
debug environment is running on your current branch and your IDE is also configured for your current branch (and you’d
prefer everything not to mess up as soon as the code will change)?
Or did you ever start tests / builds which take a long time and you realize halfway that you need to checkout another branch to fix something, but you can’t otherwise your tests / builds will miserably fail?
Oh, you solved this with another git clone in another folder. You too. You know it’s ugly, but it works.
Introducing: worktrees
Let’s say you have a feat/new-users branch:
1$ cd /home/val/Projects/myrepo # this is my project's repository
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à. You have 2 folders with each the full source code for the selected branch, but you only have the full Git history
once (the .git folder in feat-new-users/ is actually a file which makes Git point to the .git/ folder in
myrepo/).
The syntax is simple:
1$ git worktree add <path> <branch>pathbeing where you want your worktree to be (relative paths are accepted)branchbeing the branch you want to checkout in this new worktree- without
branch, Git creates a new branch with the same name as the worktree - with
-bbefore the branch, Git creates a new branch with the given name
- without
To delete your worktree:
1$ cd /home/val/Projects/
2$ rm -rf feat-new-users/
3$ cd myrepo/
4$ git worktree prune -vGood practice: a master folder and folders for branches
A “good” practice (at least, a practical practice) is not to clone your code in myrepo/ but in a subfolder named
master in which you always stay on master. It allows you to always be able to access master for emergencies where
you have to fix a critical bug 10 minutes ago.
Then you create worktrees for your long-lived branches (features branches for example).
For small and short-lived branches, I like to have a generic folder which has no appointed branch and in which I work
when I want to make a small change.
Example:
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/is my initial clone, onmaster(note the.git/folder)myrepo/generic/is a worktree, on any branch, depending on the moment’s needmyrepo/feat-new-users/is also a worktree, onfeat/new-users, a feature branch on which I have been working for some weeks
Why?
Advantages (compared to a standard clone):
- only one Git history:
- less disk space used
- a
fetchin any of the worktrees updates remote for all worktrees => no need topullin all clones
- creating a new worktree takes seconds if not less, whereas a clone of a big repo would take minutes
- you can’t have the same branch in 2 different worktrees (which could lead to confusion if you would code a little bit in a clone and also code a little bit in another clone without paying too much attention)
- avoids long branch checkouts for some big repos
Disadvantages:
- you have to learn one command
- when you want to delete a worktree, you have to, in addition to deleting the folder, run
git worktree pruneif you’re in a hurry (Git will end up detecting this and clean by itself, but meanwhile it won’t allow the deletion of the branch which was checked out in the worktreee - you’ll see, it will happen to you someday)
Anyway, make worktrees.