50

I have a server on which I have a bare repository for pushing. However, my server needs to have a working copy of the master branch.

How do I get a working copy and that only from a bare repository?

Jonathan Allard
  • 18,429
  • 11
  • 54
  • 75

8 Answers8

59

You can simply clone the repository to another directory on the same machine:

git clone /bare/repo/dir

The current directory will become a non-bare clone of your repo, and you'll get a checkout of the master branch automatically. Then use the usual commands like git pull to update it as needed.

As a side benefit, this operation is very efficient — if you specify a local directory to git clone, git will use hard links to share the read-only parts of the object databases of the two repos.

user4815162342
  • 141,790
  • 18
  • 296
  • 355
  • 1
    What kind of updates? The cloned repository is just another clone, so its working tree would need to be updated using `git pull`. If you need this to happen automatically, you could arrange the server's `post-receive` hook to run a `git pull` on the clone. – user4815162342 Sep 16 '12 at 21:09
  • Oh right, obviously. I was thinking in terms of "clone" too much. – Jonathan Allard Sep 16 '12 at 21:11
  • 1
    The target bare directory may not end in `.git` , in which case `git clone /bare/repo/dir` is all you need. – here Apr 18 '14 at 06:31
  • Note -- I had to manually add the local flag, e.g. `git clone --local /bare/repo/dir` otherwise I got a bare repository. YMMV. – Brian Dec 28 '21 at 20:54
  • 1
    @Brian I cannot reproduce this with git 2.17.1. I created a repository `x` with just one commit (that adds a file), then I cloned it to a bare repository `y` using `git clone --bare x y`. After verifying that `y` was now a bare repo, I finally executed `git clone y z`. This resulted in a non-bare `z` repo, i.e. one where the `master` branch was checked out. As for `--local`, the manual even explicitly says that "if the repository is specified as a local path [which is the case in this answer], this [behavior specified by --local] is the default, and --local is essentially a no-op." – user4815162342 Dec 28 '21 at 21:24
  • I am using "git version 2.27.0.windows.1" which is the one that didn't make a working repo in e.g. "z". Possibly windows version could be screwily misinterpreting the /bare/repo/dir that I used (e.g. "c:\projects\workfolder") and failing to automatically add --local for example. My linux-based friends who I was chatting with at the time were similarly appalled at this behavior :) Anyway I note it in case some other poor Windows victim falls prey... – Brian Dec 28 '21 at 22:31
  • 1
    @Brian Even if this were the case, I wouldn't expect `--local` to affect whether the repository is bare or it contains a checkout of the working tree. Strange... – user4815162342 Dec 28 '21 at 22:35
26

A bare repository is just the .git directory of a working directory, and an entry in the local config file. What I did to convert a bare repository into a full one is:

  • Create a new subdirectory .git and move all files from the bare repository in there
  • Edit the .git/config file to change bare = true to bare = false
  • Check out the branch you want. This extracts all files from the repository into the working directory.

You could set the Hidden attribute on the .git directory on Windows, but not on the files inside the directory.

