How to setup a GIT server with gitolite and gitweb

From ao2Wiki
Jump to: navigation, search

The goals are:

  • Host several projects with git and access them via ssh, with the option of adding other developers with push rights on a per-project basis.
  • Allow anonymous cloning via http and git protocols, and expose a web interface to browse the repositories.
  • Optionally enable Clean URLs also inside the web interface to the git repository. This is also what git-notify expects when creating links to commits.

Our git repositories will be administered using gitolite they will go in /home/git/repositories and our gitweb interface will be at http://git.example.com.

Basic setup

As root:

aptitude install git-core

Use a git user for anything related to git.

sudo adduser \
    --system \
    --shell /bin/bash \
    --gecos 'git SCM user' \
    --group \
    --disabled-password \
    --home /home/git \
    git

Put repositories in /home/git/repositories

sudo -u git mkdir /home/git/repositories

Configuring gitolite

Create a ssh key (anywhere you want) for gitolite administration and copy it on the server, (if you already have one that will be OK, of course):

ssh-keygen -t rsa
scp /home/myuser/.ssh/id_rsa.pub ${SERVER_IP}:myuser.pub

We assume the myuser user will administer gitolite.

On the server install gitolite and initialize it:

aptitude install gitolite
sudo -H -u git gl-setup /path/to/myuser.pub

Then, on a client machine, as the user relative to the key you used before, run:

git clone git@git.example.com:gitolite-admin.git
cd gitolite-admin/

