Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

The 2016 Git Retrospective: Worktrees

DZone's Guide to

The 2016 Git Retrospective: Worktrees

The awesome Git worktree command lets you check out and work on multiple repository branches in separate directories simultaneously.

· Agile Zone
Free Resource

Speed up delivery cycles and improve software quality with TestComplete. Discover the most robust automated testing tool for end-to-end desktop, mobile, and web testing. Try TestComplete Free.

It's been a busy year for the Git project! There were five huge feature releases in 2016 (v2.7 through v2.11) that introduced just over 4,000 new commits and a ton of new features. This is the first part of a six-part series looking at improvements made to some of Git's popular user-facing features.

Image titleIn this article, we'll look at upgrades to the git worktree command, which first appeared in Git v2.5 but was rounded out in 2016. Two valuable new features were introduced in v2.7 (the list subcommand, and namespaced refs for bisecting), an important bug fix landed in v2.8, and the lock/unlock  subcommands were implemented in v2.10. 

Image title

Before we begin, note that many operating systems ship with legacy versions of Git, so it's worth checking that you're on the latest and greatest. If running git --version from your terminal returns anything less than Git 2.11.0, head on over to Atlassian's quick guide to upgrade or install Git on your platform of choice. 

Worktrees

The awesome git worktree command lets you check out and work on multiple repository branches in separate directories simultaneously. For example, if you need to make a quick hotfix but don't want to mess with your working copy, you can check out a new branch in a new directory with:

$ git worktree add -b hotfix/BB-1234 ../hotfix/BB-1234
Preparing ../hotfix/BB-1234 (identifier BB-1234)
HEAD is now at 886e0ba Merged in bedwards/BB-13430-api-merge-pr (pull request #7822)

Worktrees aren't just for branches. You can check out tags as different worktrees in order to build or test them in parallel. For example, I created worktrees from the Git v2.6 and v2.7 tags in order to examine the behavior of different versions of Git:

$ git worktree add ../git-v2.6.0 v2.6.0
Preparing ../git-v2.6.0 (identifier git-v2.6.0)
HEAD is now at be08dee Git 2.6

$ git worktree add ../git-v2.7.0 v2.7.0
Preparing ../git-v2.7.0 (identifier git-v2.7.0)
HEAD is now at 7548842 Git 2.7

$ git worktree list
/Users/kannonboy/src/git         7548842 [master]
/Users/kannonboy/src/git-v2.6.0  be08dee (detached HEAD)
/Users/kannonboy/src/git-v2.7.0  7548842 (detached HEAD)

$ cd ../git-v2.7.0 && make

You could use the same technique to build and run different versions of your own applications side-by-side.

Listing Worktrees

Git v2.7 rounded out the git worktree command with a few improvements. The git worktree list subcommand displays all of the worktrees associated with a repository:

$ git worktree list
/Users/kannonboy/src/bitbucket/bitbucket            37732bd [master]
/Users/kannonboy/src/bitbucket/staging              d5924bc [staging]
/Users/kannonboy/src/bitbucket/hotfix/BB-1234       37732bd [hotfix/BB-1234]

Bisecting Worktrees

git bisect is a neat Git command that lets you perform a binary search of your commit history. It's usually used to find out which commit introduced a particular regression. For example, if a test is failing on the tip commit of my master branch, I can use git bisect to traverse the history of my repository looking for the commit that first broke it:

$ git bisect start

# indicate the last commit known to be passing the tests (e.g. the latest release tag)
$ git bisect good v2.0.0

# indicate a known broken commit (e.g. the tip of master)
$ git bisect bad master

# tell git bisect a script/command to run; git bisect will find the oldest commit 
# between "good" and "bad" that causes this script to exit with a non-zero status
$ git bisect run npm test

Under the hood, bisect uses refs to track the good and bad commits used as the upper and lower bounds of the binary search range. Unfortunately for worktree fans, these refs were stored under the generic .git/refs/bisect namespace, meaning that git bisect operations that are run in different worktrees could interfere with each other.

As of v2.7, the bisect refs have been moved to .git/worktrees/$worktree_name/refs/bisect, so you can run bisect operations concurrently across multiple worktrees.

Locking Worktrees

When you're finished with a worktree, you can simply delete it and then run git worktree prune or wait for it to be garbage collected automatically. However, if you're storing a worktree on a network share or removable media, then it will be cleaned up if the worktree directory isn't accessible during pruning — whether you like it or not! Git v2.10 introduced the git worktree lock and unlock subcommands to prevent this from happening:

# to lock the git-v2.7 worktree on my USB drive
$ git worktree lock /Volumes/Flash_Gordon/git-v2.7 --reason "In case I remove my removable media"

# to unlock (and delete) the worktree when I'm finished with it
$ git worktree unlock /Volumes/Flash_Gordon/git-v2.7
$ rm -rf /Volumes/Flash_Gordon/git-v2.7
$ git worktree prune

The --reason flag lets you leave a note for your future self, describing why the worktree is locked. git worktree unlock and lock both require you to specify the path to the worktree. Alternatively, you can cd to the worktree directory and run git worktree lock . for the same effect.

Other Small Improvements

For completeness, Git v2.7 also allows you to create local clones of worktrees (though cloning a worktree creates an entirely independent Git repository, not another worktree).

Git v2.8 also included small fixes for git worktree's -f and -B options. By default, you can't have multiple worktrees with the same branch checked out. Appending -f (or --force) to a command will override this restriction. Similarly, creating a new worktree with git worktree add -b  will fail if the named branch already exists. Using -B instead of -b will override this restriction and overwrite the existing branch for you. Prior to v2.8, there were a couple of bugs that meant that -B behaved incorrectly in some scenarios if the --force flag was not specified. 

Stay Tuned!

git worktree is already valuable for developers who need to work with multiple clones of their repository, and I'm sure we'll see even more improvements to this relatively new command in 2017. If you have any neat use cases or tips for using git worktree, please share them with me on Twitter (I'm @kannonboy). Stay tuned for the next article in the retrospective series where we'll be investigating some of the improvements made to Git's diff subsystem in 2016. Or, if you just can't wait for more Git, head on over to Atlassian's Git tutorials for some tips and tricks to improve your workflow.

If you stumbled on these articles out of order, you can check out the other topics covered in our Git in 2016 retrospective below:

Or, if you've read 'em all and still want more, check out Atlassian's Git tutorials (I'm a regular contributor there) for some tips and tricks to improve your workflow.

Release quality software faster with TestComplete. Discover how to decrease testing times and expand test coverage with the most robust automated UI testing tool. Try free for 30 days.

Topics:
git ,version control ,worktrees ,agile

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}