Git Repository: Bare and Non-bare Repositories

Posted August 27, 2013 - 3 min read
Topics:  

While I was setting up a Git remote repository and testing it, for some reason, I was not able to push my work to the repository.

remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsistent
remote: error: with what you pushed, and will require 'git reset --hard' to match
remote: error: the work tree to HEAD.
remote: error:
remote: error: You can set 'receive.denyCurrentBranch' configuration variable to
remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into
remote: error: its current branch; however, this is not recommended unless you
remote: error: arranged to update its work tree to match what you pushed in some
remote: error: other way.
remote: error:
remote: error: To squelch this message and still keep the default behaviour, set
remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.

After some research, it turned out that Git (starting with version 1.7.0) has two type of repositories: bare and non-bare.

Ideally in a distributed revision control system any local repository can be served as a remote one.

Developers just pull their code from what ever repository they want and there are no pushes.

Of course changes can be transferred between local repositories, but the correct way to do it is rather than pushing changes from a remote repository to a local one, we pull changes from the remote one.

In the real world, a central repository is sometimes needed that a number of people can push to. Git allows this of course but with a little exception.

In Git we can not push to a repository unless it’s a bare repository.

Imagine that our non-bare repository would receive pushes. Then each time we run

$git status

We would get different results! The output of git status should remain the same unless we made some changes in our working tree.

Normally when you create a local repository, this called non-bare repository, you run the following commands:

$mkdir repository
$cd repository
$git init

A local repository contains both the revision history stored under .git directory and the working tree.

However, a central repository, bare repository, is created using the same commands but width a little difference.

$mkdir repository
$cd repository
$git init --bare

A bare repository in Git does not contain the working tree. Think of it like as a backup repository.

The working tree is only needed when we are working on our local repository, because we need to make changes to it!

So we should NEVER push our changes to a repository having a working tree, unless we really know what we are doing.

After creating a bare repository, we can then clone it and push back into without any problems.

You may be asking, how we can turn a non-bare repository to a bare one?

$git clone --bare -l my_non-bare_repository my_bare_repository