I am not sure how I discovered git-worktrees but I'm sure glad that I did. It has made a big difference in how many branches I can work on at once, while still remaining simple
Git uses worktrees internally but you can use them to make clone from your local repo instead of clone from the origin. However, the big feature is that it shares history with your local repo. So you act on it independently (even push and pull from remotes ) but it's kind of an extension from the local "main" repo. You can think of it as a local fork, if you will, but with a shared history. A good explanation from the main git documentation:
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".
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 is not a bare repository) and zero or more linked worktrees.
My common use is this: I have a develop
branch checked out
locally. I then make new worktree and make a new feature branch in
that new worktree to work on that feature. If a bug comes up that
needs fixing quickly, I either make a new bugfix branch from my main
develop
worktree or I make a new fix worktree, push and merge it
from that folder. Once it is merged into develop, I can use git merge
<bugfix-branch>
in my feature worktree. I'll give a step-by-step example below.
Note that I don't push, or pull develop from my branches around develop. That is because they are sharing the same history and metadata files. So it simulates doing everything in that folder...but you are actually in different folders. This allows you to have different branches in different folder yet still have the name metadata/history in each. One interesting quirk is that you can't have have the same branch checked out by two different worktrees. So if you are working on BranchA on one worktree repo, you can't work on BranchA in another worktree folder . This seems weird but worktrees are not stand-alone - they all share the same git history.
I like Tomups git-worktree scripts. They not only manage creating the folders, but they also copy over ~.env~ files, node_modules
folders, etc. I'll give an example of how I use them with my general workflow:
- I have a repo cloned locally and make sure that the
develop
branch is checked-out. - I run
git wtadd ../proj-new-feature
which creates a worktree in the parent folder above my project calledproj-new-feature
- I change to the
proj-new-feature
folder and make a feature branch just like normal:git checkout -b feature/fancy-new-thing
- I start doing my normal development work.
- Soon I'm told about a bug in the dev environment. I go to the
folder where my
develop
branch is. It's a one-line fix, so I make a new branch there :git checkout -b bugfix/easy-bug
- Once I fix the bug and push it up, I can do back to my
proj-new-feature
folder. - There I can merge in my
bugfix/easy-bug
branch easily withgit merge bugfix/easy-bug
. No pulling from remote, etc because the worktrees share the same history - When I'm done I push the
feature/fancy-new-thing
branch to remote - After the PR is merged in, I go back to development, pull in remote and then I can delete the feature worktree with
git wtremove ../proj-new-feature
The cycle then continues.
With git worktrees I can have different features/branches active and they don't get in the way. It seems like a simple idea but really has made things easier in my workflow