look at the address, the git in front of @ is the user previously added to the server and git.example.com is the address of the machine hosting the git repositories (you can use the IP address if you haven't configured the DNS yet), this command will use ssh transport to transfer data, so if you have a firewall on your server it must allow ssh traffic.

Add more pubkeys in keys/ and/or edit conf/gitolite.conf as needed, see also /usr/share/doc/gitolite/gitolite.conf.mkd.gz for more details.

We now add a test repository and a group of users who can access it, the resulting conf/gitolite.conf is something like:

@secret = gitolite-admin
 
repo  @secret
  - = gitweb daemon
  option deny-rules = 1
 
repo  @all
  R = gitweb daemon
 
repo  gitolite-admin
  RW+ = myuser
 
@test_users = myuser otheruser
repo  testing
  config gitweb.owner = "Antonio Ospite"
  config gitweb.description = "Test repository"
  RW+ = @test_users

When using the @all special remember to set $GL_ALL_INCLUDES_SPECIAL = 1; in /home/git/.gitolite.rc.

Commit and push the changes, this will prepare push permissions for a repository named test on the server:

git commit -a
git push

If you get this warning:

warning: You did not specify any refspecs to push, and the current remote
warning: has not configured any push refspecs. The default action in this
warning: case is to push all matching refspecs, that is, all branches
warning: that exist both locally and remotely will be updated.  This may
warning: not necessarily be what you want to happen.
warning: 
warning: You can specify what action you want to take in this case, and
warning: avoid seeing this message again, by configuring 'push.default' to:
warning:   'nothing'  : Do not push anything
warning:   'matching' : Push all matching branches (default)
warning:   'tracking' : Push the current branch to whatever it is tracking
warning:   'current'  : Push the current branch

you can set the default push action in your git client config with:

git config --global push.default matching

Now the user has push rights, but the project does not exist yet. Create the test project, as user myuser:

mkdir test
cd test
git init
# ... do some work: REMEMEBER to "git add" the files
git commit -a
git remote add origin git@git.example.com:test.git
git push origin master:refs/heads/master
git config --add branch.master.remote origin
git config --add branch.master.merge refs/heads/master

The last two lines above set a default merging branch, avoiding the message below when pulling into the directory where the repository was firstly created (taken from http://andr.esmejia.com/posts/28-quick-remider-always-merge-from-master):

You asked me to pull without telling me which branch you
want to merge with, and 'branch.master.merge' in
your configuration file does not tell me, either. Please
specify which branch you want to use on the command line and
try again (e.g. 'git pull <repository> <refspec>').
See git-pull(1) for details.

If you want your project to be cloned anonymously via http you have to enable the post-update hook on the server:

git@git.example.com$ cd /home/git/repositories/test.git
git@git.example.com$ ln -s hooks/post-update.sample hooks/post-update
git@git.example.com$ ./hooks/post-update

however, this is not enough for cloning via http, your web server needs to be configured as well, see the gitweb section.

Note: you can skip doing the last step above for every new repository:

git@git.example.com$ ln -s /usr/share/git-core/templates/hooks/post-update.sample ~/.gitolite/hooks/common/post-update
git@git.example.com$ gl-setup

as explained in [1].

Configuring git-daemon

If you want to provide access anonymously with the git protocol, you can use git-daemon, this is not strictly required, but it is more efficient than providing anonymous access via http.

Starting from Debian Wheezy there is a git-daemon-sysvinit package, a standard init.d script to start git-daemon:

sudo aptitude install git-daemon-sysvinit

You can adjust the options passed to git-daemon in /etc/default/git-daemon, here's an example

# Defaults for git-daemon initscript
# sourced by /etc/init.d/git-daemon
# installed at /etc/default/git-daemon by the maintainer scripts
 
#
# This is a POSIX shell fragment
#
 
GIT_DAEMON_ENABLE=true
GIT_DAEMON_USER=git
GIT_DAEMON_BASE_PATH=/home/git/repositories
GIT_DAEMON_DIRECTORY=/home/git/repositories
 
# Additional options that are passed to the Daemon.
GIT_DAEMON_OPTIONS=""

Open TCP port 9418 on your firewall if needed, in my case (I have a in-new chain for new connections) the rule looks like this one:

$IPT -A in-new -p tcp -m tcp --dport 9418 --syn -j ACCEPT

Configuring gitweb

We are installing custom config for gitweb in /home/git/gitweb.

Install gitweb:

aptitude install gitweb

Write the config file.

My configuration is:

# Include the global configuration, if found.
do "/etc/gitweb.conf" if -e "/etc/gitweb.conf";
 
# Point to projects.list file generated by gitolite.
$projects_list = "/home/git/gitweb/projects.list";
 
# Where the actual repositories are located.
$projectroot = "/home/git/repositories";
 
# By default, gitweb will happily let people browse any repository
# they guess the name of. This may or may not be what you want.
# I prefer to set these, to allow exactly the repositories in
# projects.list to be browsed.
$export_ok = "";
$strict_export = "true";
 
# A list of base urls where all the repositories can be cloned from.
# Easier than having per-repository cloneurl files.
@git_base_url_list = ('git://git.example.com', 'http://git.example.com');
 
$home_text = "$projectroot/indextext.html";
 
# Just for a little more security
$prevent_xss = true;
 
# turn off potentially CPU-intensive features
$feature{'search'}{'default'} = [undef];
$feature{'blame'}{'default'} = [undef];
$feature{'pickaxe'}{'default'} = [undef];
$feature{'grep'}{'default'} = [undef];
 
# nicer-looking URLs
$feature{'pathinfo'}{'default'} = [1];
 
$my_uri = "http://git.example.com";
$home_link = "http://git.example.com";
 
$site_name = "git.example.com";

with this setup the server description is taken from /home/git/repositories/indextext.html

The Apache VirtualHost configuration is:

<VirtualHost *:80>
  ServerAdmin webmaster@localhost
  ServerName git.example.com
 
  SetEnv  GITWEB_CONFIG   /home/git/gitweb/gitweb.conf
 
  Alias /gitweb.css /usr/share/gitweb/gitweb.css
  Alias /git-logo.png /usr/share/gitweb/git-logo.png
  Alias /git-favicon.png /usr/share/gitweb/git-favicon.png
 
  ScriptAlias /cgi-bin /usr/lib/cgi-bin
 
  DocumentRoot /home/git/repositories
  <Directory /home/git/repositories>
    Options Indexes FollowSymlinks ExecCGI
    AllowOverride None
    Order allow,deny
    Allow from all
 
    DirectoryIndex /cgi-bin/gitweb.cgi
 
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteRule ^.* /cgi-bin/gitweb.cgi/$0 [L,PT]
  </Directory>
 
  ErrorLog /var/log/apache2/git.example.com.error.log
  CustomLog /var/log/apache2/git.example.com.access.log combined
</VirtualHost>

Now test the setup pointing the browser to git.example.com, if you get a 404 - No projects found there could be some filesystem permission issues, gitolite sets mode 0750 on projects dirs, you can add the www-data user to the git group, so gitweb can access the git repositories in read only mode.

adduser www-data git