Ben Sarrazin
Posted on March 1, 2023
Overview
The git worktree command allows you to use and/or manage multiple work trees at the same time.
So what's a work tree? You're already using one, you just might not know it. Or you might call it "working copy".
When you clone a repository the classic way (or create a new repository using git init
), git will create what is called the "main work tree":
- it clones the "bare" repository in the
.git
folder - it creates the main work tree one level above the bare repository; what you might already know as simply "the folder in which the repository was cloned"
For example:
$ git clone git@github.com:bsrz/mvvm.git
Cloning into 'mvvm'...
remote: Enumerating objects: 131, done.
remote: Counting objects: 100% (131/131), done.
remote: Compressing objects: 100% (79/79), done.
remote: Total 131 (delta 56), reused 109 (delta 38), pack-reused 0
Receiving objects: 100% (131/131), 474.84 KiB | 2.53 MiB/s, done.
Resolving deltas: 100% (56/56), done.
$ cd mvvm
$ ls -la
total 32
drwxr-xr-x 11 bsrz staff 352 Feb 28 23:30 ./
drwxr-xr-x 25 bsrz staff 800 Feb 28 23:30 ../
drwxr-xr-x 12 bsrz staff 384 Feb 28 23:31 .git/
-rw-r--r-- 1 bsrz staff 2171 Feb 28 23:30 .gitignore
drwxr-xr-x 4 bsrz staff 128 Feb 28 23:30 .img/
-rw-r--r-- 1 bsrz staff 1069 Feb 28 23:30 LICENSE
drwxr-xr-x 5 bsrz staff 160 Feb 28 23:30 MVVM/
drwxr-xr-x 5 bsrz staff 160 Feb 28 23:30 MVVM.xcodeproj/
drwxr-xr-x 4 bsrz staff 128 Feb 28 23:30 MVVMTests/
drwxr-xr-x 4 bsrz staff 128 Feb 28 23:30 MVVMUITests/
-rw-r--r-- 1 bsrz staff 22913 Feb 28 23:30 README.md
You can see the .git
folder, and one level above (aka the current directory) contains all of the files committed to the repository, aka the work tree, or working copy.
Why?
Ever had a situation where you had modified files and someone (maybe your boss) asked you to look into a bug in production code? Or maybe you have a major refactoring effort in progress with hundreds (or thousands!) of modified files, but you were asked to quickly complete another task?
If so, then you'll be familiar with the Ill-just-commit-everything-I-have-in-a-WIP-commit approach or the stash management hell.
Wouldn't it be a dream to have more than one branch checked out at the same time? This is why.
Work trees
Let's try out the same example as before but using work trees:
$ mkdir mvvm # 1
$ cd mvvm # 2
$ git clone --bare git@github.com:bsrz/mvvm.git .bare # 3
Cloning into bare repository '.bare'...
remote: Enumerating objects: 131, done.
remote: Counting objects: 100% (131/131), done.
remote: Compressing objects: 100% (79/79), done.
remote: Total 131 (delta 56), reused 109 (delta 38), pack-reused 0
Receiving objects: 100% (131/131), 474.84 KiB | 2.43 MiB/s, done.
Resolving deltas: 100% (56/56), done.
- Start by creating the directory that will contain all of your branches and the bare repository
- Change the directory to the newly created one
- This is the key part here, you want to clone a bare version of the repository; this is more or less cloning only the
.git
folder that's normally done automatically by the classic clone method
Next, you'll create the main work tree. This is done by using the git worktree add
method to register a new work tree with the bare repository:
$ cd .bare # 1
$ git worktree add ../main main # 2
Preparing worktree (checking out 'main')
HEAD is now at 0db2467 <commit message>
$ cd ../main # 3
$ ls -la # 4
total 36
drwxr-xr-x 11 bsrz staff 352 Feb 28 23:53 ./
drwxr-xr-x 4 bsrz staff 128 Feb 28 23:53 ../
-rw-r--r-- 1 bsrz staff 61 Feb 28 23:53 .git
-rw-r--r-- 1 bsrz staff 2171 Feb 28 23:53 .gitignore
drwxr-xr-x 4 bsrz staff 128 Feb 28 23:53 .img/
-rw-r--r-- 1 bsrz staff 1069 Feb 28 23:53 LICENSE
drwxr-xr-x 5 bsrz staff 160 Feb 28 23:53 MVVM/
drwxr-xr-x 5 bsrz staff 160 Feb 28 23:53 MVVM.xcodeproj/
drwxr-xr-x 4 bsrz staff 128 Feb 28 23:53 MVVMTests/
drwxr-xr-x 4 bsrz staff 128 Feb 28 23:53 MVVMUITests/
-rw-r--r-- 1 bsrz staff 22913 Feb 28 23:53 README.md
- Change the directory to the bare repository
- Add the main work tree to the mvvm folder, one level above the bare repository; 🗒️ this structure is purely a personal choice, you can clone the repository anywhere you want and check out branches anywhere you want
- Change the directory to your newly created work tree
- The committed files in your repository appear in the same way as before
You can work in the main directory in the exact same way as you were before. You can checkout other branches, you can stash modified files, you can commit files, you can rebase, merge, etc...
The power of bare repositories lie in their ability to add a 2nd, a 3rd, an Nth work tree and checkout another branch inside of them.
$ cd ../.bare # 1
$ git worktree add --track ../my-awesome-branch -b my-awesome-branch # 2
Preparing worktree (new branch 'my-awesome-branch')
branch 'my-awesome-branch' set up to track 'main'.
HEAD is now at 0db2467 <commit message>
$ cd ../my-awesome-branch # 3
- Go back to the bare repository
- Add a new work tree, this time we're creating a new branch and tracking it
- Change the directory to the new work tree
Now you can make modifications to the main work tree (using the main branch) at the same time as making modifications to the my-awesome-branch work tree (using the my-awesome-branch branch). The same capabilities apply to the new work tree: you can checkout other branches, you can stash modified files, you can commit files, you can rebase, merge, etc...
The only caveat here, is that a branch can only be checked out in a single work tree at a time. If you try to checkout a branch that's already checked out in a different work tree, you will receive this error:
$ git checkout main
fatal: 'main' is already checked out at '/Users/bsrz/Developer/mvvm/main'
Conclusion
Although, I don't always use this method, I'm starting to use it more and more. The ability to leave my work in progress as is and start new work in a separate folder has given me a ton of flexibility and has caused a lot less "git management" work. I no longer have to constantly manage stashes or save patches for later, and it allows me to pivot onto a new problem pretty quickly.
Hope this helped you learn something!
Cheers! 🍻
Posted on March 1, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.