How to create, use and remove worktrees, as an alternative to constantly stashing and popping when you need to change contexts.
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.
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>
Various online links related to worktrees:
Drawbacks of git stash
:
git stash
doesn't work with unmerged paths, after a merge or rebase with conflicts.Applications of worktrees:
Weaknesses of worktrees:
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
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 $
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 $
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] $
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 $
$ 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 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. $
$ 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.
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 $
extensions.worktreeConfig
gc.worktreePruneExpire
worktree.guessRemote
$GIT_DIR/config.worktree This is optional and is only searched when extensions.worktreeConfig is present in $GIT_DIR/config.