A quick and easy way to deploy from git with post-receive hooks

I’ve recently moved over to a custom framework for my main website and wanted deployments into the repositories release branch to be seamless. I could use Jenkins but that would probably be overkill.

To accomplish this, I wrote a quick post-commit post-receive script that will be called by git each time a commit is pushed into my repository. If the branch name matches ‘release’ the commit is extracted into a release folder under the webroot. The webroot directory (in reality a symbolic link) is then updated to point to this new release.

Using symbolic links has the advantage of not leaving your website in an inconsistant state as files are deleted and then re-extracted, it should be an atomic operation.

Here’s the script, put this in your git repository under the hooks subdirectory in a file named ‘post-commit’.
The old revision, new revision and branch name are handily passed into this script :)

Edit: One thing to keep an eye out for is that if you are running PHP5-FPM, when the symbolic link is switched to the new location the fpm seems to be still serving your scripts from the old location. I would love to figure out why this is but a workaround is to call /etc/init.d/php5-fpm restart as the final step in the post-receive script (not ideal!!)

#!/bin/bash
#
# A post commit hook that takes any updates pushed to the 'release' branch
# and creates a release directory for the new version under the webroot.
# Live site is then symlinked to this new release directory.
 
oldrev=$1
newrev=$2
branch=$3
 
# this is the root of the website (a symlink to a release directory)
webroot=/var/www/danielbyrne.net/www
 
if [ "$branch" == "release" ]
then
 
    # create a release directory to extract files into
    target=/var/www/danielbyrne.net/releases/$2/
    mkdir $target
 
    echo "Making target directory: $target"
 
    # create an archive in the webroot of danielbyrne.net
    /usr/bin/git archive master --format zip --output $target/deploy.zip
 
    echo "unzipping archive..."
 
    # extract the archive
    unzip -o -q $target/deploy.zip -d $target
 
    echo "removing deployment archive"
 
    # remove the archive file
    rm $target/deploy.zip
 
    echo "switching symbolic link to $target"
 
    # now switch the live site to point to the new release
    ln -nsf $target $webroot
 
    echo "done";
fi

5 thoughts on “A quick and easy way to deploy from git with post-receive hooks

  1. Nice ideas, thanks for posting them!

    You have “git archive master” in this script. Should that be “git archive release”?

    Also, can you skip the unzip step with something like “git archive master | tar -x -C /$target”

    I’m just going to try and get your script working on my site now…

  2. Hi There
    Have you figured out a different way than etc/init.d/php5-fpm restart

    -> I don’t have admin perssions when running the deployment script. That will not allow me to restart the fpm

    Regards
    Raphael

  3. Hi Raphael,

    I think it’s something to do with switching symlinks when apache is serving files out of those directories. I suppose you could ‘mv’ the directory and recreate it when untarring your deployment artefact but it wouldn’t be atomic and there may be downtime while doing this…

    Let me know if you find something that works for you

  4. I also have this problem with php5-fpm and nginx but the problem manifests itself only once in a long while, it seems… I just incurred in this problem on my like 50th deployment… restarting did the trick but certainly we need to avoid the restart. Maybe php5-cgi doesn’t have this problem?..

  5. Can anybody help me convert the script above to windows batch script. My git and apache servers run on windows.
    Thanks.

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>