Deploying a Site With Git Hooks

Friday, September 5 2011 ruby rails

This blog runs on Sinatra, using a CMS called Nesta (inspired by Topfunky). I love the control it gives me, but publishing a post meant deploying an update using Capistrano. I like Capistrano, but not as a post publisher... here's how I got around that.

##Step 1: Setup Your SSH Keys

Hopefully you know how to do this by now, if you don't

here's github's primer. If you're ultra lazy you can use "git gui" to open up the Git ... GUI and go to the "Help" menu. Then select "show SSH key" - if none is there, you can have it generate the key for you... which is really handy.

SSH key in hand, you need to SSH into your server. You don't have one you say? Well take a second and

go get one! Or kick up a VM with Linux in it (you know you've been meaning to if you haven't Mr. Die Hard Softy Guy).

If you don't what "SSH" is - it stands for "Secure SHell" and is a way of logging in to the terminal of a remote machine. You can copy files, run system commands and so on... very handy.

Authorizing Yourself

Many people don't take the time to do this - opting to enter their server password every time they SSH in to their server. Instead - tell your server to let you in every time dammit!

This is simple to setup. First, SSH into your server:ssh

Next, head into your ssh directory and see what's therecd .ssh ; ls -a

You should see some files in there like "idrsa" and "". If you don't - that's OK we'll fix that in a second. If you're wondering - the ".ssh" directory is a "hidden" directory (the dot in front makes it so on Unix systems) - in here all the credentials for your systems SSH "stuff" are stored.

We want to tell the system to let us in whenever we come knocking - so we need to grab our local SSH key and stick it in a file called "authorized_keys" on the remote server.

To do this, open up a new terminal window on your machine and entercat ~/.ssh/
This will splash your SSH key to the screen. Copy it, making sure you only select the text starting with "ssh-rsa".

Now head back over to your remote box and paste it into the authorizedkeys file:echo '[paste key here]' >> ~/.ssh/authorizedkeys
There you go. Log out of your remote box by typing "exit" - this will end your SSH session. Log back in and you should be good to go, without a password.

Setting Up Your Remote Git Drop

Believe it or not - the above stuff is the hard part. The rest is rather simple. SSH into your remote box again and create a directory for your site. I tend to put my stuff in my home directory simply so I don't need to wrestle with permissions:ssh
mkdir www
cd www
mkdir mysite
cd mysite

The "mysite" directory is ready to go! Initialize an empty git repo:git init
And we're almost done...

Hooking Into a Git Event

What we want to do is have Git run a command whenever we push an update to our repo. Git allows for this with "hooks" - and you can see these hooks inside the ".git" directory:cd .git
cd hooks

What you should see here is a bunch of files with the ".sample" extension. To enable any one of them, just remove the ".sample" extension and it will fire. You can use any script language in here that your server understands - shell script, ruby, python, etc.

We want the one that says "post-receive.sample". This gets fired whenever a push completes. Let's open it in VI:vi post-receive.sample

Up should pop something like this:#!/bin/sh

An example hook script for the "post-receive" event.


The "post-receive" script is run after receive-pack has accepted a pack

and the repository has been updated. It is passed arguments in through

stdin in the form

For example:

aa453216d1b3e49e7f6f98441fa56946ddcd6a20 68f7abf4e6f922807889f52bc043ecd31b79f814 refs/heads/master


see contrib/hooks/ for a sample, or uncomment the next line and

rename the file to "post-receive".

. /usr/share/doc/git-core/contrib/hooks/post-receive-email

Those are all comments in there and you can ignore them happily - but it's kind of handy that it comes with an emailer out of the box! What we want to do is edit this to reset our current working directory to that of the commit that was just pushed. This will drop all of the files that we just pushed, into the root of our web site:#!/bin/sh
cd ..
umask 002 && git reset --hard
rm -R public/*.html
touch tmp/restart.txt

So put the above text into the "post-receive.sample" file. If you don't know VI, here's what you do:press escape to enter "normal" mode
shift-v to entire "visual line" mode
15j to select 15 lines down
d to delete it all
i to enter "insert mode"
(copy and paste the above script in) escape
wq! will "write" and then "quit"

Now we need to rename the file, and make sure it's executable:mv post-receive.sample post-receive
chmod +x post-receive

The script here does a number of things. The first line simply invokes the shell - this case it's Bash. This will open a shell session in the .git/hooks directory - where our script lives.

The next lines navigate to the .git directory, telling Git that we're not using a BARE repository (which is typical for remotes). Then there's the money shot: "umask 002 && git reset --hard". Umask is a quick way to set file permissions and git reset --hard pulls our files out of our repo and dumps them out to the web root.

The "rm -R" is unique to my blog. Nesta caches all the pages as HTML in the public folder - so I need to manually remove them if I expect you to see updates :). You don't need this line.

Finally - the "touch" command updates the file time to right now, telling our web server that it needs to restart.

Setting It All Up

We have our SSH keys, our remote repo... now we just need to hook everything together. To do this, we first need to tell our local repo about the new remote:git remote add live
This tell git that we have a remote called "live" at the following SSH address.

Finally - we push!git push live master
Which is precisely the command I just entered to push this site live.


To a lot of people an FTP sync or push from a Build Server works for them - and if that's you Rock on! If you're not familiar with Git and don't care much for Linux/Commandline stuff I'm sure you've read this and threw up a little.

But at some point you'll find yourself on a Unix machine in your career - it's sort of unavoidable. What you see here is incredibly basic - slinging around SSH certs, renaming files and setting permissions. It's pretty simple really - in "real time" it took me about 15 minutes to set it up.

Finally, if you're wondering why I don't want to use Capistrano - well I just don't need it for this blog. This is a static blog with files instead of a database and every time I publish it means I have to deploy - which takes a bit too long.