Tuesday, March 10, 2009

Running a Public Git Repository on OS X 10.4.11

I recently switched from CVS to Git for my open source projects. Since I run my own cvs server I needed the same functionality from Git so that others code pull and push to a central source code repository. My server runs OS X 10.4 (Client) and was already set up for CVS access via ssh and for anonymous viewing with 'viewvc' so I also needed these same functions from Git. After a day of tweaking, testing and asking questions on #git I finally got the server setup to the way that I wanted it. You can view my git repo here. So what all have I setup you ask? Well I can use ssh to read/write the central git repo for assigned users, anyone can clone the repo to their own machine and anyone can use a web browser to browse the code. Cool. So how did I do it? With a lot of help from the internet and some great guys on the git IRC channel (#git).


I'll just assume that if you are trying this then you have admin access to your OS X 10.4 machine that is going to be hosting your git repos.


Since I have become a software developer I have become very accustomed to the command line interface (Terminal) so most of the commands that I am going to use are "Terminal" commands.


This also assumes that you have the developer tools installed on the OS X machine so that you can compile things (git mainly).


I have my git repo stored in '/Library/GIT/Public' on my OS X Server.


Apache's doc root is also in the default location on this server: '/Library/WebServer/Documents'


Get Git - Get the source code for git and compile it and install it on your machine.



[echo1] $ cd ~/Desktop
[echo1] $ curl http://kernel.org/pub/software/scm/git/git-1.6.1.3.tar.gz -O
[echo1] $ tar -xvzf git-1.6.1.3.tar.gz [echo1] $ cd git-1.6.1.3
[echo1] $ ./configure --prefix=/usr/local/git --execprefix=/usr/local/git
[echo1] $ make
[echo1] $ make install
# This will create the top level folder to hold all the git repositories
[echo1] $ cd /Library
[echo1] $ mkdir GIT
[echo1] $ sudo chmod ug+rwx GIT
[echo1] $ sudo chown root:admin GIT

That puts git binaries in /usr/local/git/bin and /usr/local/git/libexec/git-core/


For easier use you may want to add those paths to your 'PATH' environment variable like so:


export PATH=$PATH:/usr/local/git/bin;/usr/local/git/libexec/git-core/
SSH Access: To setup for git ssh:// protocol you simply need to turn on "Remote Access" under the Sharing Tab of the System Preferences. Once you have that turned on you can simply use
git ssh://yourserver/Path/to/Git/Repository
So for my server this is:
git ssh://echo1.bluequartz.net/Library/GIT/Public/MXADataModel

Anonymous Git Clone: This step required learning some of the ins-and-outs of the OS X 'launchd' service because the server needs to run the 'git-daemon' program at every startup of the machine. Git-daemon runs on port 9418 so you will also need to open this port up for TCP access through any firewalls that you have between the machine and the internet. After the port is opened up and forwarded to the server then you need to create a special file that tells OS X to sartup git-daemon when the machine is started up, here is how to do that.


Create a file called com.git-scm.git-daemon.plist in the '/Library/LaunchDaemons' directory. Pay attention to the paths used in the plist file and where you installed git as they all have to match so that git-daemon can find all the git executables.


[echo1] $ sudo touch /Library/LaunchDaemons/com.git-scm.git-daemon.plist
The contents of the file are as follows:
<!-- Create a file named com.git-scm.git-daemon.plist and
put it in /Library/LaunchDaemons/ -->
<!-- Note the binary path to the git-daemon executable -->
<!-- This file should work on OS X 10.4 and greater. It is designed to launch the git-daemon
when the system boots up -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Debug</key>
<true/>
<key>Label</key>
<string>com.git-scm.git-daemon</string>
<key>OnDemand</key>
<false/>
<key>Program</key>
<string>/usr/local/git/libexec/git-core/git-daemon</string>
<key>ProgramArguments</key>
<array>
<string>--verbose</string>
<string>--base-path=/Library/GIT/Public</string>
</array>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/local/git/libexec/git-core/</string>
<key>PATH</key>
<string>/usr/local/git/bin/</string>
</dict>
<key>StandardErrorPath</key>
<string>/var/log/git-daemon-error.log</string>
<key>StandardOutPath</key>
<string>/var/log/git-deamon.log</string>
<key>RunAtLoad</key>
<true/>
<key>Bonjour</key><true/>
</dict>
</plist>

Use the following command to launch git-daemon to run in the background.
[echo1] $ sudo launchctl load /Library/LaunchDaemons/com.git-scm.git-daemon.plist

