by Leon Rosenshein

Branch vs

Maybe I'm late to the party, but recently I learned about git worktrees. I'm familiar with branches, and they're great. Great for isolation. Great for bug fixes. Great for incremental changes. But they're not so great when you have large structural changes.

Or at least they're not great with structural changes in the presence of compiled languages and caches (both bazel and your IDE at least). From a correctness standpoint they work. You can switch between branches and your source code tree will faithfully represent the state of the branch every time. But unless your branches include the intermediate artifacts and state (which they shouldn't) then every time you switch branches your IDE will go nuts as it rescans everything and updates itself and `bazel` will invalidate itself and rebuild huge swaths of code. That's the correct behavior and it produces the correct artifacts.

But it comes at a cost. Depending on the scope of changes switching branches can cause as much work as a fresh `git clone` on a new machine. If you only do this once per branch that's not a big deal. But if you have to switch back and forth multiple times then swapping branches can become a major time sink.

My traditional approach to this has been to just `git clone` a new instance of the repo whenever I need to do this, and then remove it when I'm done. It works, but it burns 6+ GB of disk space for the `.git` folder every time, I need to remember to keep all of the master branches on my computer up to date (or at least in sync) across them, and syncing across them is hard if I need to since the common ancestor is up on github.

Worktrees solve this problem. The git repo isn't duplicated. The same one is shared for all trees, so I don't burn the disk space. There's only one master branch to keep up to date, so it can't be out of sync with itself. And the nearest common ancestor is right here on my machine, so sharing/cherry-picking is as straightforward as it can be.

And because it's a different directory tree on disk both bazel and my IDE don't lose their saved state when I switch trees. So I don't have to wait an extra 20 minutes for everything to download/build because some base version changed. I don't need to watch VSCode take over all my CPUs while it re-indexes the entire structure. I can name my tree (and the folder it's in) however I want to so that I know where I am.

So far it's working out well. It's much easier on my computer than just switching branches, and has less overhead for me than managing and syncing multiple `git clone`s. One thing I've been doing is having the new worktrees outside the base repo folder to make it easier on my IDE and make it easier for me to know what worktree I'm in. And it's simple to use. one 3 basic commands to remember. One to set up a tree, one to remove a tree, and one to list trees. After that I can switch trees just by changing folders, just like I would with a `git clone` based workflow. So far I haven't had any issues, but it's still early in my use of the pattern. Anyone already using `git worktree`? What's your experience been?