, , ,

I’ve recently started to experiment with deploying sites directly from a git repository. Up until now my current main deployment method has been based on a handmade script which involves rsyncing code up to the live server. I’ve been using git for source code management for sometime time now and for the most part I get along well with it. Particularly how I can easily create and work with branches for different feature developments and merge them back into the main release when they’re ready.

As with a lot of things with git there’s multiple ways of achieving what you want.  After trial and error I’ve settled on this method . It works for me because it’s straight forward and keeps the git specific stuff out of the website document root. It also means I can update the remote server directly from local machine, which is handy for a development server where you might be making lots of changes and keeping the number of steps to a minimum really helps the workflow.

So what’s actually involved?

The basic idea is this. I have a repository, lets call it “local”. I also set up a repository on the remote webserver, lets call it “webserver”. I tell my local repository about webserver, i.e add it as a remote. In the webserver repository I add a post-receive hook that will checkout the latest version of code to my webroot when it receives a new push from another machine. What this gives me is the ability to update my remote website code by just pushing to the repository. Of course you’ll have to decide for yourself if you want this behaviour. On a live site you may want to be very explicit about when the site gets updated. But for small teams or development sites I think it works well. You’ll need to be able to ssh into your remote site and have git set up on your local and remote server.

What to do

The steps you’ll need to take are in the link above but I’ll repeat them here for convenience.

On the remote (webserver) set up a new bare repository. N.B. My directory structure is:

/var/www/www.domain.name (folder for all files for a site)

/var/www/www.domain.name/public_html (web root of site, where web server looks for files)

/var/www/www.domain.name/git (git repository files)

/var/www/www.domain.name/nondeployed (folder for items that are specific to server and not deployed e.g user uploads)

On the remote “webserver”

$ cd /var/www/www.domain.name 

$ mkdir git 

$ cd git/ 

$ git init --bare 

$ git --bare update-server-info 

$ git config core.worktree /var/www/www.domain.name/public_html

$ git config core.bare false 

$ git config receive.denycurrentbranch ignore 

$ cat > hooks/post-receive


git checkout -f


$ chmod +x hooks/post-receive

On your local repository

If you’re using a GUI set up a new remote specifying the git repository to be at:


If you’re on the command line something like this should set up a remote:

$ git remote add web ssh://<username>@<server address>/var/www/www.domain.name/git
I've assumed you already have your local repository set up and are checking code into it. 

Some points to bear in mind. The post-receive hook is run by the user who is doing the push. You can see who this user is by looking at the username defined in the config file for the remote. The directory specified by “core.worktree” will need to be writable by that user.

Also if you want to checkout a specific branch change the line “git checkout -f”  to “git checkout  branch-name -f”

If you get an error that git can’t update a working copy try creating a new branch on your local machine, pushing that to the remote, checking it out on the remote, then try pushing your original branch again.

As I said before, I am still testing this set up. My next step will be to alter the hook script to account for user uploads and config files specific to a server. I imagine this will be done by creating a symlink from the nondeployed directory to the public_html directory.