User Tools

Site Tools


git_worktree

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>

Drawbacks of git stash:

  • Constant stashing and unstashing to move between different working directory states.
  • git stash doesn'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

Remove the worktree

You're done with that worktree so remove it:

$ git remove ../temp
$ git worktree prune

Detailed example

Initial state of the main working tree

All clean on the master branch, and no linked working trees:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.

nothing to commit, working tree clean
$
$ 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.30):

$ git worktree add -b emergency ../temp 2.1.30
Preparing ../temp (identifier temp)
HEAD is now at 90bdf0a Stahp updating bundler
$

List the working trees:

$ git worktree list
/home/rpjday/ebooks/progit/progit2  dd124f7 [master]
/home/rpjday/ebooks/progit/temp     90bdf0a [emergency]
$

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.
git_worktree.1551013678.txt.gz · Last modified: 2019/02/24 13:07 by rpjday