New week, new tricky problem! Who has never needed to test two features offered by two different branches, at the same time or almost … Apart from cloning  the project twice, running its tests and making any corrections that you forget to push to the server at one time or else which will give rise to confusion between the branches … All in all, bad solution! And all this for what ? Because by default, git only offers one workspace, regardless of how many branches there are in the repository. It makes the thing quite flexible but suddenly in our case, there is enough to pull out some hair.

And there you come across a command that was in a corner of the official doc: git worktree! And this is a revelation!

 

Create a new worktree

Let’s take an example of a simple project with the following branches:

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

I will be working on feature/1 and feature/2 branches simultaneously. The idea here is to have a work area for each of these 2 branches. I start by checkouting to the feature/1 branch for example. The contents of the current directory corresponding to the updated work area for this branch precisely.

 

[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

 

We will now create the worktree dedicated to the feature/2 branch using the following command:

 

git worktree add <directory> <branch>

The command will create a worktree in the <directory> directory  outside the repository for the <branch> branch.

 

[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

The contents of the directory thus created correspond to the updated worktree for feature/2. We therefore have 2 distinct worktrees in two different directories: web-training for the feature/1 branch (repository directory) and ../work-feature2 for the feature/2 branch.

In passing, we will notice the presence of a .git file which contains the directory path allowing to manage the metadata of this new work area, in the local web-training repository.

 

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

You can now work in this new worktree without fear of losing anything. Anything committed there will be part of feature/2 history only.

 

[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

You can also create a new branch AND an associated worktree.

 

git worktree add -b <new_branch> <directory> [SHA1|tag|branch]

 

List existing worktrees

 

You can check at anytime all the existing worktrees and list it:

 

git worktree list

And here is the result! No way to be wrong here!

For the plumbing, this happens in .git, in a worktree sub-directory:

 

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

Delete a worktree

Again the commands are simple. To remove a worktree that you no longer need (and thus avoid mistakes), use the remove option from the initial repository:

git worktree remove [-f] <directory>

The command deletes the directory of the designated worktree and the metadata associated with it. What if you forgot to commit your changes?

[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 is nice, it warns you and denies the deletion, unless you use the -f option. And as we like to keep trees “clean”, if you delete like a wild the directory of the worktree, you can clean all non needed metadata with the command 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 right? Come on let’s sum up!

    Create a new worktree from an existing branch

    git worktree add <directory> <branch>

    Create a new branch and its worktree

    git worktree add -b <new_branch> <directory> <SHA1|tag|branch>

    List existing worktrees

    git worktree list

    Delete a worktre

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

    Clean worktrees metadata

    git worktree prune