Description
GIT
Since version 1.6.6 GIT is able to tunnel its native protocol through HTTP or HTTPS. In this post I describe how to set things up so you can use GIT over HTTP(s). As always it is best to make use of HTTPS for security reasons. In this setup we use Basic authentication so you better use HTTPS
I also use virtualmin to keep my hosting business running but that should not be a problem when following along with the steps in this post.
Preparation
Ok first of all create a subdirectory in your public_html (document root) directory. This is where we are going to store the repositories. I suggest you call this directory….git (lowercase). Change directory to your new folder.
mkdir /home/[username]/public_html/git
chown [username]:[username] /home/[username]/public_html/git
cd /home/[username]/public_html/git
Apache htaccess and htpasswd
We are going to create a couple of CGI scripts to have more control over the way the backend is executed. First create a .htaccess file with the following contents:
Options +ExecCGI
AddHandler cgi-script cgi
AuthUserFile /home/[username]/public_html/git/.htpasswd
AuthType Basic
AuthName "Git Private"
Require valid-user
This tells apache that it is ok to execute a CGI script from this folder (line 1, 2). It also tells apache to require a “valid-user”; this user can be found in the .htpasswd file (see below). Now we have to create a password file for the user authentication:
htpasswd -c .htpasswd username
New password:
Re-type password for user username
For testing purpose you could create an index.html file and try to open that in the browser. The browser should ask your username and password now.
CGI Scripts
Now create a CGI script that will initialise a new bare repository for us to use. Create an init.cgi script with the following contents (extend parameter checking if you wish).
init.cgi
#!/bin/bash
# init.cgi
# Initialise a new git repository.
# Example:
# https://[yourdomain]/git/init.cgi?reponame=mynewrepo
# Params:
# reponame - the name of the git repository to create
# Remarks
# - The name of the repository may only contain the letters a-z and A-Z
# - The repository should not exist already
echo 'Content-type: text/plain'
echo
source config.sh
saveIFS=$IFS
IFS='=&'
parm=($QUERY_STRING)
IFS=$saveIFS
if [ "${#parm[@]}" -ne "2" ]; then
echo "Invalid number of parameters"
exit 1
fi
if [ "${parm[0]}" != "reponame" ]; then
echo "Invalid parameter name ${parm[0]}"
exit 2
fi
if ! [[ ${parm[1]} =~ ^[a-zA-Z]*$ ]]; then
echo "Invalid parameter value ${parm[1]}"
exit 3
fi
if [ -d "$GIT_PROJECT_ROOT/${parm[1]}.git" ]; then
echo "Git repository already exists"
exit 4
fi
mkdir -p "$GIT_PROJECT_ROOT"
git init --bare "$GIT_PROJECT_ROOT/${parm[1]}.git/" 2>&1
echo "Repository created at `date` from $REMOTE_ADDR" > "$GIT_PROJECT_ROOT/${parm[1]}.git/description"
echo "`date` : \"${parm[1]}\" repository created from ip $REMOTE_ADDR" >> "$logfile"
echo >> "$logfile"
exit 0
When you execute this script via the browser (https://yourdomain/git/init.cgi?reponame=[yourreponame] ) a new bare repository is created. The actual repositories are created in the subdirectory repos below the git folder.
The next script will startup the actual GIT http backend. I have wrapped this in an additional script so I could perform some logging. Create a script called git.cgi in your git directory with the following contents.
git.cgi
#!/bin/bash
# git.cgi
# Execute the git http-backend command
# Params
# As handed by the git client command
# Example:
# git clone https://[yourdomain]/git/git.cgi/myrepo.git
source config.sh
git http-backend "$@" 2>> "$logfile" || echo failed >> "$logfile"
echo "`date` : git command executed $@" >> "$logfile"
Finally you need a little configuration script, named config.sh , which sets some general parameters. Source is shown below.
config.sh
#!/bin/bash
# When not setting the variable below every repo has to have the magic file
# git-daemon-export-ok. If both are not present a message "Repository not exported"
# shows iup in the log file
export GIT_HTTP_EXPORT_ALL=1
export GIT_PROJECT_ROOT=~/public_html/git/repos
logfile=~/tmp/git_log.txt
Now you can clone a repository by sending your browser to the url
https://yourdomain/git/git.cgi/git/repos/[repo].git
Example workflow
In your browser: https://[yourdomain]/git/init.cgi?reponame=first
In your shell (local): git clone https://[yourdomain]/git/git.cgi/git/repos/first.git
Apply your changes
Add all items to the staging area: git add –all
Commit all changes in the staging area: git commit -am “My commit message”
Push the changes back to the server: git push
That’s all; happy GITing