Deploying Websites With a Tiny Git Hook

By Ryan Florence, published 2010-07-27

Part of the issue Git Your Act and Deployment Together.

This method of deployment is similar to that discussed in Simple git deployment, but it takes out the logging-in-to-the-server-and-pulling step. It’s still a good idea to have a remote repository somewhere, but it isn’t involved here. Instead we just need a local repository and a repository on the web server.

Because git is “decentralized” we can push and pull to and from several different remote repositories. So why not simply add our web server as a remote repository and push to it when we want to update it? The trick is in using the post-receive hook.

Hooks?! Hooks are scripts that git will execute when awesome stuff happens, like after the repository receives a push. List the .git/hooks directory to see what’s available:

$ ls example/.git/hooks
applypatch-msg  post-commit   post-update     pre-commit  update
commit-msg      post-receive  pre-applypatch  pre-rebase

Alright, let’s do this:

Web Server: Login to your web server and create the repository

$ ssh rpflo@ryanflorence.com
$ mkdir public_html/example.com
$ cd public_html/example.com
$ git init

Local Machine: Add the web server’s repository as a remote and name it production.

$ git remote add production ssh://rpflo@ryanflorence.com/~/public_html/example.com

Web Server: This is the tricky part. In step 5 we’re going to push our branch to the remote repository on the web server. The site won’t be updated after we push because the web server’s repository has a different commit, or set of files, in the working tree. No amount of pushing will force it to ‘reset’ to the most current commit (the one we’re going to push.) Therefore, we need to edit and enable the post-receive hook to reset the “HEAD” of the web server’s working tree.

It’s going to be in example.com/.git/hooks and be named either post-receive or post-receive.sample. Open it up:

$ ssh rpflo@ryanflorence.com
$ cd public_html/example.com
$ vi .git/hooks/post-receive
# or nano .git/hooks/post-receive.sample

There’ll be a lot of commented out lines, you can delete them all or leave them, doesn’t matter. Now paste this into it. (If editing files in the terminal isn’t your thing, just ftp the file.)

#!/bin/sh
cd ..
GIT_DIR='.git'
umask 002 && git reset --hard

The git reset --hard command updates the working tree with the newest commit in the branch. In other words, it updates the files in the folder to the most recent commit which happens to be the one that you just pushed. For a more robust post-receive script check this out, it’s what I actually use.

Web Server: Enable the hook. If your script was named post-receive.sample, rename it. Also, regardless of what it was named, you probably need to make it executable.

$ mv .git/hooks/post-receive.sample .git/hooks/post-receive	
$ chmod +x .git/hooks/post-receive

Local Machine: The hard part is over! Now make some changes on your local machine and push to the production remote repository. Like magic, your site updates itself, flippin’ sweet.

# make changes, commit, merge, etc.
$ git push production master

Add more remotes for staging! You can push all over the place, just repeat the steps on different servers and you’re a git-deployment maniac.

$ git remote add stage ssh://projects@domain.com/~/stage.example.com
$ git push stage master

Srsly d00d, no more FTP, okay?

Hi, I'm Ryan!

Location:
South Jordan, UT
Github:
rpflorence
Twitter:
ryanflorence
Freenode:
rpflo

About Me

I'm a front-end web developer from Salt Lake City, Utah and have been creating websites since the early 90's. I like making awesome user experiences and leaving behind maintainable code. I'm active in the JavaScript community writing plugins, contributing to popular JavaScript libraries, speaking at conferences & meet-ups, and writing about it on the web. I work as the JavaScript guy at Instructure.