Friday, June 10, 2011

Exposing GIT over HTTP in Ubuntu

Continuing my GIT exploration here I will talk about how to expose GIT over HTTP in UBUNTU

Pre-requisites: -

GIT - GIT Core should be installed (Refer to Working with GIT)
Apache2 - Install it by running the following command: -

sudo apt-get install apache2

The above command will install the apache in the following Directories

1. /etc/apache2 - will contain all the configurations like ports, virtual hosts etc
2. /var/www - Contains the HTML files, CGI scripts etc


GITWEB is a package which can be used to expose GIT repositories over HTTP

It is nothing more than few set of files: -

1. gitweb.css
2. git-logo.png
3. git-favicon.png
4. gitweb.cgi
5. gitweb.js
6. gitweb.conf (Configuration File which usually is found at /etc/gitweb.conf)

sudo apt-get install gitweb will download all of the above files

Preparing Apache for Hosting GIT: -

1. Create a directory by name of "gitweb" under "/var/www".
2. Except gitweb.conf, copy all other files downloaded with GITWEB package to "/var/www/gitweb" directory.
3. Create a another folder by name of "/var/www/gitRepo" and configure your git client and also download the code from git Server (refer to Working with GIT) for all the branches.
4. Open /etc/gitweb.conf and modify the following highlighted Attributes: -

$GIT = "/usr/bin/git";
# path to git projects (.git)
# $projectroot = "/var/cache/git";
$projectroot = "/var/www/gitRepo";

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

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

# Description Text for your Repository
$site_name = "Project Trees";

# 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";

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

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

5. Now execute the following Commands in "/etc/apache2/mods-enabled" which will enable the specific modules which are needed for this exercise: -

ln -s ../mods-available/dav.load dav.load
ln -s ../mods-available/dav_lock.load DAVLockDB
ln -s ../mods-available/dav_fs.load dev_fs.load
ln -s ../mods-available/dav_fs.conf dev_fs.conf
ln -s ../mods-available/cgid.load cgid.load
ln -s ../mods-available/cgid.conf cgid.conf
ln -s ../mods-available/rewrite.load rewrite.load

sudo a2enmod rewrite

6. Next create a virtual Hosts, that can expose your git repository

Create a git_vhosts.conf file in "/etc/apache2/sites-available" which will contain the details about the virtual Hosts.
The content of the file will look like this: -

# Virtual Hosts
# If you want to maintain multiple domains/hostnames on your
# machine you can setup VirtualHost containers for them. Most configurations
# use only name-based virtual hosts so the server doesn't need to worry about
# IP addresses. This is indicated by the asterisks in the directives below.
# Please see the documentation at
# <URL:>
# for further details before you try to setup virtual hosts.
# You may use the command line option '-S' to verify your virtual host
# configuration.

# Use name-based virtual hosting.
NameVirtualHost *:801

# Almost any Apache directive may go into a VirtualHost container.
# The first VirtualHost section is used for all requests that do not
# match a ServerName or ServerAlias in any <VirtualHost> block.

<VirtualHost *:801>
    DocumentRoot "/var/www/gitweb"
    DirectoryIndex gitweb.cgi
    SetEnv  GITWEB_CONFIG   /etc/gitweb.conf

    <Directory "/var/www/gitweb">
        Options FollowSymlinks ExecCGI
        Allow from all
        AllowOverride all
        Order allow,deny

        <Files gitweb.cgi>
            SetHandler cgi-script

        RewriteEngine on
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule ^.* /gitweb.cgi/$0 [L,PT]

    <Directory "/opt/git/myrepo.git">
        Allow from all

    # To debug rewrite rules, which were very painful to figure out. Create directories in case they don't exists
    RewriteLog /var/log/httpd/rewrite_log
    RewriteLogLevel 9

    ErrorLog /var/log/httpd/gitweb

You need to focus on the highlighted text in the above configuration as these attributes are very much specific to the paths exposed on the individual boxes.
In case you have followed all the previous instructions line by line than you just need to change "ServerName" attribute, which should be the IP or Domain Name of your machine.

7. Now to enable the Virtual Host and execute the below command from "/etc/apache2/sites-enabled" directory

ln -s /etc/apache2/sites-available/git_vhosts.conf 002-git_vhost.conf

8. Lastly restart your Apache server by using the following set of Commands

sudo /etc/init.d/apache2 stop
sudo /etc/init.d/apache2 start

NOTE: Make sure it is a clean start and there are no Errors shown on console.

9. Now browse the URL (http://:801/gitweb.cgi?p=.git;a=tree) and you will be able to see the GIT repository.

The window which Appears would be something like the below snapshot

Next I leave to you to play around this UI.

Updating Git repository: -

As we are exposing client repository over HTTP, so naturally the question arises: -

How do you make sure that your repository is continuously updated and doesn't require any manual intervention?

There are 2 ways which can be used to do this: -

1. Create a Cron JOB in Ubuntu which updates the repository at every fixed interval
2. enable the "post-update Hook" of your GIT repository and from there execute a Shell Script which does the job for you.

As both the above the options requires a Shell Script which is capable to logging remotely and updating the repository through various SSH and GIT commands.

Normal Shell scripts are nowhere capable to doing this thing....but thanks to Linux which always have a solution to any problem.

"Expect" is a wonderful utility which helped me to develop a short and simple script which does the needful.

sudo apt-get install expect

Here is actual Script which I created and used with #2 to keep my repository in Sync with each and every commit: -

/usr/bin/expect << EOD

spawn  ssh <username>@localhost

expect "password:"

send -- "<password>\r"

expect "$"

send -- "cd /var/www/gitRepo \r"

expect "$"

send -- "unset GIT_DIR \r"

expect "$"

send -- "git pull ssh://<username>@<IP>/<PATH> <BRANCH> \r"

expect "password:"

send -- "<password>\r"

expect "$"

expect eof


echo "rep updated"

No comments: