Using Git Worktrees with Many Untracked Files

Article summary

A few years ago, I wrote about a great feature of Git that I had discovered: worktrees. Since then, my use of worktrees has expanded to the point that I now use a fresh worktree for every feature branch.

Git worktrees are still great for the reasons I described in the article linked above. I’ve also found them to be handy for code reviews. Web-based code collaboration tools give you a diff, but sometimes you need to dive into the full code (and maybe even run it) to get a better look. A worktree is a quick and easy way to switch context without disrupting your own work in progress.

COW Power

A worktree gives you a clean copy of your branch (without any .gitignored files), which is generally a good thing. But if your project includes a lot of third-party or generated files, it can cause some friction. When you’re working on a web project, a prominent example of this is the node_modules directory. Most likely, this directory is in your .gitignore, so it won’t be included when you create a new worktree.

If your application modifies the contents of such non-versioned files, you want every worktree to have its own copy. In the case of node_modules, you want the contents to exactly match the specification that is checked into version control. So you could just install all your node modules again. Or copy the whole thing from your main repository. But if you’re using a filesystem that supports copy-on-write (like APFS, available since Mac OS High Sierra), there is a better way.

A copy-on-write (COW) clone duplicates an existing file without actually copying its contents on disk immediately. This is similar to a traditional hard link, except that if you modify a hard-linked file, the original file will be modified as well. But a COW clone copies the original if and only if it is written to (hence, “copy on write”).

On Mac, you can make a COW clone by using the cp command; just pass it the -c flag. Recursively cloning an entire directory structure is as easy as cp -Rc.

Inevitably, you’ll have other non-versioned files that need to be included in your worktree: developer-specific configuration, application secrets, etc. Put all this sort of stuff into a script, and you’ll have not only a time saver for creating new worktrees but also a self-documenting reference for setting up your project.