Enter Dymitruk
You are looking for "Branch per Feature" by Adam Dymitruk http://dymitruk.com/blog/2012/02/05/branch-per-feature/ . It is exactly what you are asking for.
It has a different twist on things than GitFlow; it uses 3 main types of branches: master
, Feature branches, and a qa
branch. The latter is like your beta
branch.
master
is the version that is on your production servers right now. All other branches go off of this one.
Feature branches are just that. They always branch off of master
(which is the main difference to GitFlow).
qa
is per definition the "next" version that will be going live on the production server.
It uses heavy rebasing, together with the rerere cache of git, which avoids doing conflict resolution over and over again.
Feature branches are never merged "back" into some kind of develop
branch (there is none). Instead, at any point where you have a set of feature branches that are ready for testing, qa
is recreated from scratch, starting off of master
, and having the "ready" feature branches merged into it. No branch starts off of qa
, and you never commit anything into qa
. You also never re-merge changes from a feature into qa
, you always start it from scratch.
This sounds like a conflict nightmare, but is actually very simple. Due to the rerere cache, usually, only "necessary" conflicts occur. Every conflict that ever happened once, is then automatically resolved by git
on its own. This operation is of course automated with a relatively simple shell script.
As a side effect with huge benefits, is is trivial to back features out of qa
at any point (simply rebuild qa
, leaving out the feature).
This means that when we try to merge in a feature to beta, it includes tons of unwanted commits that happened on develop.
With Dymitruk, beta (a.k.a. qa
) starts off of master
, merging all features that are ready for testing into it.
Another problem is that when we need to create a hotfix for the entire project (to be applied to all branches), we create it from master, and it won't merge into develop without an insane amount of merge conflicts
With Dymitruk, hotfixes go into master
(of course, as master
reflects the production server). Then, all feature branches are rebased upon the new master
, and finally, qa
is created from scratch, starting at the new master
.
rebasing isn't nearly as simple as merging (and I don't even think it's possible to do without the command line).
Rebase is, in this scenario, actually simpler than merging for the very reason that rebasing applies one commit after the other, hence works on smaller units of work. Merging, instead, subsumes all commits that happened on the branches. This means that as soon as the rerere cache enters the game, git
will be able to solve most conflicts on its own.
Obviously, if someone decides to change all spaces to tabs in all your code files and starts committing such a change to master
, then you're borked. But that's no different from merging, at all; the problem just occurs at a different point of time.
As you only ever rebase feature branches, you only really get the usual rebase problem when more than one developer works on a specific feature branch at a time. You can either avoid that, by making feature branches small enough. Alternatively, you'll have to communicate between developers. But in the end, if people are aware what they are doing, then a distributed rebase is surely possible. If in doubt, you can use heavy tagging as a backup measure, to avoid actually losing anything; but you will find after a while that it really is a non-issue.
Addendum
From the comments:
Suppose somebody is working on a feature branch and they need code from another in-progress feature (this happens very often).
You can start a feature branch off of another feature branch instead of master
.
Of course, then you have to pay a bit attention; if the parent feature branch gets more commits, you want to rebase the child on it. If master
changes, you have to make sure you rebase the parent feature first, and then rebase the child on the parent, not on master
.
Regarding the qa
, nothing changes.
As you will be using scripts for the two major operations (remaking qa
, rebasing all features), it's just a matter of keeping track of this in these scripts (which does not need any additional storage or configuration; these case can rather easily be deducted with basic git branch --list
commands.
Also, is there any way to accomplish this workflow using a GUI?
You will want to have at least the (re)creation of qa
and the rebase processed scripted. Since there will be regular conflict resolutions during these, they need developer attention, and thus are probably best done by command line scripts. Of course, you can use your usual preferred git GUI for merge/rebase conflict resolution; behind the scenes, it's all just git as usual.