---
title: Multiple Branches in Git
date: 2019-03-22
description: How to use git worktrees to work on multiple branches simultaneously without stashing.
tags: [git]
---

## Introduction

There are times where you might be working from a particular git branch and need to quickly jump over to a different branch to do some urgent work.

Typically you would need to first `git stash` anything you were working on (as it's unlikely to be in a state where it can be committed), and then you'd have to leave your current branch to create a new branch from `master` and thus begin working on your new urgent task.

This is a fairly straightforward workflow, but there is a mild annoyance which is that I happen to `git stash` _a lot_ and I find when jumping over to a new branch to do some urgent work that I might end up `git stash`'ing a few more times along the way.

Ultimately, when I'm done with my urgent task and ready to go back to my other branch, I then have to sift through my stash to find the relevant one I want to pop. OK so not that tragic considering `git stash list` will indicate the branch on which the stash was taken (which helps), but I do then need to Google what the syntax is for popping a specific stash (e.g. it's `git stash apply stash@{n}` where `n` is the index you want to apply.)

> [!INFO]
> for the life of me I wish I could remember the syntax but it just eludes me every time.

Oh, and then you have to think about whether you actually want to use `apply`, which leaves the stashed changes in the stack, or if you meant to actually `pop` the stashed content (`git stash pop stash@{n}`) so it's properly removed from the stack.

This is where I was recently introduced to a concept in git referred to as a 'worktree' (thanks Kiran).

## Worktree

Git offers a feature referred to as a [worktree](https://git-scm.com/docs/git-worktree), and what it does is allow you to have multiple branches running at the same time.

It does this by creating a new directory for you with a copy of your git repository that is synced between the two directories where they are stored.

This is different to manually creating a new directory and git cloning your repo down, because with the worktree model the two sub directories are aware of each other.

> [!INFO]
> as you'll see, although this workflow is pretty cool, you _could_ argue that `git stash` is just plain simpler and easier for a human mind to reason about. I'll leave that up to the reader to decide.

## Example

In the following example I'm going to create a new git repo. I'll make a change in `master`, then create a new branch for doing some work. We'll then imagine that I have been given an urgent task that I must complete _now_ and yet my current non-master branch is in such a state that I want to avoid just stashing everything.

> [!TIP]
> I use tmux to split my terminal into multiple windows, and this demonstration will require two windows (or two separate terminal instances if you're not using a screen multiplexer) for the sake of demonstration.

### Create a new repo

- `mkdir foo_project`
- `cd foo_project`
- `touch foo`
- `git add foo`
- `git commit -m "created foo file"`

### Create a new branch

- `git checkout -b foo_contents`
- `echo 123 > foo`
- `git add -u`
- `git commit -m "added content to foo"`

Now I'll create a new file and stage it for committing, but I won't commit it (this is where we pretend my branch is in some hideously complex state).

### Create new worktree branch

- `git worktree add ../foo_hotfix`

> [!TIP]
> you'll want to create the new worktree in a directory outside of your current repo's directory (just so there's a clear distinction).

At this point you'll find your current terminal is still in the same `foo_contents`, but there is now a new directory called `foo_hotfix` outside your current repo's directory.

### Make changes in new worktree branch

Open up a new terminal (or split window) and run through the following steps:

- `cd ./foo_hotfix` (or `cd ../foo_hotfix` if your new terminal is currently set to your main git repo directory)
- `git log`

OK, so if you do a `git log` you'll find that the worktree has a branch automatically created and named after the worktree (so the branch is called `foo_hotfix` in my case).

The important thing to realize is that `git worktree add` is a bit like `git branch` in that it creates the new worktree from the current branch you're in. Meaning that my `foo_hotfix` branch has the "added content to foo" commit from the `foo_contents` branch as that's where I ran the `git worktree add` command from.

This is what `git log` looks like for me in this new worktree:

```
* d374dcb (Integralist) - (HEAD -> foo_hotfix, foo_contents) added content to foo (2 minutes ago)
* 9ae3a7f (Integralist) - (master) created foo file (3 minutes ago)
```

I don't want the commit `d374dcb` in there as it's coming from a branch (`foo_contents`) that's still in progress, and so I'll need to rebase out that commit:

- `git rebase -i 9ae3a7f`

> [!INFO]
> the rebase editor opens and I change `pick` to `drop` to get rid of the commit.

Now at this point I have a new working directory that I can work in:

- `echo hotfix > baz`
- `git add baz`
- `git commit -m "some hotfix"`

### Merge my hotfix back into master

I'm going to change into my `master` branch, but remember I'm still in the `foo_hotfix` directory, so my main repo directory `foo_project` (open in another terminal window) is still in the `foo_contents` branch).

- `git checkout master`
- `git merge foo_hotfix`

### Removing the worktree

OK, so at this point we've merged our hotfix into `master`. I want to go back to my original repo directory and make sure I have the latest `master` rebased in before continuing on with my `foo_contents` work.

To remove the worktree you can either remove it using the git interface (e.g. `git worktree remove foo_hotfix`) or manually remove it (e.g. `cd ../ && rm ./foo_hotfix`), where git will, at some point in the future, internally run a prune and remove any references to this orphaned branch/working tree (you could also manually trigger that prune using `git worktree prune`).

> [!WARNING]
> if I do `git worktree remove foo_hotfix` while currently residing inside the `foo_hotfix` directory, I'll find that the `.git` repository is removed from the directory.

### Continuing working on my feature branch

Presuming I'm still in the `foo_hotfix` directory and that's where I ran `git worktree remove foo_hotfix`:

- `cd ../foo_project`
- `git rebase master` \< whoops! I need to stash my changes first †
- `git stash pop`

> [!INFO]
> † why yes, this does seem a bit strange considering that's what I was trying to avoid in the first place, but in this case it's a single 'stash' and so a simple `git stash pop` will suffice to get me back to where I need to be.

I can now continue working on my `foo_contents` branch.

## Conclusion

Well, this was fun heh! 😉

Do you think you have any uses for git's worktree feature?

Let me know on [twitter](https://twitter.com/integralist).
