views:

1339

answers:

3

What is a good deployment strategy to use with Git + Heroku (ruby on rails)?

Currently the way I work with my origin git repository: All features (or 'stories') are first checked out as branches, then get merged with master and pushed to origin.

Anything pushed to origin/master triggers a script that pulls the new rails code to the staging area (simple rails webserver).

When the time comes for me to push a new production version to heroku, should I create a new branch (called something like production_version_121), and push that somehow to heroku?

Ideally I'd like to pick and choose which features from previous development versions I should include into the production branch... test it, and push to heroku.

For example, I may not want all the latest code to get pushed to production. I might want feature "a" that I had worked on and feature "c" both merged into production somehow, without including experimental feature "b" which needs more debugging.

N.B. I'm going to try avoiding capistrano at first and get something working manually for now.

Thoughts? Best Practices?

+3  A: 

There are a variety of ways to go about this, and it really depends on your preference.

I'll give you one possible strategy off the top of my head: Given you already have an automated staging setup that uses master, I would suggest creating a 'production' branch. When you want to promote a fix/feature to production, you would just merge the topic branch into your 'production' branch.

git checkout production
git pull . my-topic-branch
(resolve any conflicts)

When you are ready to actually push that code to your production server, you should tag the branch using a unique name (probably with a timestamp). Then you simply push the production branch to Heroku.

git checkout production
git tag release-200910201249

I'd suggest creating a script or git alias to automate the tagging for timestamps, since using a consistent naming scheme is important. I use something like this:

git config alias.dtag '!git tag release-`date "+%Y%m%d%H%M"`'

That allows me to do just type git dtag when I want to tag a release with a timestamp.

You can view you tags using git tag and view them using git show release-1234. For more information on tags, run git help tag. You may also find this Github guide on tagging helpful. I'd also recommend reading up other people's workflows (here's a nice writeup) and pick and choose what works for you.

ry
Thanks for the reply!I'm not too familiar with tagging or what it actually does... although I understand (mostly) what your advice is, it would be great to have a short example or run-through of the process via git commands.Thanks again!
Zaqintosh
I've added commands for tagging and a handy alias I've used in the past. Note that these are for a local repository. You can push tags to another repo using 'git push --tags'.
ry
+7  A: 

In the Gemcutter project we simply have a production branch. Any changes that we want to see on the production site get merged into that branch, and then deployed with:

git push heroku production:master

The staging branch serves a similar purpose for the staging site (also on Heroku)

David Dollar
Thanks David! I was curious if anyone was doing it that way. Right I'm I'm just using my remote "master" as the production.. so to deploy I just keep doing: git push heroku (when the time comes)Problem is, I don't yet have features I want to pick and choose to include in a production deployment yet... I expect the need to arise, in which case I'll have to start a legit "production" branch on my remote git server. The next time I try it with: git push heroku production:master I assume it will complain and I'll need to use the "force" flag so heroku throws away what it was tracking?
Zaqintosh
My only other question is, are you using your remote master for anything? Or do you work in branches and deploy / merge to/from branches 100% of the time?
Zaqintosh
Whether or not you have to force will depend on if "production" is a direct descendant of what currently exists on the remote master.Gemcutter uses the "master" branch as trunk. It's where all the latest changes go. Feature branches are created, then merged back into trunk. Sometimes individual commits or feature branches are merged into the production branch, sometimes master is merged directly if we want it all.
David Dollar
Follow-up question: Created a "production-release-feb" branch and I reset --heard that branch to the last commit that was sent to heroku production. I want to push a specific "feature" into heroku, so I've been "cherry-picking" various commits related to that feature and bringing them into that production branch for the heroku push. So far its going fine, but what happens when I later (some future production push) want to merge (or cherry pick?) commits that I skipped over? Also, what about migrations that I skipped over? Won't those be ignored by rake if it ran a later migration?
Zaqintosh
A: 

Ever since I read Vincent Driessen's A successful Git branching model, I have been hooked. My entire company (8 of us) have now standardized on this model and a few other places I've consulted with have also started using it as well.

Most everyone I've shown it to says they were doing something similar already and found it very easy to adapt.

In a nutshell, you have 2 branches that are permanent (master and develop). Most of the time you'll just be making branches off of develop and merging them back into develop. Things get a little more complex when you get into doing production releases and hotfixes, but after reading the post a couple of times, it should becomes engrained.

There's even a command line tool called git-flow to help you out.

Jared