What's the -practical- difference between a Bare and non-Bare repository?
Asked Answered
H

11

285

I've been reading about the bare and non-bare / default repositories in Git. I haven't been able to understand quite well (theoretically) the differences between them, and why I should "push" to a bare repository. Here's the deal:

Currently, I'm the only one working on a project on 3 different computers, but there will be more people involved in it later, so I'm using Git for the version control. I clone the bare repo on all computers, and when I finish my modifications on one of them, I commit and push the changes to the bare repo. From what I've read, the bare repository does NOT have a "working tree", so if I clone the bare repo, I won't have a "working tree".

I'm guessing that the working tree stores the commit information, branches, etc. from the project. That wouldn't appear in the bare repo. So it seems better for me to "push" the commits to the repo with the working tree.

Then, why should I use the bare repository and why not? What's the practical difference? That would not be beneficial to more people working on a project, I suppose.

What are your methods for this kind of work? Suggestions?

Hutchings answered 4/4, 2011 at 15:38 Comment(9)
AeroCross, you can clone a bare repository to create a non-bare repository (that is, one which has a workspace). So, using git clone you can freely convert between bare and non-bare repositories.Bombardon
@Derek I knew that I could clone a non-bare to a bare, but not the other way around. Excellent little tip.Hutchings
@AeroCross: It's not about converting; it doesn't matter what's on the other end. If you run git clone --bare you'll get a bare repo, and if you run git clone, you'll get a non-bare one. Every public project that you've ever cloned (hosted on github, for example) is a bare repository on the other end.Vedic
Jefromi, I was correcting AeroCross' point, "so if I clone the bare repo, I won't have a "working tree"", so it is a kind of conversion. And not every public project must be a bare repository. It's just the typical choice because a bare repository is more space efficient since it has no working tree (it's as space efficient as any repository that has no working tree, though).Bombardon
@Derek: But the point is that, as soon as it finds the .git directory, fetching is wholly unaware of whether the remote is bare or not. It doesn't convert. It just fetches what it needs from the remote, and puts it where it should go. There's nothing to convert. That's what I was trying to emphasize to the OP. And I'm well aware that public projects don't have to be bare, but because people aren't stupid, they essentially all are. I think I made an acceptable generalization.Vedic
Jefromi, I used the term conversion as a metaphor to help AeroCross understand that Git can clone a bare repository. I understand that the repository itself (the contents of .git) does not undergo any conversion unless you count packing free objects for efficiency as a structural conversion. Certainly, Git does not convert the commit and other repository objects during cloning.Bombardon
See Push to non-bare repository which gives another excellent explanation of bare repository usage.Beachhead
Please see this article, very well explanation: I use a working directory created with git init or git clone when I want to add, edit and delete files in myproject locally on my dev machine. When I am ready, I share my local changes with a git push to a bare repository myproject.git (usually on a remote server like github.com) so other developers can access my local changes. [saintsjd.com/2011/01/what-is-a-bare-git-repository/]Madson
Read Here, saintsjd.com/2011/01/what-is-a-bare-git-repositorySprayberry
B
123

Another difference between a bare and non-bare repository is that a bare repository does not have a default remote origin repository:

~/Projects$ git clone --bare test bare
Initialized empty Git repository in /home/derek/Projects/bare/
~/Projects$ cd bare
~/Projects/bare$ git branch -a
* master
~/Projects/bare$ cd ..
~/Projects$ git clone test non-bare
Initialized empty Git repository in /home/derek/Projects/non-bare/.git/
~/Projects$ cd non-bare
~/Projects/non-bare$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master

From the manual page for git clone --bare:

Also the branch heads at the remote are copied directly to corresponding local branch heads, without mapping them to refs/remotes/origin/. When this option is used, neither remote-tracking branches nor the related configuration variables are created.

Presumably, when it creates a bare repository, Git assumes that the bare repository will serve as the origin repository for several remote users, so it does not create the default remote origin. What this means is that basic git pull and git push operations won't work since Git assumes that without a workspace, you don't intend to commit any changes to the bare repository:

