Automated deployment on remote server with git

Some time back, I wanted to setup my server so I could push code to my repositories, and have it automatically deployed to a website root directory after doing a git push from my local machine. I can’t remember where I found the instructions so I can’t give credit to whom I got it from, but here’s how I did it.

This is followed by a tutorial on how to extend this setup to multiple branches and work-trees for “live” and “development” versions of a website.

I use this method for small personal projects where I really only need one branch to be automatically deployed. I will assume you already have a local git repository (

Head here for instructions how to, this is still somewhat valid!) with some code in it under a branch called ‘master’, and that you will push code to a remote server holding both your repository and your web server.

Create the remote repository (basic git setup)

On server:

mkdir /path/to/repo/project.git
cd /path/to/repo/project.git
git init --bare

On local machine:

cd /path/to/mycode
git init
git remote add origin git@yourserver:project.git

At this point (providing you have setup git on your server correctly, which I’m not going to cover here! This how-to is still valid) you should be able to simply push your code to your server with the usual command

git push origin master

Adding single branch automatic deployment

First, you’ll need a place to deploy your code to, that’s call the detached work tree from Git’s point of view because it’s a copy of the code without the history or references. I have both my repositories and webserver on the same machine so these instructions are for this configuration only. This detached work tree needs to be under your webserver’s root directory if you’re deploying a web site, but you could deploy that whatever place you want.

On server:

Create the work-tree directory and make make sure the git user (or the one you use for git repositories) has permissions to write to this directory:

mkdir /path/under/root/dir/project
chown git:git /path/under/root/dir/project

Then, you need to add a bit of configuration to your repository (created above):

cd /path/to/repo/project.git
git config core.worktree /path/under/root/dir/project
git config core.bare false
git config receive.denycurrentbranch ignore

Finally, all you have to do is create and make executable a “post-receive” hook in your repository’s hooks folder:

cd /path/to/repo/project.git/hooks/
touch post-receive
chmod +x post-receive
vi post-receive

And paste this code into this file:

#!/bin/sh git checkout -f

And voilà! Next time you push new changes from your local machine to the main server, the default (master) branch will be automatically checked out from your repository into the detached working tree.

EDIT: Following Luca’s comments below, it’s worth noting that if you have no local changes, nothing will get pushed, and the hook will not be fired! So when you do your next push (after all the setup), remember to edit a file to somewhat “force” a push. Then your content will be checked out by the hook. No update, no deployment

comments

  • luca Mon, 31 Oct 2011 - 21:53

    thanks! I set up this environment in my dev server and works like a charm. You might want to add an extra step: I had to checkout your branch (in this case master) before being able to do git checkout -f which is in the post-receive hook.

  • Matt Mon, 31 Oct 2011 - 21:54

    What do you mean "checkout your branch"? Where was this? On the server, your local machine?

  • luca Mon, 31 Oct 2011 - 21:56

    sorry I meant my branch :) when you do (in your tutorial) git push origin master in order for the post-receive hook to start working I had to run first git checkout master then it worked. Without doing this step first, it looks the repo is not set to any branch and a call to git checkout -f will result in a: fatal: You are on a branch yet to be born

  • Matt Mon, 31 Oct 2011 - 22:06

    Ah, it might be because you tried to push without any content changes. Doing a git push origin master with no content will not push anything, and the hook will not get fired

  • Matt Tue, 01 Nov 2011 - 23:45

    Actually, it might be because you're not pushing anything to a branch named 'master' and git fails to recognise that... I think I need to check if git implies that the push has to be on a branch named 'master'

  • Chieroz Tue, 13 Mar 2012 - 13:41

    Thank you, great advice. Just a note: I work in a Mac environment and I had to change the order of the commands on the server: first -> git config core.bare false then -> git config core.worktree /path/to/website/folder ciao

  • Matt Tue, 13 Mar 2012 - 14:01

    Interesting Carlo, why do you think that is? Does setting the "bare" configuration actually initialises the repo as bare at the same time or something like this?

  • gustavo Thu, 12 Jul 2012 - 17:44

    After deploy the files are inaccessible with browser, because now the user git is the owner, what can i do for change this? I want they are accessibles to apache.

    • Matt Thu, 12 Jul 2012 - 18:04

      Hola Gustavo! All you need to do is either make git a member of your apache group. You could add a change of ownership in the same "post-receive" hook with chown apache:apache (assuming these are your user/group names for apache), but if git isn't in the apache group, you won't be able to deploy with git next time because the file isn't owned by git anymore. The git hooks are (in this example) standard bash scripts, so you can use all your usual bash/unix knowledge to manage permissions.

  • gustavo Thu, 12 Jul 2012 - 18:49

    Thanks a lot! I just only did:

    chown -R git:www-data /var/www/gitdeploy

    • Matt Thu, 12 Jul 2012 - 19:05

      Spot on! Well done.

  • aaki Thu, 26 Jul 2012 - 13:06

    You don't need to git config core.*, see http://toroid.org/ams/git-website-howto Seems to be easier, a bit.

  • Matt Wed, 22 Aug 2012 - 10:37

    Aaaki, if this is your first repository, then you might. I've taken the point of view that you're on a fresh install and having one repository. Your link seems however a good other approach whereby setting the GIT_WORK_TREE environment variable can be done on a per project basis. Something to consider indeed!

  • Guillaume Lang Fri, 21 Mar 2014 - 15:38

    Hello, i just wont to say big thanks to you for this tip, thank you very much, and sorry for my bad english, I'm french!

Comments are disabled temporarily until I find a suitable system, but you can still send a comment by email and I'll add it to this post. Thanks!