Saturday, September 19, 2009

Git Deployment Workflow and a Capistrano Recipe

After experimenting with several workflows for deployment in git, I've finally found one I really like.

  • You can push to staging at any time; every staging push is automatically tagged with a unique tag.
  • You can only push an existing staging tag to production. This helps to enforce QA of all pushes to production.
Using tags instead of branches has a lot of benefits:
  • No permanent remote branches on "canonical" git repo
  • More transparent historical record of what's been pushed where & when, and easily seeing what's changed between deploys
  • Uses tags for what they're meant for instead of "hacking" branches to do a job they weren't meant to do
One of the coolest things that fell out of this new workflow is the ability to see a changelog between two points:

$ git log --format=oneline production-2009-09-09.6..production-2009-09-17.11
5c0b4c9a3f45471926d8372d6dd3606b107ea3d3 Fix rake externals task to properly update phocoa cache. fix copy/paste naming bug.
62a943e96e90935c491f589efdc926c6975f7fb6 Merge branch 'master' of
9a5bd41d9ab9947b134db72bba2a226ed36107f8 [Story1111494] Make 0-priced syndicators show up as free.
8248fb1eecfc2c59007a99ab499bf6d86942d055 [Story1301780] Added a link to the dashboard on the main admin page
e2af47e70b3ba75fdd9c253f349ef35b7c61c01f Added site-wide stats and changed colors on all graphs
66b37218a4342f2e4ef6b16bd120f6e350284fea Merge branch 'master' into fixing_tests
The concepts used in this workflow can be used with any deployment engine, however we use Capistrano and have published our git+capistrano deployment recipe that allows you to easily implement this workflow in any git+capistrano project.

Requires the cap multistage extension:
gem install capistrano capistrano-ext

INSTALLATION: require the gitflow file after your multistage require
require 'capistrano/ext/multistage'
require 'git-deployment/gitflow.rb'

Expects stages "staging" and "production".


Whenever you want to push the currently checked-out code to staging, just do:

cap staging deploy

gitflow will automatically:
- create a unique tag in the format of 'staging-YYYY-MM-DD.X'
- configure multistage to use that tag for the deploy
- push the code and tags to the remote "origin"
- and run the normal deploy task for the staging stage.

Whenever you want to push code to production, you must specify the staging tag you wish to promote to production:

cap production deploy -s tag=staging-2009-09-08.2

gitflow will automatically:
- alias the staging tag to a production tag like: production-2008-09-08.2
- configure multistage to use that tag for the deploy
- push the code and tags to the remote "origin"
- and run the normal deploy task for the production stage.

Influences and References: