Git remote helpers

If you follow upstream Git development closely, you may have noticed that the Mercurial and Bazaar remote helpers (use git to interact with hg and bzr repos) no longer live in the main Git tree. They have been split out into their own repositories, here and here.

git-remote-bzr had been packaged (as git-bzr) for Debian since March 2013, but was removed in May 2014 when the remote helpers were removed upstream. There had been a wishlist bug report open since Mar 2013 to get git-remote-hg packaged, and I had submitted a patch, but it was never applied.

Splitting out of these remote helpers upstream has allowed Vagrant Cascadian and myself to pick up these packages and both are now available in Debian.

apt-get install git-remote-hg git-remote-bzr

Debian Gitweb server

After getting sick of GitHub's clunky closed-source interface, I decided to migrate my repositories to my own Debian-based server using the gitweb web interface.

Considering that I already have SSH access to the server, I only needed to provide read-only public access. As well as providing this access via the traditional 9418/tcp git protocol port, I wanted to provide access via HTTP too (I sometimes get caught behind firewalls which block 9418/tcp).

For vanity purposes, it was important that a single URL allowed both gitweb access and git cloning. Syntax highlighting for common programming languages is also a nice feature to have when migrating from github.

Finally, it was important that the configuration adhere where possible to the default Debian configuration files. I don't want the whole thing to fall apart when I upgrade to the next stable release!

The configuration below fulfils all the above requirements.

First, install git and apache if not installed:

apt-get install git gitweb git-daemon-sysvinit apache2 highlight

git-daemon-sysvinit is not available in Squeeze due to a dependency issue. You may either use git-daemon-run instead, compile this package yourself and relax the dependency, or else install the latest version of git from squeeze-backports.

Apache2 Virtual Host - /etc/apache2/sites-available/git.dereenigne.org:

<VirtualHost *:80>
ServerName git.dereenigne.org
DocumentRoot /usr/share/gitweb
SetEnv  GITWEB_CONFIG  /etc/gitweb.conf
SetEnv GIT_PROJECT_ROOT /var/cache/git

<Directory /usr/share/gitweb>
  Options FollowSymLinks +ExecCGI
  AddHandler cgi-script .cgi

  DirectoryIndex gitweb.cgi

  # Pretty gitweb URLs
  RewriteEngine On
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteRule ^.* /gitweb.cgi/$0 [L,PT]
</Directory>

  # Enable git clone over HTTP
  ScriptAliasMatch \
          "(?x)^/(.*/(HEAD | \
          info/refs | \
          objects/(info/[^/]+ | \
          [0-9a-f]{2}/[0-9a-f]{38} | \
          pack/pack-[0-9a-f]{40}\.(pack|idx)) | \
          git-(upload|receive)-pack))$" \
          /usr/lib/git-core/git-http-backend/$1
</VirtualHost>

Enable the apache2 site:

a2ensite /etc/apache2/sites-available/git.dereenigne.org

Edit /etc/gitweb.conf:

# path to git projects (.git)
$projectroot = "/var/cache/git";

@git_base_url_list = ("git://git.dereenigne.org", "http://git.dereenigne.org");

# directory to use for temp files
$git_temp = "/tmp";

$site_name = "git.dereenigne.org";

# require export flag
$export_ok = "git-daemon-export-ok";
$strict_export = 1;

# target of the home link on top of all pages
#$home_link = $my_uri || "/";

# html text to include at home page
#$home_text = "indextext.html";

# file with project list; by default, simply scan the projectroot dir.
#$projects_list = $projectroot;

# stylesheet to use
#$stylesheet = "gitweb.css";

# javascript code for gitweb
#$javascript = "gitweb.js";

# logo to use
#$logo = "git-logo.png";

# the 'favicon'
#$favicon = "git-favicon.png";

# enable git blame
$feature{'blame'}{'default'} = [1];

# enable pickaxe search
$feature{'pickaxe'}{'default'} = [1];

