===== 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 ] []
git worktree list [--porcelain]
git worktree lock [--reason ]
git worktree move
git worktree prune [-n] [-v] [--expire ]
git worktree remove [-f]
git worktree unlock
===== Links =====
Various online links related to worktrees:
* [[https://git-scm.com/docs/git-worktree|man page]]
* [[https://stackoverflow.com/questions/31935776/what-would-i-use-git-worktree-for|Stack Overflow: What would I use git-worktree for?]]
* [[https://spin.atomicobject.com/2016/06/26/parallelize-development-git-worktrees/|Atomic Object: Parallelize Development Using Git Worktrees]]
* [[https://stacktoheap.com/blog/2016/01/19/using-multiple-worktrees-with-git/|StackToHeap: Using multiple worktrees with git]]
* [[https://www.saltycrane.com/blog/2017/05/git-worktree-notes/|SaltyCrane Blog: git worktree notes]]
* [[https://blog.reelworx.at/detail/git-worktree-making-typo3-core-development-more-efficient/|ReelWorx: git worktree - making TYPO3 Core development more efficient]]
* [[https://152percent.com/blog/2018/4/17/code-review-with-git-worktrees|Code review with Git Worktree]]
===== Issues related to worktrees =====
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 ..." to unstage)
modified: README.asc
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." 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 ..." to unstage)
modified: README.asc
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." 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
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
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 ..." to unstage)
modified: README.asc
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." 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.