Bare Repositories

Bare Repositories

A bare repository has no working tree — only the Git internals (objects, refs, config). It is the standard layout for central repositories that multiple developers push to. Hosting services like GitHub and GitLab store every repository as bare on the server.

For the theory behind bare vs non-bare repositories, see Building Blocks.

Create a bare repository

$ git init --bare project.git
Initialized empty Git repository in /home/user/project.git/

The .git suffix is a convention, not a requirement — it signals that the directory is a bare repository.

Compare the layouts

# Bare — no working tree, internals at the top level
project.git/
├── HEAD
├── config
├── hooks/
├── objects/
└── refs/

# Non-bare — working tree + .git folder
project/
├── .git/
│   ├── HEAD
│   ├── config
│   ├── hooks/
│   ├── objects/
│   └── refs/
└── README.md

In a bare repository, what normally lives inside .git/ sits at the top level. There is no place to check out files.

Use a bare repository as a local remote

This is the most common use case — simulate a central server on your own machine for practice or local collaboration.

# 1. Create the bare (central) repository
$ git init --bare /tmp/central.git

# 2. Clone it into a working copy
$ git clone /tmp/central.git /tmp/dev-alice
$ cd /tmp/dev-alice

# 3. Make a commit and push
$ echo "Hello" > greeting.txt
$ git add greeting.txt
$ git commit -m "Add greeting"
$ git push origin main

# 4. Clone again to simulate a second developer
$ git clone /tmp/central.git /tmp/dev-bob
$ cd /tmp/dev-bob
$ cat greeting.txt
Hello

Both clones push to and pull from the same bare repository, exactly like working with GitHub.

Convert a non-bare repository to bare

$ git clone --bare project project.git

This copies only the Git data — no working tree files. The result is a bare repository you can use as a central remote.

You can also convert in place:

$ cd project
$ mv .git ../project.git
$ cd ..
$ rm -rf project
$ cd project.git
$ git config --bool core.bare true

Clone a bare repository

$ git clone --bare https://github.com/user/project.git

Useful for creating mirrors or backup copies that do not need a working tree.

Push to a non-bare repository (and why it fails)

Pushing to a non-bare repository is rejected by default:

$ git push /tmp/dev-alice main
remote: error: refusing to update checked out branch: refs/heads/main

Git refuses because a push updates the branch reference but not the working tree — this would leave the two out of sync and could cause the recipient to unknowingly revert the pushed changes on their next commit. For a full walkthrough of the problem, see Building Blocks — Why bare repositories exist.

If you need to accept pushes on a non-bare repository (rare), you can enable it:

$ git config receive.denyCurrentBranch updateInstead

This tells Git to update both the branch and the working tree on push. Use this only for special setups like deployment targets — not for regular development.

Gotchas

On this page