Git Worktrees
Ever wanted to have multiple branches checked out in git?
Since July 2015 (https://github.com/blog/2042-git-2-5-including-multiple-worktrees-and-triangular-workflows), git worktrees was introduced to solve this problem. Let me show you how to use this with some examples. I will create a git repo called "foo":
$ git init ~/foo
When I do this, my git repo is now located at ~/foo/.git
If I view what's under the .git folder, I have the following files:
- HEAD
- config
- description
And the following folders:
- branches
- hooks
- info
- objects
- refs
I will add one file to master and commit it:
$ touch a.txt; git add a.txt; git commit -m "First checkin"
OK, now let's create a branch named "dev":
$ git branch dev
Now, let's create a folder ~/foo/worktrees
called "worktrees" and switch to it (the name of this folder doesn't matter)
$ mkdir worktrees; cd worktrees
From here, we now run the following git command:
$ git worktree add dev-branch dev
After this, you'll get some output like the following:
The git worktree takes the following form:
git worktree add [name-of-our-worktree] [branch-name]
You'll see a new directory appear named "dev-branch". If you nagivate inside, you are now in the "dev" working directory! But you can back out, and be in the "master" working directory. So in git, we refer to the working directories created by git worktree as linked working trees. This is distinquished from our main working tree which in this case is master.
What happens if you try to create a linked working tree for master? Note that our main working tree is master. Well, we can run:
$ git worktree add master master
We get the following output:
$ fatal: 'master' is already checked out at '~/foo'
Git doesn't allow us to have two working directories that would be the same. However, if you added the -f flag, you can force git to do this anyway. I'm not aware of a use case where you would want to do this.
OK, another thing to notice, is that there is a file in our linked working tree named ".git". What is this file? If we look inside, we find:
$gitdir: ~/foo/.git/worktrees/dev-branch
If we now look back in our ~/foo/.git
, we find a new folder called "worktrees". Insider this folder, there is a folder for each linked working tree. If we look inside the "dev" folder, we see the following files:
- HEAD
- ORIG_HEAD
- gitdir
- commondir
- index
and folders:
- logs
If we look at contents of commondir, it is "../..". It's relative path, and this relative path is relative to GIT_DIR, which in this case is ~/foo/.git/worktrees/dev-branch
. Thus, GIT_COMMON_DIR points to ~/foo/.git
Viewing Worktrees¶
At any point, if you want to list all working trees (including the main working tree), run:
$ git worktree list
This yields (given our current setup):
~/foo/.git (bare)
~/foo/worktrees/dev-branch 9aaccf4 [dev]
Note the main working directory is included in this list
Deleting Worktrees¶
To delete a linked working tree, simply delete the folder. When you do this, you'll notice that in the main git directory, the worktree information is still there. If you want to clean this up, run:
git worktree prune
Else, git will clean it up automatically based on the value set in your git config for gc.worktreePruneExpire
Moving Worktrees¶
What happens if you move your working directory? Let's do this:
$ mv dev-branch dev-branch-move
Now, if we run git worktree list
it still reports ~/foo/worktrees/dev-branch
as the path
To update, I modified the following items:
~/foo/worktrees/dev-branch-move/.git
~/foo/.git/worktrees/dev-branch --> ~/foo/.git/worktrees/dev-branch-move
~/foo/.git/worktrees/dev-branch-move/gitdir
Also, I suppose you would need to update ~/foo/.git/worktrees/dev-branch-move/gitdir
if you moved the linked directory tree to a different directory
What's next?¶
In https://git-scm.com/docs/git-worktree, it is addressed that remove
and mv
commands would be good for git worktree
, and I agree. Right now, it's a set of manual steps.