Using git hooks to deploy your web application

09 August 2013

Often times when building web applications, I used to spend time deploying my web applications via ssh and scp. Then I used Heroku for a few projects, and I really liked that deploying to heroku was as easy as it could be.

git push heroku master

I wanted to have a similar deployment scheme on my own projects that aren't deployed on Heroku.

How it works

Since git is a distributed version control system, you can push the code that lives on your machine to another machine very easily via ssh. So your first instinct is to set up a repo in the location that your code needs to be deployed, and push to it via git. This is a good instinct, but git does not allow you to push code to a working copy. To resolve this, you will create a bare repository on your server, and push to it. You will also set up a git hook to automatically deploy your application when code gets pushed to the bare repository.

Setting it up

Before you start, your codebase needs to be in a git repository. This could be a Github repository that you use for version control. I will assume that your codebase lives in one directory called project on your development machine, which I will refer to as develop.

This codebase will be deployed to your server. I will refer to your server as deploy.

Now, you are going to create a bare git repository on deploy, and you will be able to push to it from develop.

username@deploy:~$ mkdir repos # this is the dir where all your repos will be stored.
username@deploy:~$ cd repos
username@deploy:~/repos$ mkdir project.git 
username@deploy:~/repos$ cd project.git # You can replace this with the name of your project.
username@deploy:~/repos/project.git$ git init --bare
# Initialized empty Git repository in /home/username/repos/project.git

You will now set up your codebase on develop to push to the repos/project.git directory on deploy.

username@develop:~$ cd /path/to/my/project
username@develop:~/code/project$ git status 
# This must be a git repo.
username@develop:~/code/project$ git remote add deploy username@deploy:~/repos/project.git # This is the path to your bare repo.
username@develop:~/code/project$ git push deploy master 

This will push your codebase, to the bare repository you just created on deploy. You can verify this by cloning the bare repository if you'd like.

username@develop:~$ cd /tmp
username@develop:/tmp$ git clone username@deploy:~/repos/project.git
# Cloning into 'project'...
# remote: Counting objects: 666, done.
# remote: Compressing objects: 100% (417/417), done.
# remote: Total 666 (delta 255), reused 632 (delta 221)
# Receiving objects: 100% (666/666), 621.96 KiB | 462 KiB/s, done.
# Resolving deltas: 100% (255/255), done.
username@develop:/tmp$ cd project
username@develop:/tmp$ ls
# make sure your files are here.

Now that we are pushing to the repos/project.git directory on deploy. Let's set up our repository to actually deploy its code. I'll assume that your application gets deployed to /var/www/myproject.com .

username@deploy:~$ cd repos/project.git
username@deploy:~$ ls
# HEAD  branches  config  description  hooks  info  objects  refs
username@deploy:~$ cd hooks
username@deploy:~$ [editor] post-receive

The post-receive hook gets called by git right after code gets pushed to a repository (right after git push deploy master). We will make this hook deploy your application to /var/www/myproject.com . Using an editor of your choice, place the following in the post-receive file.

#!/bin/bash

### This file gets run when code is pushed to the project.git directory.

GIT_WORK_TREE=/var/www/myproject.com git checkout -f

Make the hook executable.

username@deploy:~/repos/project.git/hooks$ chmod +x post-receive

Make sure that your user has permissions to write to /var/www/myproject.com. This is it! You can now deploy your code anytime you want by running:

username@develop:~/code/project$ git push deploy master

Verify that your code is deployed when you push, and you should never need to use scp to deploy ever again.