Kim Rudolph

Setup Gitolite with Cgit

There are several reasons why it might be necessary to migrate from Apache Subversion to git. The projects gitolite as a tool to manage git on a server and cgit as a simple and fast frontend are robust choices for a new infrastructure.

The goal is to be able to create repositories and interact with them like

$ git clone git@gitserver:my-project

and also view any changes at an read only web interface at http://gitserver/git/. A prominent example of how cgit looks is the linux kernel page.

If there is a need for a web interface which is not read only but also needs to be self controlled (e.g. behind a firewall), there are several choices. For example paid solutions like GitHub Enterprise, Atlassian Stash or non paid like gitorious or GitLab.

Hello Mr. git

To separate the git handling from the other users or services on the server, there should be a git user and a git group. That account does not need a password, it will only be accessed via ssh.

For testing this with a setup on localhost instead of an remote server, all following root@gitserver parts can be replaced with a simple sudo.

root@gitserver$ useradd --create-home --user-group git

Installing Gitolite

For short installation instructions read the official gitolite README, the steps are the following:

Create a new (ssh-keygen -t rsa) key if needed, copy the public key to the git home directory and make it readable. That public key should be the one used for the root@gitserver access. The naming of the public key (here krudolph) is important as it is the identifier for access rights configurations.

krudolph@local$ scp ~/.ssh/krudolph.pub root@gitserver:/home/git/krudolph.pub
root@gitserver$ chmod o+r /home/git/krudolph.pub 
root@gitserver$ su git
git@gitserver$ cd ~
git@gitserver$ git clone git://github.com/sitaramc/gitolite
git@gitserver$ mkdir bin
git@gitserver$ gitolite/install -to ~/bin
git@gitserver$ bin/gitolite setup -pk krudolph.pub

The user krudolph is now able to clone the gitolite-admin repository.

krudolph@local$ git clone git@gitserver:gitolite-admin

That administration repository consists of the configuration file conf/gitolite.conf and the keydir folder containing the public keys of all users. Any configuration changes are validated and performed after a git push. Groups can be defined like the @admins group below. The @all group references all users by default.

conf/gitolite.conf

@admins = krudolph

repo gitolite-admin
  RW+  =   @admins

Adding a New User

A copy of the public key needs to be put in the keydir folder and pushed. Remember to set the filename to the actual username.

krudolph@local$ git add keydir/otheruser.pub
krudolph@local$ git commit -am "Added new user: otheruser"
krudolph@local$ git push origin master

Adding a New Repository

Add the project to the gitolite configuration in the local clone of the gitolite-admin repository

conf/gitolite.conf

...
repo test-project
  RW+  =  @all

and push the configuration file. gitolite will create the bare repository for it and also add the project to the /home/git/projects.list file.

Installing Cgit

The cgit frontend runs as a cgi application on several HTTP servers.

git@gitserver$ git clone git://git.zx2c4.com/cgit
git@gitserver$ cd cgit
git@gitserver$ git submodule init
git@gitserver$ git submodule update
git@gitserver$ make
git@gitserver$ sudo make install

In this example, cgit will run with Apache, so that needs to be installed.

root@gitserver$ apt-get install apache2

To achieve the goal of a clean URL like http://gitserver/git/, the page configuration needs an Alias definition and also the cgit virtual-root (see below) has to be set.

/etc/apache2/conf.d/cgit.conf

Alias /git "/var/www/htdocs/cgit"

<Directory "/var/www/htdocs/cgit">
  AllowOverride all
  AddHandler cgi-script .cgi
  DirectoryIndex cgit.cgi 
  Options +ExecCGI
  Order allow,deny
  Allow from all
</Directory>

Cleaning up the Cgit Url

Apache requires the mod_rewrite module and

root@gitserver$ a2enmod rewrite
root@gitserver$ service apache2 restart

a .htaccess file at the cgit root folder to strip the /cgit.cgi/ part of the url.

/var/www/htdocs/cgit/.htaccess

RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ cgit.cgi/$1 [L]