~/Projects/bare$ git push
fatal: No destination configured to push to.
~/Projects/bare$ git pull
fatal: /usr/lib/git-core/git-pull cannot be used without a working tree.
~/Projects/bare$ 
Bombardon answered 4/4, 2011 at 17:11 Comment(15)
I think this is the most detailed answer I can find around. IMO, this is the most significant difference between the bare and non-bare repository, and the answer clears up perfectly the working scheme I'm using. Thanks a lot!Hutchings
Yes, I agree that this is arguably the most significant difference between bare and non-bare Git repositories. The fact that a non-bare repository has a workspace, but a bare repository does not is an important difference, but git clone --no-checkout can create a non-bare repository with no workspace files, too.Bombardon
A non-bare repository doesn't necessarily have a default remote "origin", either.Bungle
mipadi, how do yo create such a repository using git clone? As far as I understand, unless you specify --bare, git clone always creates the default remote origin. I agree, however, that after you clone a repository, you can delete the remote origin in the clone.Bombardon
You can create a Git repository simply with git init, which will create a non-bare repo with no remote specified.Bungle
mipadi, this is true, but it's also not a clone.Bombardon
This is incorrect. A repository will have a default origin if it has been cloneed. If it has been inited locally, it will not have such an origin. This has nothing to do with whether it is bare or not.Sophistry
Noufal, this is what mipadi stated a few comments before yours. I stated in a comment to mipadi's answer that you can create a non-bare repository without a checked-out working tree and both you and mipadi pointed out that you can create a non-bare repository without an origin. So what, then, is a key difference between a bare and non-bare repository?Bombardon
Great explanation of bare and non-bare repository @Derek Mahar.Infante
Now the question is how to change a bare repo into non-bare (e.g., because the original bare repo was a mirror of a remote hg repo and by cloning I would loose all information in .git/hg)?Gimmick
@DerekMahar What do you mean by default remote origin? As stated git init is non-bare and obviously has no origin (same for --bare). I would think that all cloning has an origin. Shouldn't you be checking for the origin with git remote show origin? git clone --bare <repo> clones the repo as a bare repo, meaning it is the .git directory and good notation would be instead git clone --bare <repo> <repo.git>. If you check a clone, either --bare or not, it has an origin. Bares by default rather do not allow pulling from origin (or anywhere), as stated since they have no working tree.Stepha
@NoviceC A default remote origin is a reference in the repository to the clone source. According to my example (this may have changed in later versions of Git), git clone --bare does not create a default remote origin.Bombardon
Anyway, I'm not sure why the OP accepted this answer. I was trying to provide another difference between bare and non-bare repositories. @Bungle made a good point that a new Git repository created with git init also doesn't have default remote origin. The question didn't require that the bare repository be created only with git clone.Bombardon
@DerekMahar, if I create a repo via git clone --bare originalrepo barerepo, and then issue git remote -v while in barerepo directory, I obtain origin /full/path/of/orignalrepo (fetch) and origin /full/path/of/orignalrepo (push); so I'd say barerepo has got the origin remote. Could you elaborate on this? Maybe it's about git version?Jellaba
@DerekMahar, oh, btw, when I do git clone --bare originalrepo barerepo the output on stdout is Cloning into bare repository 'barerepo'... and not Initialized empty Git repository in /full/path/of/barerepo/.Jellaba
S
105

5 years too late, I know, but no-one actually answered the question:

Then, why should I use the bare repository and why not? What's the practical difference? That would not be beneficial to more people working on a project, I suppose.

What are your methods for this kind of work? Suggestions?

To quote directly from the Loeliger/MCullough book (978-1-449-31638-9, p196/7):

A bare repository might seem to be of little use, but its role is crucial: to serve as an authoritative focal point for collaborative development. Other developers clone and fetch from the bare repository and push updates to it... if you set up a repository into which developers push changes, it should be bare. In effect, this is a special case of the more general best practice that a published repository should be bare.

