Worktrees

Git Worktrees

Git worktrees are a feature that allow a developer to checkout more than one branch at a time. Typically, when you edit a repo you checkout a branch, make your changes and then push it back to the repo. There are times when that workflow is interrupted. It can be interupted for many reasons:

  • You have to stop working on whatever you are working on to fix a bug
  • Your have to check out a co-workers branch for a code review
  • Whatever you were working on is now on hold and you won’t be coming back anytime soon
  • You want to see how something was implemented and you deleted the old code

Handling these interuptions can be a handled in a couple of ways. The first and easiest is to just stash the changes. The second and not recommended is to fork the repository. This is not recommended because you can check out the same branch more than once. You then have to manage the changes between the forks, which can cause conflicts.

Git worktrees allow you to checkout a branch into a separate directory. It won’t allow you to checkout the same branch more than once.

So, for instance, for the bug fix you add a worktree with a branch for the bug fix, switch over to that worktree and fix the bug and check it in.

In the case of a code review, you can check the co-workers branch out into a new worktree, review the code and then remove the worktree when you are done.

If the task you are working on goes on hold, you can add a new worktree for whatever you are switching over to and leave the old one in place.

And finally, in the case of wanting to see how something was implemented and you have deleted the old code, you can checkout the old code into a worktree to be able to compare them side-by-side.

My History with Worktrees

I started using worktrees from the command-line:

git worktree add [-f] [--detach] [--checkout] [--lock [--reason <string>]] [-b <new-branch>] <path> [<commit-ish>]

And invariably, I would screw it up, but I continued to use it.

At one job, I showed my boss worktrees and he improved on the command-line version with a git alias

[alias]
    wta = "!f() { git worktree add \"`git rev-parse --show-toplevel`-$1\" ${2-$1}; } ; f"
    wtb = "!f() { git worktree add \"`git rev-parse --show-toplevel`-$1\" -b ${2-$1}; } ; f"
    wtr = "!f() { git worktree remove \"`git rev-parse --show-toplevel`-$1\"; } ; f"
    wtp = worktree prune
    wtl = worktree list

This made things easier to remember and simplified things. However, the “linked worktrees” were hard-coded:

~/Desktop/projects/managing_workspaces (usage) $ git wta dev
Preparing worktree (checking out 'dev')
HEAD is now at eb4c049 Merge branch 'single-word-command' into dev
managing_workspaces      f0bf2358b9 [usage]
managing_workspaces-dev  eb4c049721 [dev]

It would take the current folder name and a branch name, which can end up with:

managing_workspaces                      f0bf2358b9 [usage]
managing_workspaces-dev                  eb4c049721 [dev]
managing_workspaces-single-word-command  242453c083 [single-word-command]
managing_workspaces-single-work-command  d720a9a300 [single-work-command]
managing_workspaces-temp1                12f4a4c4ee [temp1]

It directly associates the “main worktree” with the “linked worktree”. But if your branch names a bit long, things can get out-of-control.