Client collaboration via github

UPDATE: The post-receive URL on github has now been moved to a new "Services" tab on the project edit page.

It can be a hassle setting up and maintaining development environments
for clients; particularly if they're not very technical, or if they
use Windows.

I usually set up a separate VPS for each client's project as a
development/staging server, and it would be great if they could
just edit the source files on there. Then they could play around
and see the effect of their changes in realtime. The trouble is
that this requires some kind of remote editing or file-syncing setup
(e.g. SSH+vi), which can be troublesome to set up.

So, I'm trying out a combination of github's in-browser source
editing, plus a post-receive URL pointing to the client's development
VPS. Here's how it should work.

  • I set up the client's project as a github repository, and add the client as a collaborator.

  • The client makes changes to the view/css files using github's in-browser editor.

  • When they commit their changes, github posts to a listener on the client's development VPS (using a post-receive hook)

  • The listener on the VPS pulls the client's changes

  • The client views their development site to see the changes in (nearly) realtime

This is surprisingly easy to set up. I'll walk you through setting this up for a dummy "Hello, world" rails application. The ingredients we'll be using are;

  • github - a free account will do fine, for this demo

  • A development server - github will be posting to a URL on this server, so you need to be able to access it from the internet

  • A listener to pull changes from github, whenever there's a new commit. I'm going to use a very simple sinatra application, running via a command-line mongrel instance.

  • An application to act as our super-important client project

Setup a simple rails project as a github repository. You can just use a
bare "rails foobar" project - no need to set up databases.

Now, ssh to your development server (the one github will be posting to when your client makes changes). Setup a clone of the github repo.

For this demo, use the "public" clone url (the one that starts with "git://github.com").

You can use this technique for a private repo - otherwise it would be a bit pointless - but that takes a bit more SSH setup than I want to get into in this post.

I'm using "screen" so that I can start the demo application running
in a terminal and have it keep running after I log out. If you don't
know about the unix screen command, go learn about it right now.
After SSH it's one of the most useful tools to have in your toolbox.

cd dstest
[Ctrl-A D to detach from screen]

So, now the application is running, and you can open a browser window to;


and see the "Welcome to Ruby on Rails" page.

Now for the listener which will pull our client's changes.

If you haven't already got them, you will need sinatra and mongrel on your development server;

sudo gem install sinatra
sudo gem install mongrel

Now, put the following into a file called "gitmon.rb"

require 'rubygems'
require 'sinatra'
post '/update_site' do
dir = '/home/david/dstest'
system "cd #{dir}; git pull"
"Site updated\n"

You will need to change the "dir" line to
be the full path to your rails project.

Now use screen again to start a listener that will continue to run after you log out;

ruby gitmon.rb
[Ctrl-A D to detach from screen]

The listener will start up on Sinatra's
default port, 4567. You can test it by


You should see "Sinatra doesn't know this diddy."

Now we just need to tell github to post to the listener whenever it gets new commits.

Login to your github account and go to
your repository's edit page.

Setup the "Post-receive URL" as;


That should do it.

Now, edit a file (e.g. public/index.html) using the github in-browser editor (if you're not logged-in, you won't see the edit link). Commit your change.

Refresh the browser window you've got open to;


and you should see your changes (it can take a few seconds before your site updates).

This is just the tip of the iceberg, and there are a lot of ways this technique could be extended (e.g. hooks to run migrations after a "git pull" on the development server, or getting the sinatra listener to post to Campfire whenever a client commits something).

Also, there is a lot of information in the POST from github, which we're just ignoring here.

I hope you find this useful. I'll be setting it up for one of my clients very soon, so I'm keen to see how it works out.