How do I convert a bare git repository into a normal one (in-place)?

GitGit Bare

Git Problem Overview


I have a bare git repository, but need to access and browse its contents over ssh (in a file manager like user experience).

I assume I could clone it:

git clone -l <path_to_bare_repo> <new_normal_repo>

However, my repository is about 20GB in size and I don't have the space to duplicate it. Is there a way to convert the bare repository in-place to end up with a working copy in it?

Git Solutions


Solution 1 - Git

Note: I tested this on a very simple 1-commit repository. Double-check this, read the man pages, and always be happy you've backed up before following advice you found on StackOverflow. (You do back up, right?)

To convert a --bare repository to a non-bare:

  1. Make a .git folder in the top-level of your repository.
  2. Move the repository management things (HEAD branches config description hooks info objects refs etc.) into the .git you just created.
  3. Run git config --local --bool core.bare false to convert the local git-repository to non-bare.
  4. (via comment by Tamás Pap) After step #3 you will see that you are on branch master (or whichever your main branch is) and all your files are deleted and the deletion is staged. That's normal. Just manually checkout master, or do a git reset --hard, and you are done.
  5. (to resolve issue reported by Royi) Edit .git/config file adding line fetch = +refs/heads/*:refs/remotes/origin/* after url = <...> in [remote "origin"] section. Otherwise git fetch will not see origin/master and other origin's branches.

These steps are in the opposite direction of this question, "git-convert normal to bare repository" - in particular note this answer, which states that the above steps (in, I presume, either direction) is different from doing a git-clone. Not sure if that's relevant to you, though, but you mentioned git clone in the question.

Solution 2 - Git

I had a slightly different scenario:

Solution:

  • clone a bare repo in that content, in a .git dir:
    git clone --bare https://github.com/user/project .git
  • Mark it as a non-bare repo:
    git config --local --bool core.bare false
  • reset the index (otherwise, it believes everything has been deleted, since a .git bare repo doesn't include a file 'index'.)
    git reset HEAD -- .
    That restores the .git/index.

I have effectively transformed a bare repo into a non-bare one, while preserving the content I had previously got.
The full script I have been using for years involves the steps:

cd /path/to/current/worktree

# That creates a .git directly at the right place
git clone --bare /url/of/repo .git

# restore the link between the local repo and its upstream remote repo
git config --local --bool core.bare false
git config --local remote.origin.fetch +refs/heads/*:refs/remotes/origin/*
git fetch origin
git branch -u origin/master master

# reset the index (not the working tree)
git reset HEAD -- .

But I do recon the accepted solution (with the helpful git reset step added by ADTC) is simpler.

Solution 3 - Git

The original poster's question is about not having enough space to do things the simple way. For those that do have enough space, the answer is far simpler:

git clone foo.git foo

Solution 4 - Git

To simplify and combine the information in the answers:

There are three differences that make a bare repo different from a normal .git folder:

  • core.bare is set to true in config file
  • index file and working tree do not in exist
  • a default refspec for the "origin" remote is not generated

So, you can simply move your bare repo to be the .git subfolder of a new folder,

mkdir clone
mv bare.git clone/.git

Change core.bare:

cd clone
git config --local --bool core.bare false

Add a default origin refspec to make git fetch and git push pick the same defaults as usual:

git config remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'

And generate the index file and working tree:

git checkout master

I recommend git checkout rather than git reset to generate the files, in case it is accidentally typed into the wrong place.

Solution 5 - Git

If you are low on diskspace, expanding the working tree by converting to a normal repository will be an issue, but you can browse the contents of a bare repo without converting it. Use git cat-file -p <commit-sha> on any commit to see the tree to which it refers. Use git cat-file -p <blob-sha> to see the contents of the file referenced by the blob. Use git show <sha>:path where sha is either a commit or a tree to see the contents of the blob at path.

Solution 6 - Git

cd into bare repo and do

  1. Either:
git config core.bare false
git reset --hard
  1. Or
git clone X.git X

(will give you regular git repo that named X)

Solution 7 - Git

If you don't mind working on different worktree , then

git worktree add ../repo2
cd ..
git status # now works fine

Please note, this is not a clone.

Solution 8 - Git

Push-to-Deploy

Rather than convert the bare remote into a standard repository, you can use the post-receive script in the hooks directory to expand the repository into a deployment directory.

Here is a good example of setting up Push-to-Deploy

For ease of reference, this is the script contents example from the above link. It will deploy only pushes from "master" branch to a directory named "deploy" that is on the same level as the parent directory of the repository:

#!/usr/bin/env ruby
# post-receive

# 1. Read STDIN (Format: "from_commit to_commit branch_name")
from, to, branch = ARGF.read.split " "

# 2. Only deploy if master branch was pushed
if (branch =~ /master$/) == nil
    puts "Received branch #{branch}, not deploying."
    exit
end

# 3. Copy files to deploy directory
deploy_to_dir = File.expand_path('../deploy')
`GIT_WORK_TREE="#{deploy_to_dir}" git checkout -f master`
puts "DEPLOY: master(#{to}) copied to '#{deploy_to_dir}'"

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionnyiView Question on Stackoverflow
Solution 1 - GitsimontView Answer on Stackoverflow
Solution 2 - GitVonCView Answer on Stackoverflow
Solution 3 - GitsarnoldView Answer on Stackoverflow
Solution 4 - GitfuzzyTewView Answer on Stackoverflow
Solution 5 - GitWilliam PursellView Answer on Stackoverflow
Solution 6 - GitnPcompView Answer on Stackoverflow
Solution 7 - GitBoaz NahumView Answer on Stackoverflow
Solution 8 - GitCapinWinkyView Answer on Stackoverflow