Deploy websites using git

This guide explains how to deploy to a remote server by pushing to a remote git repository which is using a custom post-receive hook to checkout the contents of the repository to the webservers public www root.

The local repository

cd ~/sites
git init
> Initialized empty Git repository in /Users/dewey/sites/

The remote repository

Creating a bare repository

This is the bare repository we are going to push to.

cd ~/git/
mkdir && cd
git init --bare
> Initialized empty Git repository in /home/user/git/

Adding a custom post-receive hook

This hook will run after each push to the bare repository, checking out the changes to the working tree (Which isn't located in the bare repository because that's how it works). The working tree will have no .git directory (That's how we want it) and will be served by nginx.

vim ~/git/

With this content:

echo "********************"
echo "Post receive hook: Updating website"
echo "********************"

export GIT_WORK_TREE=/home/user/www/
git --work-tree=/usr/share/nginx/www/ --git-dir=$HOME/git/ pull
git --work-tree=/usr/share/nginx/www/ --git-dir=$HOME/git/ checkout master -f

Creating the Work Tree directory

This is the directory where all the files should end up after each push. We will create it within nginx's document root so it'll be served up by the webserver.

cd /usr/share/nginx/www/


We have to add our regular user to the www-data group which owns the files in nginx's document root so we'll be able to checkout the files.

sudo chown www-data /usr/share/nginx/www/
sudo usermod -a -G www-data user
sudo chgrp -R www-data /usr/share/nginx/www/
sudo chmod -R g+w /usr/share/nginx/www/

Push to remote repository

Now we have to add the remote repository to our local repository so we can push to it.

Our local repository's .git/config should look like this:

[remote "production"]
    url = ssh://
    fetch = +refs/heads/*:refs/remotes/production/*
    gtSSHKey = /Users/user/.ssh/id_rsa
[branch "master"]
    remote = production
    merge = refs/heads/master

Once this is added git remote will show the remote repository:

git remote
> production

Pushing via

git push production

should now be possible.