Git workflow for cherry picking features from staging to production
TL;DR
Branches: master, production, staging. New features branched from production, merged into master, merged into staging. Deploy staging. When accepted, merge from feature branch into production. Deploy production.
Background
Wednesday was a productive day. I was rattling through the to-do list on daPulse, flipping responsibilities from red (developer to do) to purple (customer to check). It looked like a good day on the git log, too – I was getting stuff done. The GoToMeeting went well as we ran through each feature on the staging website with the customer. Until: “Good job Ian, now can you put live those features the customer’s signed off?”
I had developed features X, Y and Z but I’d only gotten sign off for X and Z.
Well, for this kind of job I would just get a list of files I’d changed that day
with a git diff --name-only firstSHA..HEAD
and SFTP them up*, but that wasn’t
going to cut it. Different commits related to different features and they weren’t
always in order – for example, if I’d tweaked a feature later on. Just one commit
after another into master.
Right, so I’m going to need some organisation. I head off to refresh my memory on git-flow and it’s good but it doesn’t fit this scenario. It fits if I’m building up a release in an organised manner where I know what’s going in now and what’s going in in the next iteration. But I don’t. Every feature needs to hang around until it’s ready to be plucked into production.
The method
We create two new branches: staging and production. These will contain exactly what’s on each environment’s server. When we start a new feature we do so by branching a new feature branch from the tip of production. We do that because we have a stable known starting point when we eventually deploy it, with no dependencies that haven’t yet made it to production.
When we think our feature’s ready, we merge it into master. master represents the collection of all features we’re working on in development. We might commit small changes here, but anything we do commit here will need to be cherry picked into production. Wherever possible we prefer a feature branch off of production.
Commits from master can be:
- Merged into staging, or
- Cherry picked (not merged) into production.
When we’re ready to show the customer we merge master into staging and then deploy it immediately so it’s on the staging server ready for customer acceptance.
Here’s a summary:
When the feature is signed off, the feature branch should be merged into production, and deployment should be made to production.
Tips
We’ll keep some sanity and have faith in deployments if the branches labeled staging and environment accurately reflect what’s been deployed to those environments.
- When deploying to production: only publish from the production branch
- When deploying to staging: only publish from the staging branch
- Deploy immediately after updating either branch
To keep things tidy, delete feature branches after they have been merged into the production branch. git will let you delete branches without warning so long as you’ve merged them into an existing branch but you will want to keep your features around at least until you’ve merged them into the production branch.
I prefer --no-ff
to see the history of each feature. It adds a lot of clarity
that can get lost in a fast-forward commit.
What might this look like?
Here’s a screenshot of a contrived workflow through developing two features. In this scenario the customer only signs off on feature 2. Note how the .gitignore commit is cherry-picked into production whilst the features are merged.
Conclusion
I am just putting this into practice for the project. I wonder about unpublished features depending upon each other and how that will impact this workflow. Ideally each feature will be self-contained, even if that means a bit of repeat code in multiple features that will be resolved (DRYed up) in a later merge.
Notes
- I prefer automated deployment whenever possible