ygoe
  • 18,655
  • 23
  • 113
  • 210
  • 1
    Slightly more streamlined version [here](https://archive.kernel.org/oldwiki/git.wiki.kernel.org/index.php/Git_FAQ.html#How_do_I_clone_a_repository_with_all_remotely_tracked_branches.3F): `git clone --bare whereIwantIt/.git ; cd whereIwantIt ; git config --bool core.bare false ; git checkout anyBranch` – Cole Aug 15 '23 at 05:51
21

I was looking for the "detached working tree" approach (as seen here):

git init --bare

git config core.bare false
git config core.worktree /somewhere/else/

git checkout -f
Elijah Lynn
  • 12,272
  • 10
  • 61
  • 91
Jonathan Allard
  • 18,429
  • 11
  • 54
  • 75
  • 5
    Note that you need to run the `core.bare` before the `core.worktree` line, as noted in that blog post's comments (and confirmed by me just now). Otherwise you'll get the error `fatal: core.bare and core.worktree do not make sense`. – craigpatik Feb 07 '14 at 15:21
  • Weird, so did I: https://gist.github.com/joallard/8871673. Maybe the behavior in Git changed at some point? – Jonathan Allard Feb 07 '14 at 20:57
  • This looks like it's *close* to what I need, but your link is broken and the commands given above aren't really explained enough that I can adjust them for my needs. Can you fix the link and/or explain what's going on there? – Wildcard Dec 07 '15 at 18:54
  • @Wildcard Hit me up in [chat](http://chat.stackoverflow.com/rooms/97232/git) this afternoon, I'll try to figure it out with you and update my answer to be more complete. (Otherwise you can leave me an email, it's on my Github profile) – Jonathan Allard Dec 07 '15 at 20:09
  • 1
    Thank you for the offer! :) I think I found what I needed. I didn't find it on SO, so after I figured it out I posted about it here: http://stackoverflow.com/a/34143072/5419599 – Wildcard Dec 07 '15 at 21:01
  • @craigpatik I was getting the "do not make sense", thanks for your comment, I edited the answer and swapped worktree with bare. – Elijah Lynn Sep 01 '18 at 23:22
11

This works for me:

git --git-dir=path-to-bare-repo.git --work-tree=path-to-target checkout master .

this command will extract all files from the repository to the directory specified by path-to-target

Tomas
  • 1,531
  • 1
  • 16
  • 22
5

This is how it works:

$ git init --separate-git-dir /path/to/existing-bare-repository /path/to/workdir
$ cd /path/to/workdir
$ git checkout .

Voilà!

For info: git init will report: Reinitialized existing Git repository in /path/to/existing-bare-repository. But be confident. man git-init says: Running git init in an existing repository is safe. It will not overwrite things that are already there.

The magic is that git init alone does not make your files appear in the working directory. You have to checkout the root directory.

Adrian W
  • 4,563
  • 11
  • 38
  • 52
  • ** WARNING** I just tried this with a copy of the bare repo. I got this: $ diff /path/to/the/real/prod/bare/repo.git/config /path/to/the/copy/prod/bare/repo.git/config 4c4,5 < bare = true --- > bare = false > logallrefupdates = true $ git --version git version 2.20.1 You may want to use a copy of the bare, not the bare itself. – mpersico Apr 18 '19 at 14:55
  • The command converts the raw repository to a repository with a checkout directory. I.e. the repository is no longer bare. So, your observation is an intended effect of this command. But may be it is good to point this out. Compare to the answer of @jonathan, which obtains the same effect by explicitly applying the config changes you have observed. – Adrian W Apr 18 '19 at 16:36
  • I thought the idea was just to get a copy of the files it actually convert the repo. Now I know. – mpersico Apr 20 '19 at 14:43
  • In my understanding of git, a bare repo is one without working directory. If you attach a working directory to a formerly bare repository, it is no longer bare, no matter by which means you achieve this. And since OP (@Jonathan) [answered his own question](https://stackoverflow.com/a/12548255) with _I was looking for the "detached working tree" approach_, this was apparently his intention. I only wanted to present a way which is IMHO more elegant, because it does not need to fiddle with configuration bits. – Adrian W Apr 20 '19 at 19:32
4

This is a riff off the other 2 answers but it fills the gap for my use case -- it works for updating the repo from the origin and checking out branches and any git operation because you end up with a normal complete git repo.

git clone /path/to/bare/repo /new/path/to/full/repo
cd /new/path/to/full/repo
git remote set-url origin git@github.com:swift/swift.git

After executing these 3 lines of code you can then git pull and git branch and git checkout some_branch and so on because you now have a normal complete git repo connected to your remote repo.

GregT
  • 2,194
  • 2
  • 19
  • 15
  • your the only one who mentioned some_branch, you should elaborate. i was specifically trying to find an example for branch, and this one was hot on google for branch, and is part of OQ. ... – blamb Aug 30 '16 at 04:43
3

Also consider using

https://git-scm.com/docs/git-worktree

it should allow to create a local working copy from a bare repo without the need of cloning it (this can save space if the repo is a big one)

2

You can use 'git show' for this.

http://www.kernel.org/pub/software/scm/git/docs/git-show.html

Basically:

git --no-pager --git-dir /path/to/bar/repo.git show branch:path/to/file.txt
kaartic
  • 523
  • 6
  • 24
Ben Martin
  • 1,470
  • 2
  • 13
  • 16