Use the following command to kill the git-daemon:
[echo1] $ sudo launchctl unload /Library/LaunchDaemons/com.git-scm.git-daemon.plist
Web Access to Git Repository
Use 'make' to generate the gitweb.cgi file (which is a perl file) and then install that file and the supporting image files into the proper location on your server for Apache served files and such. Pay attention to the path where git is located as the cgi needs to be able to find git in the PATH or otherwise find the file. While in the top level of the git source repo do the following:
# Remove any cgi file that has already been created
[echo1] $ rm gitweb/gitweb.cgi
# Create the cgi files
[echo1] $ make GITWEB_PROJECTROOT=/Library/GIT/Public GITWEB_CSS="/gitweb/gitweb.css" GITWEB_LOGO="/gitweb/git-logo.png" GITWEB_FAVICON="/gitweb/git-favicon.png" bindir=/usr/local/git/bin gitweb/gitweb.cgi

# check the permissions on the newly created directories !!!
[echo1] $ sudo mkdir /Library/WebServer/Documents/gitweb
[echo1] $ sudo cp gitweb/gitweb.css gitweb/git-logo.png gitweb/git-favicon.png /Library/WebServer/Documents/gitweb/
[echo1] $ sudo mkdir -p /Library/WebServer/CGI-Executables/gitweb
[echo1] $ sudo cp gitweb/gitweb.cgi /Library/WebServer/CGI-Executables/gitweb/

To setup a project to send on email on updates
Copy the post-receive-email file into the installed git location
[echo1] $ cp ~/Desktop/git-1.6.1.3/contrib/hooks/post-receive-email /usr/local/git/share/git-core/templates/hooks/post-receive-email
Change mode to make that file executable in the new destination
[echo1] $ sudo chmod ug+x /usr/local/git/share/git-core/templates/hooks/post-receive-email
If you already have a bunch of imported git projects in /Library/GIT/Public then you can create and run a script such as the following to update each project in order to send an email when that repo is updated (pushed into) from a remote source. Create a file called 'update-repos.sh'
[echo1] $ cd /Library/GIT/Public
[echo1] $ touch update_repos.sh
[echo1] $ chmod ug+x update_repos.sh

with the following contents:

#------ Start of Script File 'update_repos.sh'
#- Don't forget to give this file execute permissions so that it can
#- be run from the terminal
#!/bin/bash
cd /Library/GIT/Public
dirs=`ls`
for dir in $dirs
do
cd /Library/GIT/Public/$dir
echo "Working on $dir"
echo "[hooks]" >> config
echo " mailinglist = \"youremailaddress@nowhere.com\"" >> config
echo " announcelist = " >> config
echo " envelopsender = \"youremailaddress@nowhere.com\"" >> config
echo " emailprefix = \"[Git Commit] $dir \"" >> config
# Create a symlink to the post-receive-email script
ln -s /usr/local/git/share/git-core/templates/hooks/post-receive-email hooks/post-receive
done
#---- End of file 'update_repos.sh'

That script will update the 'config' file for the project and also create a symlink to the email script that was copied above. Assuming you have setup email sending capabilities on your mac then emailing should now work.

You will also need to edit the post-receive-email script at around line 195 with the line:
Subject: ${emailprefix} $project ($refname_type, $short_refname, ${change_type})
otherwise the subject of the email will be _very_ long because it will include the description of the project.



Shell Script to convert an existing CVS repository into a Git repository


#!/bin/bash
# This file will migrate a series of CVS modules from CVS to git.
# there are a bunch of prerequisites to have working before this
# script can be used.
# You need to install git first
# You need to have git-daemon running and working correctly
# You will also need cvsps compiled and installed BEFORE running this
# script. cvsps can be downloaded from 'http://freshmeat.net/projects/cvsps/'

# Function to create a new git repository on the local machine.
# this script was taken from http://www.guyslikedolls.com/git-on-macosx
newgit()
{
if [ -z $1 ]; then
echo "usage: $FUNCNAME project-name.git"
else
gitdir="/Library/GIT/Public/$1"
mkdir $gitdir
pushd $gitdir
git --bare init
git --bare update-server-info
chmod a+x hooks/post-update.sample
touch git-daemon-export-ok
popd
fi
}

# Where is the CVS Repository located
export CVSROOT=/Library/CVS/CTMD

# List the various CVS Modules that you would like to convert to git
modules="MXADataModel MXAImport MXATools"

# Loop over all the modules and migrate them to git one at a time. This can
# take a while even on a fast machine.
for module in $modules
do
echo "Working on $module"
cd ~/Desktop
rm -rf $module
mkdir $module
cd $module
git cvsimport -v $module
rm -rf /Library/GIT/Public/$module.git
newgit $module.git
git push /Library/GIT/Public/$module.git master
done


I hope some of this is helpful to someone as it took a while to get everything figured out. Thanks to everyone who helped out.

No comments: