Earlier this year I bought a new Mac mini for various reasons. One of the big ones was so I would have a place to stash private git repositories that I didn't want to host on 3rd party services like Github or Bitbucket. This post describes how I set up Gitolite and my own hook scripts, including how I mirror my git repos on S3 using JGit.
Step 1: Install Gitolite
Gitolite is a system for managing git repositories using git itself to manage the configuration. Essentially, after initial configuration you make all changes by editing a config file, committing it, and pushing up to your git server.
Gitolite installation is pretty straightforward:
- Install git on your server. On a Mac the easist way is to use Homebrew. On Ubuntu or Debian
apt-get install git-core. Redhat systems are similar.
- Create a user named
- Login as the
- Remove any existing
- Put your public key in a file named
your_name.pub. Mine is called
~/binis in your
Run these commands in the
gituser's home directory:
$ git clone git://github.com/sitaramc/gitolite $ mkdir -p $HOME/bin $ gitolite/install -to $HOME/bin $ gitolite setup -pk YourName.pub
Move to your workstation and run this command:
$ git clone git@your_server:gitolite-admin
If everything has gone well you'll be able to clone that repo without being asked for a password. There are a ton of things you can do with Gitolite and I don't have room to get into it here. Check out the README on Github and the extensive documentation for more instructions and details on how exactly Gitolite processes things.
Step 2: Write some hooks
Well, not really. You can use mine if you want, if they suit your goals. I wanted to hit a few different areas with my git server:
Simple, flexible mirroring and backups
One of the big things that I was paying Github for was to serve as an off-site repository backup. If for some reason I lost my laptop, my various projects and businesses would be safe because the code was also at Github. But what if I could just push to S3? Amazon S3 is far more cost effective if all you need is a place to shove files, and it so happens that the JGit project lets you use an S3 bucket as a remote.
Simple to use pre- and post-receive hooks
My hook scripts let you set up a pre- or post-receive hook directly in your Gitolite config with an optional branch filter regex.
One of the other things I do with my Mac mini is run a customized reporting application on top of my Ledger file, which contains close to six years of personal finance data. The reporting application runs on top of a postgresql database which I load with the combination of a local clone of my finances repo and a post-receive hook that starts the dump and load.
So those are my hooks. If you want to use them, clone the repo onto your server and copy or symlink
You'll also need to modify your
$GITUSER_HOME/.gitolite.rc file slightly. Add these lines somewhere
toward the top of the
GIT_CONFIG_KEYS => '.*', AUTH_OPTIONS => 'no-port-forwarding,no-X11-forwarding,no-pty',
The first line allows the config file to contain any git config options you want. The second removes
the default agent forwarding restriction to allow you to push to remote repos using the
mirrors configuration described below. If you aren't going to be using my script's mirrors you don't need to add that line.
If you want to push to S3 buckets, you'll need to create a file named
.jgit in the
home directory with these contents:
accesskey: YOUR-AWS-ACCESS-KEY secretkey: YOUR-AWS-SECRET-KEY
S3 mirror URLs follow the format
amazon-s3://<filename>@<s3-bucket-name>/<repo_name>.git. See below
for an example.
Step 3: Profit
Here's my gitolite config after installing my hooks:
repo @all config mirrors.s3 = "amazon-s3://.jgit@my-s3-bucket/%GL_REPO" repo gitolite-admin RW+ = peter repo CREATOR/[a-zA-Z0-9].* C = @all RW+ = CREATOR RW = WRITERS R = READERS gitweb repo apps/[a-zA-Z0-9].* C = @all RW+ = CREATOR config hooks.pre = '/usr/local/var/dokuen/bin/dokuen-deploy' repo financials-master RW+ = peter config hooks.clone.path = "/usr/local/var/repos/financials" config hooks.post = "sudo -u peter /usr/local/var/dokuen/bin/dokuen run_command rake load --application=ledger" repo peter/git-hooks config mirrors.github = "firstname.lastname@example.org:peterkeen/git-hooks.git" repo peter/bugsplat config mirrors.github = "email@example.com:peterkeen/bugsplat.rb" config mirrors.heroku = "firstname.lastname@example.org:bugsplat.git"
At the top, every repo gets transparently mirrored to my S3 bucket.
replaced with the actual path of the repo. After some boilerplate about the
repo comes the meat of the config. I use a gitolite feature called Wild Repos which will
automatically create a repo matching the pattern (in this case
first time I push to it. The
apps entry is the exact same idea with the addition of a
pre-commit hook that fires off my Dokuen deploy script.
I described the
financials-master repo earlier. After that is some additional config
for a few auto-created repos. Gitolite stacks your configurations together which is what
lets me get away with only specifiying the mirror config. Everything else is in the
wild repo definiton.
Running a private git server probably isn't for everyone but for me, it allows me to have a huge amount of flexibility in how I set up my repos. It's also been basically maintenance free with the exception of some small config changes here and there.