Git: "Bare" repos
Back to git.
A "bare" Git repo is the cornerstone to any "forge" or other central Git repository. But there’s nothing complex about it! It’s just the ".git" directory without a workspace. You don’t (in fact, can’t) do any development in a bare repo, you just clone from it, pull from it, or push to it.
By convention, a bare repo has ".git" in the directory name, like foo.git
.
You make one like this:
$ mkdir foo.git $ cd foo.git $ git init --bare
It does not need to be hosted on another computer, but it can be.
To be able to push to this repo, you’ll need to add it to the
.git/config
file in your development repo.
This is added to .git/config
to push to a bare repo on the same computer:
[remote "origin"] url = /home/dave/repos/foo.git fetch = +refs/heads/*:refs/remotes/origin/*
This is added to .git/config
to push to a bare repo on a remote computer
called "deimos" via SSH:
[remote "deimos"] url = ssh://deimos/home/dave/foo.git
Now you can just do this to push changes from your local repo:
$ git push
To be able to pull from this repo easily may require you to setup the
default parameters for fetch
. Here’s an example for pulling from a local
directory on the same local computer, but the fetch
params would be the same
for a remote computer:
[remote "origin"] url = /home/dave/repos/foo.git fetch = +refs/heads/*:refs/remotes/origin/*
Now you can pull changes to your local repo:
$ git pull
NOTE: If you create a repo by cloning from your bare repo, Git will
automatically setup the [remote]
section in the .git/config
file for you!
Another really cool thing about setting up your own bare repos is that you can easily push to a bunch of different computers (or directories) by name. For example, if I wanted to make a "test" destination, I could make a remote section for it like so:
[remote "test"] ...
And push to it like so:
$ git push test
There’s a billion options for all of this, but that’s the gist of it.
(Aside: I realized I’d written my clearest explanation about bare repos (third time’s the charm, right?) in my super-easy-2-stage-git-deployment card. So that’s where some of the above text comes from. My original explanation, followed by more about my home setup for personal projects follows below.)
Host your own Git repos!
In short, you do not need a massive Git forge service like Microsoft GitHub to be able to clone/push/pull repos on your local network or a remote computer you own somewhere.
All you need is SSH access and what is known as a "bare" repo.
"Bare" repos are what the forge services host for you. The big difference between a bare repo and normal repo is that there’s no workspace in the bare repo. It just contains the Git files. You don’t work on your project in the bare repo. A bare repo also has no "origin" because, presumably, it is the origin for your clones.
(As with anything Git, this is surely an oversimplification, but that understanding is all I’ve ever needed. So far.)
A script to automate the process
(For a fuller story about my home computing setup, see: Personal Linux Setup with Git Repos and Stow.)
I could describe how I set these up, but I wrote a script to automate it today and that’s even better.
-
This uses
ksh
because it’s available on both OpenBSD and Slackware. -
I’m pretty sure you can probably run this with Bash with no changes.
-
I have a working project directory at
~/proj
and my bare repos are stored at~/repos
. -
To clone a repo from this machine, I just do
git clone phobos:repos/<project>.git
-
The
<project>.git
naming scheme for the bare repos is just a convention I’m following. I think it’s pretty standard.
If you can read a shell script, you can see the whole process here:
#/bin/ksh if [[ -z $1 ]] then echo "Usage: $0 <project-name>" exit 1 fi echo "'$1' shall exist!" # create bare repo: bare_repo="$HOME/repos/$1.git" echo "Creating bare repo at $bare_repo..." cd $HOME/repos git init --bare $1.git # clone to projects: cd $HOME/proj git clone $bare_repo cd $1 echo "# $1" > README.md git add README.md git commit -m 'Initial commit' git push echo "Done creating '$1'. Project dir at: '$HOME/proj/$1'"
I think it’s pretty clear how this works, but in short:
-
A bare repo is created in
~/repos/
-
It is cloned into
~/proj/
-
A stub README.md is created and committed
-
The new commit is pushed back to the bare repo origin