How to convert a normal Git repository to a bare one?

Viewed 250576

How can I convert a 'normal' Git repository to a bare one?

The main difference seems to be:

  • in the normal Git repository, you have a .git folder inside the repository containing all relevant data and all other files making up your working copy

  • in a bare Git repository, there is no working copy and the folder (let's call it repo.git) contains the actual repository data

18 Answers

In short: replace the contents of repo with the contents of repo/.git, then tell the repository that it is now a bare repository.

To do this, execute the following commands:

cd repo
mv .git ../repo.git # renaming just for clarity
cd ..
rm -fr repo
cd repo.git
git config --bool core.bare true

Note that this is different from doing a git clone --bare to a new location (see below).

Your method looks like it would work; the file structure of a bare repository is just what is inside the .git directory. But I don't know if any of the files are actually changed, so if that fails, you can just do

git clone --bare /path/to/repo

You'll probably need to do it in a different directory to avoid a name conflict, and then you can just move it back to where you want. And you may need to change the config file to point to wherever your origin repo is.

Here is the definition of a bare repository from gitglossary:

A bare repository is normally an appropriately named directory with a .git suffix that does not have a locally checked-out copy of any of the files under revision control. That is, all of the Git administrative and control files that would normally be present in the hidden .git sub-directory are directly present in the repository.git directory instead, and no other files are present and checked out. Usually publishers of public repositories make bare repositories available.

I arrived here because I was playing around with a "local repository" and wanted to be able to do whatever I wanted as if it were a remote repository. I was just playing around, trying to learn about git. I'll assume that this is the situation for whoever wants to read this answer.

I would love for an expert opinion or some specific counter-examples, however it seems that (after rummaging through some git source code that I found) simply going to the file .git/config and setting the core attribute bare to true, git will let you do whatever you want to do to the repository remotely. I.e. the following lines should exist in .git/config:

[core]
    ...
    bare = true
...

(This is roughly what the command git config --bool core.bare true will do, which is probably recommended to deal with more complicated situations)

My justification for this claim is that, in the git source code, there seems to be two different ways of testing if a repo is bare or not. One is by checking a global variable is_bare_repository_cfg. This is set during some setup phase of execution, and reflects the value found in the .git/config file. The other is a function is_bare_repository(). Here is the definition of this function:

int is_bare_repository(void)
{
    /* if core.bare is not 'false', let's see if there is a work tree */
    return is_bare_repository_cfg && !get_git_work_tree();
} 

I've not the time nor expertise to say this with absolute confidence, but as far as I could tell if you have the bare attribute set to true in .git/config, this should always return 1. The rest of the function probably is for the following situation:

  1. core.bare is undefined (i.e. neither true nor false)
  2. There is no worktree (i.e. the .git subdirectory is the main directory)

I'll experiment with it when I can later, but this would seem to indicate that setting core.bare = true is equivalent to removeing core.bare from the config file and setting up the directories properly.

At any rate, setting core.bare = true certainly will let you push to it, but I'm not sure if the presence of project files will cause some other operations to go awry. It's interesting and I suppose instructive to push to the repository and see what happened locally (i.e. run git status and make sense of the results).

Added 2:
After writing the answer realized that accepted answer would likely result in the same result on my PC if followed by git add *.

I got files disappear from my working folder (only .git left), it is again nice and compact by:

git switch --orphan some_new_branch_name 

Then convert to bare if one wants to:

git config --bool core.bare true

That way config including remote link is kept:

$ git config --list
core.repositoryformatversion=0
core.filemode=true
core.bare=true
remote.origin.url=https://github.com/vmatare/thinkfan.git
remote.origin.fetch=+refs/*:refs/*
remote.origin.mirror=true

Added:
In the comments it is mentioned that it would not remove "any git-ignored files", it such case they need to be additionally deleted manually (or repository itself that is .git subfolder be moved elsewhere).

Notes:
Before core.bare true some actions resulted in errors:

$ git fetch --all
Fetching origin
fatal: Refusing to fetch into current branch refs/heads/devel of non-bare repository
error: Could not fetch origin

some_new_branch_name have not been listed in output of git branch after that. To test further I did git checkout master I got files back and again no some_new_branch_name in output of git branch, so I think new orphan branch would not be added to repository unless some work is done there (and / or commits performed).

Wow, it's simply amazing how many people chimed in on this, especially considering it doesn't seem that not a single on stopped to ask why this person is doing what he's doing.

The ONLY difference between a bare and non-bare git repository is that the non-bare version has a working copy. The main reason you would need a bare repo is if you wanted to make it available to a third party, you can't actually work on it directly so at some point you're going to have to clone it at which point you're right back to a regular working copy version.

That being said, to convert to a bare repo all you have to do is make sure you have no commits pending and then just :

rm -R * && mv .git/* . && rm -R .git

There ya go, bare repo.

Related