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 [email protected]: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 does not set up remote-tracking branches under refs/remotes/origin/*, so branches are not tracked in the conventional way. Setting 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 status in the bare directory (it requires a working tree). Commands like git log work fine, but most workflows require a worktree.
  • 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.

You Might Also Like