Overview
How to create, use and remove worktrees, as an alternative to constantly stashing and popping when you need to change contexts.
DESCRIPTION
From man git-worktree:
A git repository can support multiple working trees, allowing you to check out more than one branch at a time. With git worktree add a new working tree is associated with the repository. This new working tree is called a "linked working tree" as opposed to the "main working tree" prepared by "git init" or "git clone". A repository has one main working tree (if it’s not a bare repository) and zero or more linked working trees. When you are done with a linked working tree, remove it with git worktree remove.
SYNOPSIS
Also from man git-worktree:
git worktree add [-f] [--detach] [--checkout] [--lock] [-b <new-branch>] <path> [<commit-ish>] git worktree list [--porcelain] git worktree lock [--reason <string>] <worktree> git worktree move <worktree> <new-path> git worktree prune [-n] [-v] [--expire <expire>] git worktree remove [-f] <worktree> git worktree unlock <worktree>
Links
Various online links related to worktrees:
Issues related to worktrees
Drawbacks of git stash:
- Constant stashing and unstashing to move between different working directory states.
git stashdoesn't work with unmerged paths, after a merge or rebase with conflicts.- If you work with a compiled language, stashing means you'll have to recompile everything upon unstashing.
Applications of worktrees:
- Emergency fixes.
- Having multiple released versions of the software open at a time, for maintenance.
- Testing that takes a long time that would normally tie up your working directory.
- Comparing the behaviour of different versions of the software.
Weaknesses of worktrees:
- Can't (normally) have the same branch checked out in two working trees.
- Incomplete support for submodules.
Condensed example
Create a new worktree
From within your current working tree, create a new worktree outside the working tree, with a new branch called emergency off of the current master branch:
$ git worktree add -b emergency ../temp master
Work in that worktree
cd to that new worktree, work, commit your work on the emergency branch, and return to your original working tree:
$ pushd ../temp ... hack hack hack hack hack hack hack hack hack fix ... $ git commit -a -m "commit emergency fix" $ popd
where you can see the additional branch you created in the worktree:
$ git branch emergency * master $
Remove the worktree
If you have no further use for the worktree, remove it, which has no effect on the branch that was created:
$ git worktree remove ../temp $ git branch emergency * master $
Detailed example
Initial state of the main working tree
Using the “Pro Git” book as a test repo, start with some staged and unstaged changes on the master branch:
$ git status On branch master Your branch is up to date with 'rpjday/master'. Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: README.asc Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: LICENSE.asc $
The original working tree is referred to as the “main working tree”, while subsequent worktrees are “linked working trees,” so you always have at least one worktree:
$ git worktree list /home/rpjday/ebooks/progit/progit2 dd124f7 [master] $
Creating the linked working tree
Create a working tree off of an earlier tag (2.1.100):
$ git worktree add -b emergency ../temp 2.1.100 Preparing worktree (new branch 'emergency') HEAD is now at f2d0827 Merge pull request #1145 from rpjday/topic/rpjday/maintaining $
List the working trees:
$ git worktree list /home/rpjday/ebooks/progit/progit2 dd124f7 [master] /home/rpjday/ebooks/progit/temp 90bdf0a [emergency] $
Note that nothing has changed in the current working tree:
$ git status On branch master Your branch is up to date with 'rpjday/master'. Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: README.asc Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: LICENSE.asc $
Move to new working tree
$ pushd ../temp
Check the status:
$ git status On branch emergency nothing to commit, working tree clean $
List all working trees:
$ git worktree list /home/rpjday/ebooks/progit/progit2 dd124f7 [master] /home/rpjday/ebooks/progit/temp 90bdf0a [emergency] $
Verify current branch, and current position in history:
$ git show
commit f2d082747b0a9474f9d2d08c6945482b55691e4a (HEAD -> emergency, tag: 2.1.100)
Merge: 7a13f5a 5c0663e
Author: Ben Straub <ben@straub.cc>
Date: Mon Dec 10 10:06:11 2018 -0800
Merge pull request #1145 from rpjday/topic/rpjday/maintaining
maintaining: explain how "git describe" works with lightweight tags
$
Examine the .git file in this linked working tree – this is what identifies a linked working tree:
$ cat .git gitdir: /home/rpjday/ebooks/progit/progit2/.git/worktrees/temp $
Make and commit a change in the worktree
Make a change, and stage it:
$ git diff --cached diff --git a/README.asc b/README.asc index fa40bad..9d69d12 100644 --- a/README.asc +++ b/README.asc @@ -1,3 +1,5 @@ +Change to README.asc on emergency branch in worktree + = Pro Git, Second Edition Welcome to the second edition of the Pro Git book. $
Commit:
$ git commit -m "Change README.asc in worktree" [emergency 8b31c7b] Change README.asc in worktree 1 file changed, 2 insertions(+) $
Verify:
$ git show
commit 8b31c7b18e22fddca50eb9af706b6927f2c14ddc (HEAD -> emergency)
Author: Robert P. J. Day <rpjday@crashcourse.ca>
Date: Sun Feb 24 08:36:12 2019 -0500
Change README.asc in worktree
diff --git a/README.asc b/README.asc
index fa40bad..9d69d12 100644
--- a/README.asc
+++ b/README.asc
@@ -1,3 +1,5 @@
+Change to README.asc on emergency branch in worktree
+
= Pro Git, Second Edition
Welcome to the second edition of the Pro Git book.
$
Return to main working tree
$ popd ~/ebooks/progit/progit2 $
Everything here is just where we left it:
$ git status On branch master Your branch is up to date with 'rpjday/master'. Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: README.asc Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: LICENSE.asc $
Linked working tree and emergency branch are still there:
$ git worktree list /home/rpjday/ebooks/progit/progit2 5df317d [master] /home/rpjday/ebooks/progit/temp 8b31c7b [emergency] $
$ git branch emergency * master $
What you choose to do with the work committed to the emergency branch is up to you.
Remove working tree
Once you're done with the worktree, remove it and “prune” it:
$ git worktree remove ../temp [rpjday@localhost progit2]$ git worktree list /home/rpjday/ebooks/progit/progit2 5df317d [master] $
Note that the emergency branch still exists.
$ git branch emergency * master $
Additional issues to cover
- locking and unlocking working trees
- moving working trees
- git config --worktree (man git-config)
- config var
extensions.worktreeConfig - config var
gc.worktreePruneExpire - config var
worktree.guessRemote - setting up tracking branches
- detached HEAD state
$GIT_DIR/config.worktree
This is optional and is only searched when
extensions.worktreeConfig is present in $GIT_DIR/config.