User Tools

Site Tools


git_worktree

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

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.
git_worktree.txt · Last modified: 2019/03/06 08:24 by rpjday