Gitolite quick and dirty mirror

Tue, 5 May, 2012 (500 Words)

I’m running a gitolite instance on my personal server to manage my repositories (personnal, private or public) ; and I am quickly going to share with you how I setup a quick and dirty mirror feature.

First, I am using gitolite 3. The mirroring we are going to setup is not the supported mirroring built-in. We are going to implement a simplier way to set mirror thing :

  1. Write a custom gitolite command ; the idea is to be able to write git-config stuff.
  2. Write a hook that take a specific git-config (let say mirror.url) and do a simple mirroring.

Gitolite commands

Gitolite 3 has been rewritten to be more flexible : Why a completely new version. The rewrite made it really easy to extend gitolite. I’ve fork gitolite on github I’ve created a repository git to easily add commands to my gitolite instance via local code. The gitolite command I wrote is a quick and dirty script in shell to add git config. The source should speek for itself ; It should include some way to check if the given config is not already present in the gitolite-admin configuration file — and so might be rewritten in Perl.

The command is write-git-config because a git-config command already exists in the built-in commands.

#!/bin/sh # Usage: ssh git@host write-git-config # # Set git-config value for user-created ("wild") repo. die() { echo "$@" >&2; exit 1; } usage() { perl -lne 'print substr($_, 2) if /^# Usage/../^$/' < $0; exit 1; } [ -z "$1" ] && [ -z "$2" ] && [ -z "$3" ] && usage [ "$1" = "-h" ] && usage [ -z "$GL_USER" ] && die GL_USER not set # ---------------------------------------------------------------------- repo=$1; shift key=$1; shift value=$1; shift # this shell script takes arguments that are completely under the user's # control, so make sure you quote those suckers! if gitolite query-rc -q WRITER_CAN_UPDATE_DESC then gitolite access -q "$repo" $GL_USER W any || die You are not authorised else gitolite creator "$repo" $GL_USER || die You are not authorised fi # if it passes, $repo is a valid repo name so it is known to contain only sane # characters. This is because 'gitolite creator' return true only if there # *is* a repo of that name and it has a gl-creator file that contains the same # text as $GL_USER. configfile=`gitolite query-rc GL_REPO_BASE`/"$repo".git/config git config --file "$configfile" "$key" "$value"

Gitolite hooks

The next step is to write a quick post-receive hook that check if there is a certain git-config entry and run git push --mirror. The file is in $HOME/.gitolite/hooks/common/post-receive ; you could add a better system to hooks (to be able to add “dynamic” hooks, …).

#!/bin/sh # Simple gitolite mirroring # flush STDIN coming from git, because gitolite's own post-receive.mirrorpush # script does the same thing [ -t 0 ] || cat >/dev/null [ -z "$GL_REPO" ] && die GL_REPO not set target=`git config --get mirror.url` [ -z "$target" ] && exit 0 # Support a REPO variable for wildcard mirrors gl_repo_escaped=$(echo $GL_REPO | sed 's/\//\\\//g') target=$(echo $target | sed -e "s/REPO/$gl_repo_escaped/g") # Do the mirror push git push --mirror $target

The next, and final step is to run gitolite compile to update links to hooks for every repositories.

For real

And finaly, this is the final step you’ll do.

$ ssh git@host write-git-config vincent/vcsh-home mirror.url git@github.com:vdemeester/vcsh-home.git
$ git push
Counting objects: 5, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 294 bytes, done.
Total 3 (delta 2), reused 0 (delta 0)
remote: To git@github.com:vdemeester/vcsh-home.git
remote:    65681a8..701c990  master -> master
To git@host:vincent/vcsh-home.git
   65681a8..701c990  master -> master

And that should be it !

Update 2012/10/04 : Moved from gitolite fork to gitolite local code repository.