Mastering Git workflow – Part 2/2

Handling interruptions elegantly using git-worktree

In our last post about git, we discussed the git-stash command. We thought of a situation where we get interrupted to work on more urgent stuff, which is quite common in our days as software developers.

We’ve also discussed that git-stash could cause some conflicts in your repository and how we could mitigate them. In today’s post, we’ll continue pursuing a good way to deal with interruptions (and some other things). The situation is the same as the last time but we’ll be using git-worktree to solve it.

What is git-worktree

In a nutshell, this command allows us to checkout multiple branches at once. It’s a rough description so let’s see what the documentation says:

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, along with additional metadata that differentiates that working tree from others in the same repository. The working tree, along with this metadata, is called a "worktree".

Also from the docs, we can see that working trees are different than branches.

This new worktree is called a "linked worktree" as opposed to the "main worktree" prepared by git-init or git-clone. A repository has one main worktree (if it’s not a bare repository) and zero or more linked worktrees.

Most likely the repositories you’ve been working with are no bare repositories. Perhaps you have more than one branch in such repositories but you have only the main worktree. You can confirm that by running the command git worktree list in your repository.

You’ll see a result like shown below.

/path-to/your-repo  hash-commit [your-current-branch]

Here’s mine.

/home/edy/projects/youtube/git-demos/dotfiles  73ca3c8 [main]

To get a better idea about the relationship between a working tree and a branch. Try to check out another branch and list the working trees again.

> git checkout -b other-branch
> git worktree list

Now it’s clear that we can check out a branch per working tree. We can think of the working tree as the place we work (the directory) and the branch as the version of the code we have inside such a place.

Let’s see how it can be useful in the next sections.

The ABCs of git-worktree

To link a worktree you can run the following command:

git worktree add <path> [<commit-ish> | <branch>]

We can, for example, create a worktree by running:

> git worktree add ../some-folder
Preparing worktree (new branch 'some-folder')
HEAD is now at 73ca3c8 fix init file

Note: we created the worktree in a top-level folder. It can be any path actually, but we should avoid adding it inside of the current dir (main worktree) so we use this pattern ../new-folder.

It created a new branch, but we can pass an existing branch name or a commit hash. I have a branch called hello so I can add a worktree with that branch by running:

> git worktree add ../wt1 hello
Preparing worktree (checking out 'hello')
HEAD is now at 73ca3c8 fix init file

By running git worktree list you’ll see something like the following.

/home/edy/projects/youtube/git-demos/dotfiles     73ca3c8 [main]
/home/edy/projects/youtube/git-demos/some-folder  73ca3c8 [some-folder]
/home/edy/projects/youtube/git-demos/wt1          73ca3c8 [hello]

To go to a specific worktree you just need to go to its folder.

cd ../some-folder # goes to some-folder worktree with the some-folder branch
cd ../wt1 # goes to wt1 worktree with the hello branch

Once you are in a linked worktree, you can do anything you used to do in the main worktree. However, you can’t switch to an already checked out branch.

For example, if you are in the wt1 folder you cant switch from hello branch to the main branch because such a branch is already checked out.

Running the git branch command you’ll see something like what is shown below.

* hello
+ main
  other-branch
+ some-folder

In the list of branches it is possible to see one with an asterisk (*) which means that it’s the checked out branch in the current worktree. The ones with the plus symbol (+) are also checked out branches but are from other worktrees.

If you try to checkout in one of them again, then it should see something like the following:

(on the wt1 folder)
> git checkout main
fatal: 'main' is already checked out at '/home/edy/projects/youtube/git-demos/dotfiles'

Once you’re done with a worktree you can just throw it away by running:

git worktree remove ../some-folder

Usages for git-worktree

Handling interruptions

Worktrees are really good to handle interruptions, you don’t even have the risk to have conflicts in your current work as we had by using git-stash.

Once you need to go to work on some different branch just start a new worktree and work on that, no worries.

The downside of that is to install your project dependencies again since you would be creating a new folder for that worktree (there’s no free lunch).

Different versions of the same project (avoid IDE confusion)

It’s helpful when you have different versions of the same project. Suppose you’re working on a project and you need to go back to an older version to check some behavior or to fix a bug in a legacy code. You could have a worktree per major version.

It would avoid the IDE confusion that might happen when you switch branches and keep them in the same directory. I recall facing similar situations using Eclipse IDE.

Summary

git-worktree is a very poweful git command. This little article is not enough to cover all the possibilities it brings up. Hopefully, you could get the two common situations described here where this command can be helpful, and depending on your workflow you can find much more ways to use it.

This post completes the last one on git, about git-stash and gives you one more git skill. If you have any questions please leave them in the comments and consider sharing this content with your friends.

That’s all, see ya!

References

We want to work with you. Check out our "What We Do" section!

Edigleysson Silva

I own a computer

View all posts by Edigleysson Silva →