I’ve been thinking a lot about best practices regarding branching in distributed version control systems such as git an mercurial (the two dvcs’s I have experience with and use on a daily basis).
The way I’ve been doing it is slightly different in each of these, but generally follows these guidelines:
- master branch – concurrent with production code
- development branch – concurrent with “beta” code
- feature branches – for feature development
Development is done in a feature branch (usually created off of the master branch, so we know we’re working with a stable code base), and when dev is completed, reviewed, and developer-tested, it’s pushed/merged into the development/beta branch, put out on a beta server, and tested.
If all goes well, the feature is approved, and we can merge it into the master/stable branch, stage it, do final testing, and get it into production.
If it doesn’t go well, though, things break down. If, for instance, a feature is scrapped or just delayed indefinitely, we probably want to remove it from the dev/beta branch. However, since merges from master/stable (hotfixes, content changes, etc.), and other new features have probably been put into the dev branch, it becomes difficult to remove a single feature from that branch.
I’m coming to the conclusion that this workflow is just broken, but it seems like it should work. So, specifically:
- Is it possible to remove a particular feature from this type of branch?
- Is this just a broken workflow?
And more generally:
- Given long-term development of features, and a need to have a branch concurrent with live, what are the best practices involved in dvcs?
5
I think the workflow at its core is fine and basically follows the ideas presented here: A successful Git branching model. However, I think the reason it breaks down for you is because you are essentially “off by one” in the merging and testing process:
- Feature branches should be based off of the development branch instead of the stable/master branch. Long-term features are continuously rebased on top of the development branch.
- Feature branches should only be merged into the development branch when they are ready and approved for next release (i.e. when merged, it will definitely go into the next release.)
- When preparing a new release, a release branch is made off the development branch where final testing is done before merged into the stable/master branch for production.
Things definitely gets a little more complicated when a feature depends on another feature not yet merged into development, but as Doc Brown mentioned in his answer, I think “feature toggles” is a good idea here. The nearly completed features are merged into development, but disabled for production use. Dependent features are then rebased on top of development and merged when ready.
2
I think removing an already integrated feature after a merge is hard with most VCS (or DVCS), so you should make sure that this situation happens as seldom as possible. Some ideas:
-
If you have a feature for which the approval is at stake (for example, you need a usability test first before you are sure that you are creating the “right” thing), make sure your testers make that usabilty test already with a version from the feature branch, before integrating it into development branch. So you can avoid the integration if the feature is at stake
-
To my experience small feature slices have a lower risk of getting scrapped or delayed than big ones, since one can make them much easier and quicker production-ready. So try harder to make feature slices as small as possible.
-
If you have a more complex feature, consisting of a dozen (or more) feature slices, and you want the final user to see that complex feature only as all-or-nothing, introduce feature toggles into your code, and use a feature branch for each slice, not for the whole thing. This does not really make it easier to “unmerge” any feature code afterwards, but if, for example, after the integration of half of the feature slices into the dev branch someone decides not to complete the whole thing for the next release, you can leave the finished feature slices in the dev branch, without activating the feature toggle. So your users will not notice that there is a half-completed feature in there.
EDIT: If you really get into the need of “dismanteling” a feature at a point in time where parts of it have been integrated into the dev branch and got mixed-up with other changesets, you have the option of using a separate feature branch (or should I say “feature-like branch”?) for that task. You change and/or delete the relevant parts of the code within that branch, developer-test it and then integrate that change set into the dev branch again.
EDIT2: read this blog post of Martin Fowler for more information about feature toggles.
5