Where to keep Git worktrees?

Lately I’ve finally been getting into Git worktrees, especially now that GitHub CLI supports creating a worktree in the same step as checking out a pull request; gh pr checkout 120 --worktree ../pr-120 creates a worktree in ../pr-120 and checks out the associated branch.

But I’ve seen conflicting guidance on where it’s best to put these worktrees relative to your projects.

Say for instance you have a code directory that looks something like this:

`-- code/
    |-- personal-blog/
    |   |-- .git/
    |   `-- src/
    `-- side-project/
        |-- .git/
        `-- src/

When creating worktrees for your personal-blog and side-project repos, where should you put those worktrees? (The .git and src directories will be removed in subsequent examples.)

“Sibling method”

This is the method I’ve most commonly seen in blog posts and articles offering guidance on worktrees. Here, the worktrees are siblings to the main project directories:

`-- code/
    |-- personal-blog/
    |-- personal-blog-new-feature/
    |-- personal-blog-pr-271/
    |-- side-project/
    |-- side-project-bugfix/
    `-- side-project-pr-10/

However, this strikes me as problematic. For the worktree directories to live alongside the project directories means that the root directory (code/) will get crowded quickly. It’s difficult to tell what’s a worktree and what’s a main project directory at a glance. The directories might not be ordered correctly, if you don’t give your worktree the proper prefix. Searching for text in the root directory will find files in all worktrees, which may not be desirable.

The command for creating a worktree with the “sibling method”:

git worktree add ./side-project-bugfix # sibling method

The remainder of the methods discussed here use a nested structure, where the worktree directory is a child directory of an otherwise empty directory named for the project directory. This prevents worktrees from multiple projects colocating in the same parent directory.

For each method below, an alternative exists wherein the directories are collapsed, but I’m not considering this approach, as it makes unclear how worktrees are related to their main project directory, unless carefully named.

“Cousin method”

|-- code/
|   |-- personal-blog/
|   `-- side-project/
`-- worktrees/
    |-- personal-blog/
    |   |-- new-feature/
    |   `-- pr-271/
    `-- side-project/
        |-- bugfix/
        `-- pr-10/

Rather than a relative path, the “cousin method” uses an absolute path that lives potentially alongside the root code directory, or above. Here, the worktree directories are “cousins” of the main project directories; they share a grandparent, but not a parent.

This is a bit better, but now the closest common ancestor between the worktree directories and the main project directories is something perhaps too broad and too crowded, for instance ~/Documents or even just ~/. There may be several or dozens of other directories living alongside code/ and worktrees/ in this case, muddying the relationship between the two.

This is what Emdash and Copilot do by default; Emdash in ~/emdash/worktrees, Copilot in ~/.copilot/copilot-worktrees.

(Claude Code, incidentally, puts worktrees inside your project directory by default, in .claude/worktrees, a “child method” not explored here. This, of course, requires adding a new line to your .gitignore.)

Example Git command to create a worktree with the “cousin method”:

git worktree add ~/worktrees/side-project/bugfix # cousin method

“Niece method”

`-- code/
    |-- .worktrees/
    |   |-- personal-blog/
    |   |   |-- new-feature/
    |   |   `-- pr-271/
    |   `-- side-project/
    |       |-- bugfix/
    |       `-- pr-10/
    |-- personal-blog/
    `-- side-project/

After laying out all of these options, this method seems the most attractive to me. Here, the worktrees still have the projects’ root directory as a common ancestor. And — while searching the root directory will return potentially unwanted results from worktrees as in the sibling method — here, this is easily solved by adding .worktrees to an .ignore file.

I’ve also made the worktrees directory hidden in this method; of course it could just as easily be hidden in any of the previous methods, as well.

The command for creating a worktree with the “niece method”:

git worktree add ../.worktrees/side-project/bugfix # niece method

But what if you further organize your code/ directory by area or topic? Something like:

`-- code/
    |-- personal-blog/
    |   |-- .git/
    |   `-- src/
    |-- side-project/
    |   |-- .git/
    |   `-- src/
    `-- work/
        |-- work-website/
        |   |-- .git/
        |   `-- src/
        `-- work-mobile-app/
            |-- .git/
            `-- src/

Should we then put all worktrees in the “root” directory, code/ so that we only have one .worktrees directory, like this — basically a slight modification of the “cousin method”:

`-- code/
    |-- .worktrees/
    |   |-- personal-blog/
    |   |   `-- new-feature/
    |   |-- side-project/
    |   |   `-- bugfix/
    |   `-- work/
    |       |-- work-website/
    |       |   `-- feature-branch/
    |       `-- work-mobile-app/
    |           `-- feature-branch/
    |-- personal-blog/
    |-- side-project/
    `-- work/
        |-- work-website/
        `-- work-mobile-app/

Or stick with a strict “niece method” as above, giving us multiple .worktrees directories, like this:

`-- code/
    |-- .worktrees/
    |   |-- personal-blog/
    |   |   `-- new-feature/
    |   `-- side-project/
    |       `-- bugfix/
    |-- personal-blog/
    |-- side-project/
    `-- work/
        |-- .worktrees/
        |   |-- work-website/
        |   |   `-- feature-branch/
        |   `-- work-mobile-app/
        |       `-- feature-branch/
        |-- work-website/
        `-- work-mobile-app/

Personally, I still prefer the latter “niece method.” Yes, we have multiple .worktrees directories, but I don’t think there’s really a disadvantage to this. Further, this means that, within any main repository directory, the worktrees are always at the relative path of ../.worktrees/; you don’t have to think about whether you need to navigate up one or two or more directories to find a project’s worktrees. The command for creating new worktrees always begins with the same path:

git worktree add ../.worktrees/side-project/bugfix # cousin method

“Bare method”

Of course, I haven’t even gotten into the “bare method,” which requires modifying the way you clone the repository in the first place. Personally I find this a little off-putting. I don’t like the idea of every project being in a directory node named .bare or similar, or of having to remember to clone repositories correctly every time you might want to use worktrees later. The “niece method” above is simple and flexible enough for me.


Here’s a gh alias that will assign the command prw (“PR worktree”) to create a worktree for a given PR number, using the “niece method”:

gh alias set --clobber --shell prw 'gh pr checkout "$1" --worktree="../.worktrees/$(basename "$PWD")/pr-$1"'

And here are some Git aliases for working with worktrees, using the “niece method”:

[alias]
  # List Worktrees in fzf
  wtl = "!f() { selected=$(git worktree list | fzf) || return 0; printf '%s\\n' \"${selected%%  *}\"; }; f"
  # Add Worktree
  wta = "!f() { worktreePath=\"../.worktrees/$(basename \"$PWD\")/$1\"; git worktree add --quiet -b \"$1\" \"$worktreePath\" && printf '%s\\n' \"$worktreePath\"; }; f"
  # Remove Worktree from fzf
  wtr = "!f() { selected=$(git worktree list | fzf) || return 0; git worktree remove \"${selected%%  *}\"; }; f"

And Copilot allows you to configure worktrees to use this method with variables:

%repository-root%/../.worktrees/%repository-name%

Leave a Reply