Skip to main content

Deploying With Git

I have the misfortune to work on a number of PHP based web applications at work. Previously, the deployment process involved determining which files had changed since the last release and copying them across to the server. Needless to say, this was an error-prone and inefficient way of deploying updates.

Gitobots, Roll Out

We use Git for our version control and, with Heroku's push to deploy in mind, I looked further into the possibilities of using Git for our deployment process. Abhijit Menon-Sen's article details the process very well. With a few slight variations, these are the steps I follow to deploy changes via Git.

Prime Remote

On the remote server for your application (e.g. production, staging or test), create a new, bare Git repository for your codebase:

cd /cygdrive/c/repo
mkdir project.git
cd project.git
git --bare init

Hooks

As this bare repository does not contain a working tree (the actual source), a Git hook is used to checkout the code to a specific location. Git hooks allow custom scripts to be executed when certain important actions occur.
  1. Create the directory from which your application is accessed/executed - e.g. /cygdrive/c/webroot/project 
  2. Create the file post-receive in the project.git/hooks directory. 
  3. Edit the file to include the following:
    #!/bin/sh
    GIT_WORK_TREE=/cygdrive/c/webroot/project git checkout -f staging
    rm -rf /cygdrive/c/webroot/project/twig_cache/*
    
  4. Set the file to be executable - e.g.:
    chmod +x post-receive
    
The main point of this hook is in the configuration of a working directory and the checkout of a specific branch (staging in this case) to this location. I also utilise the hook to clear out a cache directory for a templating engine (Twig) used in the application.

Push It 

Within your local development repository, add the bare repository as a remote:

git remote add staging-web ssh://keibro@127.0.0.1/cygdrive/c/repo/project.git

Once you have committed your local changes and are ready to deploy to your server, the server code base can be updated by pushing to the remote repository:

git push staging-web staging

The remote repository should update and also note that it is already on that particular branch. The updated files should now be present in the working directory.

Note: it may be necessary to manually execute the post-receive hook for the first push.

Branching Environment

The above process can be replicated for various environments so that changes can be pushed to these environments as needed (e.g. test, staging, production). Following a similar model as described by Vincent Driessen, I utilise different branches for each environment (e.g. the staging branch is pushed to the remote repo staging-web, the master branch is pushed to the remote repo production-web). However, this generally implies that each environment will require unique configuration settings.

In order to address this issue, I created a new local configuration file to supplement a more generic configuration file.
  • config.local.php contains configuration settings that are unique to that environment - e.g. database connection details, email settings, etc. Note: This file is not under Git control, as you do not want to commit any changes from this file across all your environments. Changes need to be made to each environment individually - these changes are normally relatively infrequent.
  • config.php contains generic environment settings that apply across all environments - e.g. global constants, LDAP server connection details, etc. This file is under Git control.

It is necessary to ensure that all environment specific variables are extracted into appropriate configuration files (e.g. REST access points for your Backbone frontend, database connection, etc.)

While not optimal, this solution addressed the problem at hand.

Restricted Access

As all files under Git control are now pushed to the server, you may wantto ensure that some files are not accessible when accessed via the web browser. In this case, I created a new directory restricted within the project and included a .htaccess file to prevent access to the files contained therein.

Comments

Popular posts from this blog

Brain Error: No space left on device

I'm not dumb. I just have a command of thoroughly useless information. Calvin - It's a Magical World, Bill Waterson Wired's June 2008 edition included an article entitled ' Quiet Please : how Man-made noises may be altering Earth's ecology'. The article focused on the theory put forward by Bernie Krause , a field recording scientist, that nature's soundtrack (biophony) is being adversely affected by a louder human-made cacophony (anthrophony). Krause postulates that the animal kingdom divides the acoustic spectrum so it's inhabitants do not interfere with each other. However, human-made noise is increasingly disrupting this harmony and intrudes on a piece of the spectrum already in use - drowning out natures voice. As an example, Krause summizes that the rapidly declining population of the Yosemite spadefoot toad is due to the noise generated from low-flying military aircraft, performing training exercises in the area. Coyotes and owls are able to home ...

Local Testing OAuth Social Signin

On some recent Grails projects, I have been looking at using the Twitter and Facebook OAuth signin process. This process allows you to authenticate users based on their Twitter/Facebook logins, without the need for the user to expose their passwords to your site. When you create your 'application' within Twitter or Facebook, it is necessary to define the URL where the application can be accessed. Twitter and Facebook will only redirect to this URL during the authentication process. I have tested running some applications on Heroku or Appfog , with Twitter and Facebook happy to redirect to the appropriate URLs with successful authentication. However, when testing locally, I follow these steps to work through the authentication process. 1. App Context Ensure that the Grails app context is '/' - as the application is generally deployed this way on Heroku/Appfog: Config.groovy grails.app.context = '/' 2. Port Binding: While the local application w...

Explore. Dream. Discover. Be Interesting.

Interesting 2008 Bunting and all ... Twenty years from now you will be more disappointed by the things that you didn’t do than by the ones you did do. So throw off the bowlines. Sail away from the safe harbor. Catch the trade winds in your sails. Explore. Dream. Discover. Mark Twain Over the weekend, my wife and I attended Interesting 2008. The concept of the event - to gather a number of speakers to talk about something they are interested in - was intriguing and all reports suggested it would be a Saturday well spent. Comparisons with the TED talks certainly helped to pique my interest and we were most definitely not disappointed. Russell Davies , the coordinator of the day, has this to say about being 'interesting': The way to be interesting is to be interested. You’ve got to find what’s interesting in everything, you’ve got to be good at noticing things, you’ve got to be good at listening. If you find people (and things) interesting, they’ll find you inter...