Siloam answered 20/3, 2017 at 10:4 Comment(1)
So, in short (and layman's terms): "bare" means you can use push but you can't develop from within the repository, i.e. you have to use git clone instead, while non-bare is the other way around, i.e. you have a workspace within the repository folder where you edit and commit all your files, but you can't push anything in from the outside.Deathlike
B
93

The distinction between a bare and non-bare Git repository is artificial and misleading since a workspace is not part of the repository and a repository doesn't require a workspace. Strictly speaking, a Git repository includes those objects that describe the state of the repository. These objects may exist in any directory, but typically exist in the .git directory in the top-level directory of the workspace. The workspace is a directory tree that represents a particular commit in the repository, but it may exist in any directory or not at all. Environment variable $GIT_DIR links a workspace to the repository from which it originates.

Git commands git clone and git init both have options --bare that create repositories without an initial workspace. It's unfortunate that Git conflates the two separate, but related concepts of workspace and repository and then uses the confusing term bare to separate the two ideas.

Bombardon answered 4/4, 2011 at 19:23 Comment(1)
Really Good point you bring up. Would it be correct to say "A Nonbare git repository has a supplemental workspace directory tree( but A bare git repository does Not )" ?Cudlip
G
80

A bare repository is nothing but the .git folder itself i.e. the contents of a bare repository is same as the contents of .git folder inside your local working repository.

  • Use bare repository on a remote server to allow multiple contributors to push their work.
  • Non-bare - The one which has working tree makes sense on the local machine of each contributor of your project.
Georama answered 10/2, 2015 at 9:58 Comment(3)
Can't multiple contributors push their work anyway? There's no need for a bare repository. Anyway with a normal repository as well lots of people can work parallely.Grisette
@Mugen, with non bare repository you'll get an error message on your local machine trying to push to the checkouted branch.Gaily
@Deepak, then what's the point of the term bare repo? Why not just call it the normal thing with everything but the .git folder deleted? or the normal thing's .git subfolder?Pressley
A
52

A default/non-bare Git repo contains two pieces of state:

  1. A snapshot of all of the files in the repository (this is what "working tree" means in Git jargon)
  2. A history of all changes made to all the files that have ever been in the repository (there doesn't seem to be a concise piece of Git jargon that encompasses all of this)

The snapshot is what you probably think of as your project: your code files, build files, helper scripts, and anything else you version with Git.

The history is the state that allows you to check out a different commit and get a complete snapshot of what the files in your repository looked like when that commit was added. It consists of a bunch of data structures that are internal to Git that you've probably never interacted with directly. Importantly, the history doesn't just store metadata (e.g. "User U added this many lines to File F at Time T as part of Commit C"), it also stores data (e.g. "User U added these exact lines to File F").

The key idea of a bare repository is that you don't actually need to have the snapshot. Git keeps the snapshot around because it's convenient for humans and other non-Git processes that want to interact with your code, but the snapshot is just duplicating state that's already in the history.

A bare repository is a Git repository that does not have a snapshot. It just stores the history.

Why would you want this? Well, if you're only going to interact with your files using Git (that is, you're not going to edit your files directly or use them to build an executable), you can save space by not keeping around the snapshot. In particular, if you're maintaining a centralized version of your repo on a server somewhere (i.e. you're basically hosting your own GitHub), that server should probably have a bare repo (you would still use a non-bare repo on your local machine though, since you'll presumably want to edit your snapshot).

If you want a more in-depth explanation of bare repos and another example use case, I wrote up a blog post here: https://stegosaurusdormant.com/bare-git-repo/

Attenweiler answered 27/10, 2019 at 21:35 Comment(2)
The "non-bare" repo also contains the staging area #49228709 needed for ongoing developmentAuse
This answer was the most useful in understanding the difference. ThanksHuebner
B
22

A non-bare repository simply has a checked-out working tree. The working tree does not store any information about the state of the repository (branches, tags, etc.); rather, the working tree is just a representation of the actual files in the repo, which allows you to work on (edit, etc.) the files.

Bungle answered 4/4, 2011 at 15:41 Comment(2)
So that means that I can add branches, tags, etc. to the bare repository then pull from the bare to the non-bare / production repository?Hutchings
mipadi, a non-bare repository may not have a checked-out tree. This is the case if you create a non-bare repository with git clone --no-checkout. In this case, the non-bare repository has a location for the workspace, but Git doesn't checkout any files into that workspace.Bombardon
R
21

A bare repository has benefits in

  • reduced disk usage
  • less problems related to remote push (since no working tree is there to get out of synch or have conflicting changes)
Refugee answered 4/4, 2011 at 15:48 Comment(6)
So the bare repository is the best / recommended way to work with several people with no access to THEIR repositories? (Kinda like SVN?)Hutchings
AeroCross, I'd say a bare repository is a good choice for that scenario.Bombardon
I thought "n commits ahead" message was related to branches (i.e. refs) and not related to working trees.Benign
@Benign Yes, Nothing here contradicts that?Refugee
I mean if a developer makes a push to the remote repository, then all other contributors will be out of sync anyways, whether the remote is a bare or non-bare repository. Maybe I don't quite understand the meaning of "sync" in your answer.Benign
@Benign If the remote repo isn't bare, it would cause the worktree to get out of sync with a checked out HEAD as well. This is why it wouldn't be allowed, and thus the advantage of having a bare repo (basically, just don't have a worktree)Refugee
P
17

Non bare repository allows you to (into your working tree) capture changes by creating new commits.

Bare repositories are only changed by transporting changes from other repositories.

Pineda answered 2/6, 2015 at 9:24 Comment(1)
That makes sense, as the developer's workstation would have a non-bare repository & changes are git pushed into a bare repository on a server.Erlking
D
15

I'm certainly not a Git "expert". I have used TortoiseGit for a while and wondered what it was talking about when it asked me if I wanted to make a "bare" repo whenever I created one. I was reading this tutorial: https://www.atlassian.com/git/tutorials/setting-up-a-repository/git-init and it addresses the issue, but I still was not quite understanding the concept. This one helped a lot: http://bitflop.com/tutorials/git-bare-vs-non-bare-repositories.html. Now, the first one makes sense too!

According to these sources, in a nutshell, a "bare" repo is used on a server where you want to set up a distribution point. It's not intended for use on your local machine. You generally push commits from your local machine to a bare repo on a remote server, and you and/or others pull from that bare repo to your local machine. So your GitHub, Assembla, etc. remote storage/distribution repo is an example where a "bare" repo is created. You would make one yourself if you were setting up your own analogous "sharing center".

Deactivate answered 11/8, 2015 at 14:21 Comment(1)
Note: The BitFlop link no longer exists in 2022. That domain is up for sale. However, the Atlassian Bitbucket tutorial is still a useful link!Erlking
F
4

This is not a new answer, but it helped me to understand the different aspects of the answers above (and it is too much for a comment).

Using Git Bash just try:

me@pc MINGW64 /c/Test
$ ls -al
total 16
drwxr-xr-x 1 myid 1049089 0 Apr  1 11:35 ./
drwxr-xr-x 1 myid 1049089 0 Apr  1 11:11 ../

me@pc MINGW64 /c/Test
$ git init
Initialized empty Git repository in C:/Test/.git/

me@pc MINGW64 /c/Test (master)
$ ls -al
total 20
drwxr-xr-x 1 myid 1049089 0 Apr  1 11:35 ./
drwxr-xr-x 1 myid 1049089 0 Apr  1 11:11 ../
drwxr-xr-x 1 myid 1049089 0 Apr  1 11:35 .git/

me@pc MINGW64 /c/Test (master)
$ cd .git

me@pc MINGW64 /c/Test/.git (GIT_DIR!)
$ ls -al
total 15
drwxr-xr-x 1 myid 1049089   0 Apr  1 11:35 ./
drwxr-xr-x 1 myid 1049089   0 Apr  1 11:35 ../
-rw-r--r-- 1 myid 1049089 130 Apr  1 11:35 config
-rw-r--r-- 1 myid 1049089  73 Apr  1 11:35 description
-rw-r--r-- 1 myid 1049089  23 Apr  1 11:35 HEAD
drwxr-xr-x 1 myid 1049089   0 Apr  1 11:35 hooks/
drwxr-xr-x 1 myid 1049089   0 Apr  1 11:35 info/
drwxr-xr-x 1 myid 1049089   0 Apr  1 11:35 objects/
drwxr-xr-x 1 myid 1049089   0 Apr  1 11:35 refs/

Same with git --bare:

me@pc MINGW64 /c/Test
$ ls -al
total 16
drwxr-xr-x 1 myid 1049089 0 Apr  1 11:36 ./
drwxr-xr-x 1 myid 1049089 0 Apr  1 11:11 ../

me@pc MINGW64 /c/Test
$ git init --bare
Initialized empty Git repository in C:/Test/

me@pc MINGW64 /c/Test (BARE:master)
$ ls -al
total 23
drwxr-xr-x 1 myid 1049089   0 Apr  1 11:36 ./
drwxr-xr-x 1 myid 1049089   0 Apr  1 11:11 ../
-rw-r--r-- 1 myid 1049089 104 Apr  1 11:36 config
-rw-r--r-- 1 myid 1049089  73 Apr  1 11:36 description
-rw-r--r-- 1 myid 1049089  23 Apr  1 11:36 HEAD
drwxr-xr-x 1 myid 1049089   0 Apr  1 11:36 hooks/
drwxr-xr-x 1 myid 1049089   0 Apr  1 11:36 info/
drwxr-xr-x 1 myid 1049089   0 Apr  1 11:36 objects/
Foodstuff answered 3/4, 2018 at 9:52 Comment(0)
C
3

$ git help repository-layout

A Git repository comes in two different flavours:

  • a .git directory at the root of the working tree;
  • a .git directory that is a bare repository (i.e. without its own working tree), that is typically used for exchanging histories with others by pushing into it and fetching from it.
Chrysotile answered 2/12, 2018 at 16:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.