Configuring Cgit

The following configuration file will connect the gitolite with the cgit parts and set several useful parameters. A full reference can be found at the cgitrc file.

/etc/cgitrc

# Enable /git as an URL prefix
virtual-root=/git

# Specify default clone prefix
clone-prefix=git@gitserver

# Specify the css and logo url
css=/git/cgit.css
logo=/git/cgit.png

# Show extra links for each repository on the index page
enable-index-links=1

# Enable ASCII art commit history graph on the log pages
enable-commit-graph=1

# Show number of affected files per commit on the log pages
enable-log-filecount=1

# Show number of added/removed lines per commit on the log pages
enable-log-linecount=1

# Enable statistics for a whole year
max-stats=year

# Set the title and heading of the repository index page
root-title=code center

# Set a subheading for the repository index page
root-desc=my private repositories

# Allow download of tar.gz, tar.bz2 and zip-files
snapshots=tar.gz tar.bz2 zip

# Enable pushing git configuration properties
# like a description via gitolite.conf
enable-git-config=1

# Disable pagination if there are more than 50 projects
max-repo-count=10000

# Fetch more atom feed items
max-atom-items=100

# Disable the .git suffix
remove-suffix=1

# All existing projects are fetched from the
# list maintained by gitolite
project-list=/home/git/projects.list

# Path to those listed projects
scan-path=/home/git/repositories

To enable cgit ro read the repositories, it has to have read access to the project list. No read access will lead to a No repositories found message.

root@gitserver$ chown git:www-data /home/git/projects.list

That also needs to be configured for all created projects. If a project does not show up, the access rights might be the cause.

/home/git/.gitolite.rc

...
UMASK  =>  0027,
...

Adding Descriptions to Cgit Project Overview

Git project configuration properties can be set at the local clone of the gitolite-admin repository.

conf/gitolite.conf

repo test-project
    RW+              =  @all
    config cgit.desc =  This is the test project description

gitolite will parse the configuration if it is allowed via GIT_CONFIG_KEYS.

/home/git/.gitolite.rc

...
GIT_CONFIG_KEYS                 =>  '.*',
...

Also cgit needs to know that it should read the configuration (.git/config) of each git repository.

/etc/cgitrc

enable-git-config=1

Migrating from Subversion

Importing existing svn projects in a git project requires git-svn and several mapping steps, which are comfortably wrapped in the svn2git gem.

$ apt-get install git-svn ruby rubygems
$ gem install svn2git

The following script performs an initial import in the ~/migration folder. If run again, the export will be refreshed.

The --verbose option should be set to view any details on failing updates or imports. Those might happen if the subversion projects have branches and tags with the same name. Beware that an import of large projects can take several hours, especially if it has a lot of tags and branches, the --verbose option helps to see that there is actually any progress.

As the git commits have to run through the gitolite-shell the import script needs to be started by any user that is not the the git user. The svn to git mapping is only referenced at the initial import project where the migration started. The svn2git --rebase has to be performed at that initial migration project.

#!/bin/shell

set -e

function migrate_svn_to_git
{
  project=$1
  final_name=$2
  migrationfolder=$HOME/migration
  gitoliteproject=$HOME/gitolite/gitolite-admin

  cd $migrationfolder

  # needs only an update?
  if [[ -e $final_name ]] ; then
   
    cd $final_name
    svn2git --rebase --verbose
    git push --tags --progress origin
    git push

  else

    # create repository
    cd $gitoliteproject
    git pull
    echo -e "\nrepo ${final_name}\n  RW+  =  @all" >> conf/gitolite.conf
    git commit -am "Added repository for migrated project ${final_name}"
    git push
    cd $migrationfolder
    git clone gitrepo:$final_name

    # migrate the project
    cd $final_name
    svn2git project --verbose 
    git push --tags --progress origin
    git push --all --progress origin -u

  fi
}


migrate_svn_to_git "https://subversion-server/project-name" "project-name"
migrate_svn_to_git "https://subversion-server/other-project-name" "other-project-name"