# enable snapshot downloads
$feature{'snapshot'}{'default'} = ['zip', 'tgz'];

# enable syntax highlighting
$feature{'highlight'}{'default'} = [1];

# enable pretty URLs
$feature{'pathinfo'}{'default'} = [1];

Edit /etc/default/git-daemon:

# 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=gitdaemon

GIT_DAEMON_BASE_PATH=/var/cache/git
GIT_DAEMON_DIRECTORY=/var/cache/git

# Additional options that are passed to the Daemon.
GIT_DAEMON_OPTIONS=""

Start the git daemon:

/etc/init.d/git-daemon start

To create a new project:

ssh myserver
mkdir /var/cache/git/myrepo.git
cd /var/cache/git/myrepo.git
git init --bare
echo "myrepo description" > description
touch git-daemon-export-ok

To push to this project:

git add remote myserver user@myserver:/var/cache/git/myrepo.git
git push myserver master

While this page is about Debian, the same commands can be used to set up a similar setup on Ubuntu.

Set git email address on a per repository basis

git allows you to specify email addresses on a per repository basis. This is handy when working with repositories from multiple organisations.

When in the repo directory, use the following commands to set a per repository email address:

jbloggs@hostname:~/git$ git config user.name “Joe Bloggs”
jbloggs@hostname:~/git$ git config user.email “jbloggs@alternativedomain.com”

Alternatively, you can edit .git/config manually, and add the required information under the [user] heading:

[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true
[remote "origin"]
        fetch = +refs/heads/*:refs/remotes/origin/*
        url = git@example.com:example.git
[branch "master"]
        remote = origin
        merge = refs/heads/master
[user]
        name = Joe Bloggs
        email = jbloggs@alternativedomain.com

git multiple remotes

git has a very undocumented feature which allows you to group multiple remote URLs as a single remote.

This allows you to push to many remote branches in a single command. I prefer using gitweb to browse my repositories, so I push to my own server, but I know that other people like using github, so I may as well push there as well.

To add multiple remote URLs, edit the .git/config file in the repository and add a second (or more) url line.

[remote "origin"]
        url = jmccrohan@git.dereenigne.org:/srv/git/openwrt-packages.git
        url = git@github.com:jmccrohan/openwrt-packages.git
        fetch = +refs/heads/*:refs/remotes/origin/*

Now I can push to both my own server and to github using

git push origin

Git SVN Mirror

Git is a version control system for managing source code. It is notable for originally being written by Linus Torvalds to manage the Linux source tree.

While Git is arguably one of the best control systems around, there are many projects still using SVN. If you find yourself accustomed to Git, moving backwards to SVN can cause problems. Luckily, Git has a solution. Git is capable of interacting with SVN repositories directly. This allows you to checkout a remote SVN repository in to a Git repository on a local machine, make your changes, and commit back to the remote SVN repository. This means that you never have to interact using SVN syntax. You can also create a Git mirror of the SVN project, and publish it using a provider such as Github.

I currently use this to provide a Git mirror of lcd4linux. This is a one way mirror, but this adequate for most open source projects where patches and a mailing list are used as a the main source of updating code.

First create and initialise the git repo, then pull in the svn repo into git:

mkdir lcd4linux
cd lcd4linux
git svn clone https://ssl.bulix.org/svn/lcd4linux/

This can take a while depending on the size of the svn repo, and the amount of commits.

Create your project on Github, and add this as a remote repo to your local repo.

git remote add origin git@github.com:jmccrohan/lcd4linux.git

Now push this to your remote repo:

git push origin master

The svn repo can now be checked for commits using:

git svn rebase

These changes can now to be pushed to your remote git repo using the same command as above:

git push

These commands can be automated using cron to provide an automatic update. Save the following shell script, and use cron to call the script every 15 minutes:

#!/bin/sh

cd /home/jmccrohan/lcd4linux
git svn rebase
git push

Call cron every 15 mins:

*/15 * * * * /home/jmccrohan/lcd4linuxrebasepush >> /dev/null 2>&1