Deploying a Site With Git Hooks
- Saturday, September 17, 2011
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.
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:
Next, head into your ssh directory and see what's there
cd .ssh ; ls -a
You should see some files in there like "id_rsa" and "id_rsa.pub". 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 enter
cat ~/.ssh/id_rsa.pubThis 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 authorized_keys file:
echo '[paste key here]' >> ~/.ssh/authorized_keysThere 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 email@example.com mkdir www cd www mkdir mysite cd mysite
The "mysite" directory is ready to go! Initialize an empty git repo:
git initAnd 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 ls
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:
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 .. GIT_DIR='.git' 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 firstname.lastname@example.org:www/mysiteThis tell git that we have a remote called "live" at the following SSH address.
Finally - we push!
git push live masterWhich 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.