Skip to main content

A Better Way to Worktree

· 2 min read

I've consistently been using worktrees for the past two years.

But I recently learned git clone --bare is suboptimal – there's a better way to clone a repo for worktree usage that doesn't require cluttering up your repo root or creating extra branches for the worktree workflow.

Here's the fastest, cleanest way I've found to clone a repo for usage with worktress. Works every time, without needing to run git gc all the time to clean up storage bloat.

I use it in zsh, but it should work in bash. (Fish users, sorry, I have no clue)

function git-empty-clone() {
# Useful for cloning a repo suitable for use with git worktrees
# Taken from this stack overflow answer:
# https://stackoverflow.com/questions/54367011/git-bare-repositories-worktrees-and-tracking-branches
if [ $# -lt 2 ]; then
echo "Usage: git-empty-clone <repo-url> <target-dir>"
return 1
fi

local repo_url="$1"
local target_dir="$2"

git clone "$repo_url" "$target_dir" || return 1
cd "$target_dir" || return 1

# Create an empty root commit
local empty_tree
empty_tree=$(git hash-object -t tree /dev/null)
local empty_commit
empty_commit=$(echo | git commit-tree "$empty_tree")

# Checkout the empty commit in detached HEAD
git checkout "$empty_commit"
echo "Use git worktree add <branch_name> to start using worktrees."
}

Example usage to clone my vim configs repo, then add a worktree for the dev branch:

git-empty-clone [email protected]:whoislewys/vim_runtime.git vim_runtime.git
git worktree add dev

Read the thread to learn why it works and uncover the mystery of Git's empty tree.

Better worktree initialization

The .worktreeinclude approach is perfect, and scales nicely to monorepos.

Before coming across it, I was using a post-worktree-create git hook that conflicted with husky pre-commit hooks, and I ended up having to invoke it manually so as not to bloat the pre commit hooks for team members not using worktrees. A mess.

TODO: write support for pi, my preferred agent harness, to use .worktreeinclude