The things you need to have in place though are Continuous Deployment (http://en.wikipedia.org/wiki/Continuous_delivery), Test Driven Development (http://en.wikipedia.org/wiki/Test-driven_development), Agile (http://en.wikipedia.org/wiki/Agile_software_development) and the desire to keep releasing small independent incremental features without any one of them blocking each other.
So the key is branches (obviously). We have 2 main branches which are shared by everyone, and every new feature takes place in a feature branch.
Our 2 shared branches are
When we start a new feature, we do all the work in our feature branch which we cut from master. Our feature branches are named by ticket number (i.e. 575-add-invoice-to-order) so that they can reference our JIRA tickets (though any ticketing system will do) and we can keep track of them.
If you have been working on a feature branch for a long time, it is worth occasionally rebasing or merging from integration to keep it fresh.
When we think the feature is ready for the business owner to inspect, we merge it into acceptance and once this build is green, we deploy it to the acceptance server for the business owner to look at and (hopefully) accept. If for some reason the business owner needs some changes, we do them in our feature branch and then re-integrate into acceptance and then redeploy. Rinse and repeat until accepted.
Periodically, we will wipe the acceptance branch (when there are no pending stories in it) and re-cut it from master to weed out any stories that never get accepted (due to changing business needs).
Once the feature has been accepted, we merge it from our feature branch into master. Never merge acceptance into master as it may have other unaccepted stories in it.
Once master is green, deploy it to the staging server to test the actual build. Once the feature is checked on staging, we deploy to our production servers and do another feature check. Master should be deployed as soon as it is ready (i.e. don't let it hang around).
No downtime releases
We strive for no downtime releases most of the time, but occasionally we will need some scheduled downtime. If the feature one is working on does need downtime, we normally hold off on merging it into master until about an hour before deployment and we make sure everyone knows about it (it's quite rare though). We even deploy migrations without downtime provided we are only adding fields or tables (renames do require downtime unfortunately).
So what advantages do we get from this workflow? Well, mainly, none of us are blocking each other. All of us can release without having to worry about the state of our coworkers' stories/features. Some features take longer to get accepted than others and it gives the business owners more time to examine a feature before accepting it.
The downsides are minimal once you get used to the flow, but there is a little bit of complexity to take on when you first get on board. There is a lot of merging going on and sometimes you might have to fix merge errors twice (once in acceptance and once in master).
The other downside is if your feature does actually have dependencies on another feature then you need to wait for it to get integrated before you start working. It is possible, if you can't wait, to cut from the other feature branch instead of master, but it is not a risk free approach (especially if the first feature gets cut or rejected or delayed).
This flow also works best if all your developers are full stack or vertical, rather than horizontal. It is the case in our team that some of us are more geared towards the front end and some of us are geared towards the back end. We normally get around this either by sharing the feature branch or else by doing code reviews.
In summary, our git workflow is the following
- Feature branches for all new features
- Merge feature branch into acceptance and deploy on acceptance server for the business owner to accept
- Merge feature branch into master and make sure build is green.
- Deploy on staging and manually check
- Deploy to production and manually check
- Hotfixes are done on master deployed ASAP
- acceptance is periodically deleted and re-cut from master