We’ve switched to git at work a few month ago. Not an easy task but the rewards are worth the trouble. Our branching model was based on Git Flow because it’s well documented and gives you a structure to start with DVCS. Well, after a few iterations it wasn’t working as expected in our context. So we had to come up with our own workflow.
I guess Git Flow works well on a clean code base with good test coverage. But on legacy code, where one feature means two regressions, a release branch is like the vietnam war, you never know when you will get out of it. That was one of our main problem on subversion, we were creating release branch to go to production. And it would take forever to actually ship the code. Meanwhile all other development efforts remain stuck.
I though that cheap branching and merging in git would solve our issue. But cheap merging is not enough, you also need to be able to easily pick what to merge. And with Git Flow it’s not easy to remove a feature from a release branch once it’s there. Because a feature branch is started from develop it is bound by its parents commits to other features not yet in production. As a result, if you merge a feature without rebasing you always get more commits than wanted.
So here is the workflow we use to solve those issues:
The main branches
We have three branches with an infinite lifetime based on the classical trio (dev/test/prod):
Master is the same as in git flow:
origin/masterto be the main branch where the source code of
HEADalways reflects aproduction-ready state.
Staging is a bit like develop in Git Flow :
origin/developto be the main branch where the source code of
HEADalways reflects a state with the latest delivered development changes for the next release. Some would call this the “integration branch”.
Develop is there for continuous integration, this is where we constanly merge all the changes to detect bugs and conflicts as soon as possible. The source code in the develop branch never reach a stable point where it is ready to be released. Instead only some feature branches reach a stable point. Those stable feature branches are merge into the staging branch. Since feature branches were created from master and not from develop we can pick individualy which one will be merge to staging. In fact this is the main point of this workflow: We can easily choose which features will go into production next.
To release the code to production we just merge staging into master.
All work is done in feature branches which can be merge into
- master for a quick fix in production
- staging for bug fixes
- develop constanly for continuous integration
Since we use github we usualy do a pull request to merge feature branches. We don’t always follow the rules and commit on master and staging happens, they are merge back to staging and develop. The only place where we don’t commit is develop 😉 (only merge commit)
Git Flow was not working for us, but by creating feature branches from master instead of develop we gained the ability to easily choose which features we release next. This gave us much more flexibility and got us out of “vietnam release branch”.
Now I should tell about all the best practices to make this workflow really work, but I’m lucky, someone already wrote them down.
And you, what is your branching model ?
What happens with the dev branch when you decide not to release a feature? From your diagram, it looks like it would have already been merged into the development branch. Do you have to back it out?
Yes you have to commit on develop to remove it. But this is an exception, we often postpone a feature but haven’t yet dropped one.
“And you, what is your branching model ?”
Well, here’s mine, for bugfixes anyway:
To me as well, git flow seemed like it would be too restrictive in certain situations (with the caveat that I have not tried to use it myself.)
Nice, I like the idea of branching from the commit that introduce the bug.
This seems to make a lot of sense, also great for explaining some of Adam’s points (great stuff but isn’t the easiest to interpret).
1) why swapping branch names “staging is like develop”, “develop is for .. integration”, why not simply “integration” and “staging” (sames qa in Adams post)… The legacy of using git-flow earlier?
2) Anything special to follow up those features that missed a release? I guess they should syncup with master (rebase or merge)
3) How do you handle the frequent merges from -unfinished- features to develop?
Since develop is only for CI, (if you’re using Jenkins’) could the auto-merging save the manual work? (e.g with branch config: feature/*)
Hello Gergo thanks for you comments
1) develop and master is pretty standard in the git world. Staging is just a translation of the french word “recette”
2) In general it’s bad to keep a feature branch too far behind master. We merge master to the feature to keep in sync. You can’t rebase, if you do this you get conflict when you try to merge again to develop (but may be I’m doing it the wrong way, I’m no git rebase ninja)
3) Well branching and merging is so cheap in git that we did not bother to automate the merging to develop. And we use github pull request which make merging even easier. But in a continuous deployment’s spirit your idea is worth a try.