Drupal Deployment with a Git post-receive hook

Drupal deployment and maintenance often proves challenging when teams of developers are involved in a given Drupal project. A great way to reduce deployment pains is to use a distributed version control system, and integrate deployment efforts in your DVCS. As Drupal core is using Git, I am focusing on Git as a DVCS and using Git’s hooks to handle deployment. I’ll also point out that the Git hook deployment technique discussed here works for deploying many (most) web sites, but I am going to add details on drush and features modules, and get more specific to Drupal eventually (hence the title).

There are a lot of different ways to host Drupal, and I’m going to gloss over pros/cons and many of the techniques here (it’s another post). For now, I assume the following:

  • A web server capable of serving PHP is running.
  • You have server(s) representing at least staging and production (and development on a local machine).
  • Git is installed and configured locally and installed on your server(s).

I am going to demonstrate with the fake domain: drupaldeploy.com. I assume you either have DNS configured or hosts file entries to direct drupaldeploy.com and staging.drupaldeploy.com to the same server. On that server you have users ‘git’ and ‘drupaldeploy’. Your ssh public key (and keys for anyone who needs to deploy) is present in the /home/git/.ssh/authorized_keys file. I assume the ‘git’ user can write to the webroots and they are:

  • drupaldeploy.com: /home/drupaldeploy/drupaldeploy.com/html/
  • staging.drupaldeploy.com: /home/drupaldeploy/staging.drupaldeploy.com/html/

I assume your local git repository is initialized and populated with In your git repository, I am going to assume you are creating multiple branches and not working solely in master. I assume you have at least:

  • master – this is production
  • staging – this is for staging (almost ready for production, but likely needs review or QA)
  • development – where most of your development work occurs
  • etc. – feature branches and bug fixes (use these to keep the other three highly organized and relatively stable)

This certainly isn’t the only option for branching techniques, but it’s well organized and manages to keep important branches safe. I’m basing this model predominantly on the branching model at nvie.com. Now let’s get to it.

Create a git bare repository on the server

ssh git@drupaldeploy.com
mkdir ~/drupaldeploy.git
cd ~/drupaldeploy.git/
git init --bare

Add a remote repository on local and push to the server

cd /your/local/repo/
git remote add drupaldeploy git@drupaldeploy.com:/home/git/drupaldeploy.git
git push drupaldeploy master

The hook

Check to see what is being pushed, and deploy it to the appropriate location. On the server, create the /home/git/drupaldeploy.git/hooks/post-receive file (make sure it is executable by the ‘git’ user):

#!/bin/bash

read oldrev newrev refname

if [ $refname = "refs/heads/master" ]
then
  echo "### Deploy production"
  GIT_WORK_TREE=/home/drupaldeploy/drupaldeploy.com/html git checkout -q -f master
  
elif [ $refname = "refs/heads/staging" ]
then
  echo "### Deploy staging"
  GIT_WORK_TREE=/home/drupaldeploy/staging.drupaldeploy.com/html git checkout -q -f staging

fi

Now anyone on the team can make some changes to their local repository’s master or staging branch, pull from the bare repository to make sure they’re current, and then deploy updated code with:

git push drupaldeploy master

-or-

git push drupaldeploy staging

Additional Notes

It’s easy to expand this technique to allow Drupal (and module) core installation via git. In some circumstances (particularly if you are hacking core), running Drupal and module maintenance updates through git can ease the burden of maintenance on heavily customized sites.

If you are using the Features module (hint: you should be), feature updates can be committed and imported/updated via careful commit locations and updates to your git hook. This is made even easier if you are using Drush…

If you are using Drush, you can do awesome things like importing/updating Features (i.e., check for file presence in some directory, and if present execute ‘drush content import –file %filename’), or automatically clearing the cache whenever a web root update occurs (via ‘drush cc’).

Depending on your server config, it may also be appropriate to restart services. There are permissions considerations to account for, but restarting Nginx, Apache, PHP-FPM, Varnish, etc. can be handled in Git hooks.

Further Reading

http://toroid.org/ams/git-website-howto
http://www.adappt.co.uk/automated-deployment-drupal-using-git
http://wolfgangziegler.net/git_deploy_code_changes
http://joemaller.com/990/a-web-focused-git-workflow
http://nvie.com/posts/a-successful-git-branching-model
http://www.kernel.org/pub/software/scm/git/docs/githooks.html
http://git-scm.com/book/en/Customizing-Git-Git-Hooks

Nicholas Whittier

Nicholas Whittier

Nicholas is a developer who loves to figure out how things work. Whether it is an errant bash script, missing kernel drivers, CSS conflicts, a JRE incompatibility, an unsolved Rubik's cube, or anything in between, he wants to learn why it is broken and how to fix it. Additionally, Nicholas fancies GNU/Linux system administration, database administration, Java development, and web development. 

One Response

  1. error: src refspec live does not match any.
    error: failed to push some refs to ‘ssh://git@foo.git’

    “staging” is the issue, master works as expected.

    I set the configurations equally. Thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *

Categories

Search

Recent Posts

Most Common Tags