GitWorktree.org logoGitWorktree.org

Git Bare Repository with Worktrees

Combining a bare clone with git worktree is a popular pattern that eliminates the concept of a “main” checkout directory. Every branch lives in its own worktree, and the bare repo is purely a shared object store.

What Is a Bare Repo?

A bare repository contains only the Git database — the objects, refs, and configuration — without a working tree. It is what you get on a Git server, and it is what git clone --bare creates locally.

Normal clone vs bare clone
# A normal clone has a working tree + .git directory
myapp/
├── .git/        # Git database
├── src/         # working tree
└── README.md

# A bare clone has only the Git database
myapp.git/
├── HEAD
├── config
├── objects/
├── refs/
└── ...          # no working tree

Because a bare repo has no working tree, you cannot edit files in it directly. That is exactly the point — you add worktrees for every branch you want to work on.

Why Use Bare + Worktrees

With a regular clone, your main checkout is “special” — it holds the .git directory and all other worktrees depend on it. If you accidentally delete it, all linked worktrees break. The bare repo pattern avoids this asymmetry:

  • No “main directory” confusion. The bare repo is clearly just infrastructure. Every branch you work on lives in an equally-weighted worktree.
  • Clean mental model. You never accidentally edit files in the bare repo because there are no files to edit.
  • Easy to reorganize.You can add, remove, and move worktrees without worrying about disrupting the “primary” checkout.
  • Consistent directory structure. Every checkout follows the same pattern, making scripts and editor configurations simpler.

Setup Step-by-Step

Follow these steps to set up a bare repository with worktrees from scratch.

Setting up bare repo + worktrees
# 1. Create a parent directory for the project
mkdir ~/projects/myapp && cd ~/projects/myapp

# 2. Clone the repository as bare
git clone --bare git@github.com:you/myapp.git myapp.git

# 3. Configure the bare repo to fetch all remote branches
cd myapp.git
git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
git fetch origin

# 4. Create worktrees for the branches you need
git worktree add ../main main
git worktree add ../develop develop
git worktree add -b feature/auth ../feature-auth

The key step is number 3. By default, git clone --bare sets the fetch refspec to only the default branch. Updating remote.origin.fetch ensures you can fetch and track all remote branches.

Listing worktrees
# Verify the setup
$ git worktree list
/home/dev/projects/myapp/myapp.git   (bare)
/home/dev/projects/myapp/main        abc1234 [main]
/home/dev/projects/myapp/develop     def5678 [develop]
/home/dev/projects/myapp/feature-auth ghi9012 [feature/auth]

Pros and Cons

Pros

  • No asymmetry between “main” and “linked” worktrees — all worktrees are equal.
  • Accidentally deleting a worktree does not break the Git database.
  • Cleaner directory structure with a clear separation between the repo and the checkouts.
  • Ideal for developers who always work in worktrees and never need a default branch checkout.

Cons

  • Slightly more setup than a regular clone — you need to configure the fetch refspec manually.
  • Some tools and IDE integrations expect a regular clone and may not recognize the bare repo as a project root.
  • You cannot run git log or git statusin the bare directory — you must cd into a worktree first.
  • Team members unfamiliar with the pattern may be confused by the directory layout initially.

Directory Structure Example

A fully set up project using the bare repo pattern looks like this:

Bare repo directory layout
~/projects/myapp/
├── myapp.git/              # bare repository (Git database only)
│   ├── HEAD
│   ├── config
│   ├── objects/
│   ├── refs/
│   └── worktrees/          # metadata for linked worktrees
│       ├── main/
│       ├── develop/
│       └── feature-auth/
├── main/                   # worktree: main branch
│   ├── .git                # file pointing to myapp.git/worktrees/main
│   ├── src/
│   └── package.json
├── develop/                # worktree: develop branch
│   ├── .git
│   ├── src/
│   └── package.json
└── feature-auth/           # worktree: feature/auth branch
    ├── .git
    ├── src/
    └── package.json

When to Use This Pattern

The bare repo + worktrees pattern works best when:

  • You routinely work on multiple branches simultaneously and want every branch to be a first-class worktree.
  • You use a branching model like Git Flow where you always have main, develop, and feature branches active.
  • You want a clean separation between the Git database and your working directories.
  • You are setting up a new project from scratch and can adopt the pattern from day one.

If you already have a regular clone with linked worktrees and it works for you, there is no need to convert. The bare repo pattern is an alternative, not a requirement.

Related Guides