This is an old revision of the document!
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 and prune, which has no effect on the branch that was created:
$ git worktree remove ../temp $ git worktree prune $ 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
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 status On branch emergency nothing to commit, working tree clean $
$ git show
commit 90bdf0a2cb410463a949ae9279ac7e065f7b023b (HEAD -> emergency, tag: 2.1.30)
Author: Ben Straub <ben@straub.cc>
Date: Tue Jan 16 10:31:13 2018 -0800
Stahp updating bundler
diff --git a/.travis.yml b/.travis.yml
index 9d0bcb2..cffacfd 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,7 +1,6 @@
language: ruby
cache: bundler
before_install:
-- gem install bundler
- bundle install
after_success:
- script/tag_on_master
$
Examine the .git file in the linked working tree:
$ cat .git gitdir: /home/rpjday/ebooks/progit/progit2/.git/worktrees/temp $
Commit some work in the new working tree
$ git diff diff --git a/README.asc b/README.asc index d7810fd..0576243 100644 --- a/README.asc +++ b/README.asc @@ -1,4 +1,4 @@ -= Pro Git, Second Edition += Pro Git, Second Edition (rday) Welcome to the second edition of the Pro Git book. $
$ git commit -a -m "silly change" [emergency 6bf829d] silly change 1 file changed, 1 insertion(+), 1 deletion(-) $
$ git show
commit 6bf829d7e63b1184c73546aa94625849054b1ebc (HEAD -> emergency)
Author: Robert P. J. Day <rpjday@crashcourse.ca>
Date: Tue Feb 6 09:48:48 2018 -0500
silly change
diff --git a/README.asc b/README.asc
index d7810fd..0576243 100644
--- a/README.asc
+++ b/README.asc
@@ -1,4 +1,4 @@
-= Pro Git, Second Edition
+= Pro Git, Second Edition (rday)
Welcome to the second edition of the Pro Git book.
$
Return to main working tree
$ popd ~/ebooks/progit/progit2 $
Still on master branch:
$ git status On branch master Your branch is up-to-date with 'origin/master'. nothing to commit, working tree clean $
Linked working tree is still there and available:
$ git branch emergency * master $
$ git worktree list /home/rpjday/ebooks/progit/progit2 dd124f7 [master] /home/rpjday/ebooks/progit/temp 6bf829d [emergency] $
$ git show emergency
commit 6bf829d7e63b1184c73546aa94625849054b1ebc (emergency)
Author: Robert P. J. Day <rpjday@crashcourse.ca>
Date: Tue Feb 6 09:48:48 2018 -0500
silly change
diff --git a/README.asc b/README.asc
index d7810fd..0576243 100644
--- a/README.asc
+++ b/README.asc
@@ -1,4 +1,4 @@
-= Pro Git, Second Edition
+= Pro Git, Second Edition (rday)
Welcome to the second edition of the Pro Git book.
$
Remove working tree
Remove the directory itself:
$ rm -rf ../temp
Still seems to be there:
$ git worktree list /home/rpjday/ebooks/progit/progit2 dd124f7 [master] /home/rpjday/ebooks/progit/temp 6bf829d [emergency] $
We need to “prune” deleted working trees:
$ git worktree prune [rpjday@android-a172fe96dd584b41 progit2]$ git worktree list /home/rpjday/ebooks/progit/progit2 dd124f7 [master] $
But our work that was committed from that working tree is still there in the object store:
$ git show emergency
commit 6bf829d7e63b1184c73546aa94625849054b1ebc (emergency)
Author: Robert P. J. Day <rpjday@crashcourse.ca>
Date: Tue Feb 6 09:48:48 2018 -0500
silly change
diff --git a/README.asc b/README.asc
index d7810fd..0576243 100644
--- a/README.asc
+++ b/README.asc
@@ -1,4 +1,4 @@
-= Pro Git, Second Edition
+= Pro Git, Second Edition (rday)
Welcome to the second edition of the Pro Git book.
$
Additional issues
- locking and unlocking working trees
- moving working trees
- gc.worktreePruneExpire
- 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.