23

In a continuously developed web project (not a product) we currently have the following branching strategy, roughly based on git flow:

  • develop branch: latest working version
  • master branch: version to be released / released version
  • feature branches: features in development
  • hotfix branches: urgent bugfixes in released version

Master is read only, updated via pull requests from develop or hotfix branches. Each update results in a release candidate being built and deployed to the staging system. Release candidates are deployed to production after manual approval.

Feature branches are created based off develop, or from the last commit that has been merged into master. A pull request from a feature branch to develop is built, deployed to a free test system where integration tests and acceptance tests (automatic & manual) are executed. When successfully tested and reviewed, the PR gets merged, so that it will become part of the next release (i.e. merge from develop to master).

My goal

I would like to simplify this and get rid of the develop branch. The develop branch has mostly historical reasons and since it is always a successfully tested version, I think it is unnecessary to keep it separated from master. Removing it will also simplify the release process because there is no additional merge anymore.

I have the following constraints:

  • releases are scheduled and should not be fully automated
  • while feature branches are typically short lived, some stay unmerged for several weeks (e.g. a redesign) but need to be tested as well (currently as open pull requests to develop)
  • sometimes a single feature should be released outside the regular release, effectively turning it into a hotfix. With the current strategy I can rebase a feature branch and merge it directly into master
  • it also happens that we need to hold back features after acceptance tests with external systems on staging failed

Where I am not sure about the transition:

  • currently I am building pull requests for testing and merge commits for releases. Can I unify this?
  • how to deal with hotfixes when the master is ahead of the latest release. Should I build and deploy releases directly from hotfix branches?
  • is there a sensible way to deal with features that should be excluded from a release after they have already been merged? Is a separate develop branch really an advantage for these cases? Most of the time I end up reverting and re-reverting commits manually anyways.
6
  • 4
    It seems that on the one hand, you say you don't need the DEV branch, but then go on to explain why you really do need it. Feature branches that live for weeks would be very difficult to merge to master after diverging for that long. Are you sure you want to do away with DEV? Mar 2, 2017 at 12:58
  • @DaveSwersky good question! I am not sure, that's why I am asking here :) About long lived feature branches: the difficulty to merge is a problem that already exists and would just be moved to another place. And with regular merges back from the main branch it's doable. How would it be more difficult if the main branch is master? Mar 2, 2017 at 13:05
  • Long-lived branches will always be a challenge, though perhaps more of a challenge merging to master than to a DEV branch. The solution to that problem may be to break the work apart better to keep those branches short-lived. If you can prevent topic/feature branches from living more than 24-48 hours, you might have better luck eliminating DEV. Mar 2, 2017 at 13:08
  • 1
    @FabianSchmengler What is the real reason you want to remove the dev branch? It really sounds like you need it for cases when things don't go as planned.
    – avi
    Mar 2, 2017 at 13:32
  • call it master or develop or whatever you want, you will need an integration branch if you want to have real CI, or if you delegate it to the feature branches, it will only be outer integration of them against current release in isolation. Mar 3, 2017 at 18:48

4 Answers 4

8

IMHO the problems you're facing are just a side effect of the poor branch strategy you started with: you're effectively plowing new development on develop (i.e. what converges towards the future production code) through the current production code on master. This leads to contradicting requirements and problems since typicaly the future code diverges from the current one:

  • the new development destabilizes production - regressions seen after merging develop into master
  • stabilizing the production slows down future development - you need to stabilize develop to make it good enough for merging into master

Dropping develop won't help (much) - you're not eliminating the problem, you're just transferring the develop-specific portion of the problem into master.

A better approach would be to move the production behind the current/future development, to prevent interference with development for future releases, as illustrated in this image from What is Your Branching Model?:

enter image description here

Please note that I'm only referring to the release branches in the above image, not on what's happening in the trunk.

How would this work for you:

  • the develop branch dissapears, as you wished, absorbed into master
  • the master branch is your trunk, this is where development happens with no speed restrictions (it's never merged into production).
  • production is/are one or more release branches pulled from a master label/tag considered close enough to production quality (a short list of remaining todo items can be addressed in that branch if needed). These branches can only receive direct hot-fixes and/or cherry-picked fixes from master, they are never merged with master or other branches
  • hotfixes are direct commits into release branches

If a hotfix applies only to a production version but not to the master it is directly committed to the release branch. If it applies to both it's typically committed to master first and cherry-picked/double-committed to the release branch as well.

Now looking at what goes into master (which is past the point where the current release branch is pulled off), you have 2 options:

  • continue with feature branches just like you do today, except they'll be based off master, not develop. Converting them to hot fixes remains possible - you'd just have to rebase them to the corresponding release branch instead of master
  • switch to continuous integration and reap its benefits (can be done at any time going forward), including in a progressive manner - gradually pull fewer and fewer feature branches.

If you like this approach here's how you get there from where you are today:

  • establish a release naming strategy:
    • you can't have an ongoing release branch with the same name
    • you can't (shouldn't actually) rebase or sync a production release branch
  • pull a releaseX branch from master immediately, following that naming strategy
  • stop commits from going into develop, they'll be soon going straight to master.
  • merge develop into master
  • instruct developers to rebase their workspaces on master instead of develop.
  • open master for commits
  • delete develop if you desire (or leave it permanently locked/read-only for reference)
6
  • Thank you for the detailed suggestions. I'm not sure yet if release branches are a good idea outside of product development, but I'll reconsider it, it could make sense for this project Mar 31, 2017 at 19:39
  • You also have the continuous deployment alternative, which puts the development in the same place with the production (as opposed to pushing through or preceeding it), but for that you need a culture shift (as it implies dropping all integration and feature branches). Mar 31, 2017 at 20:04
  • I recognize that diagram :)
    – paul_h
    Apr 1, 2017 at 23:10
  • I have a doubt about committing hotfixes in master first and then cherry-picking to release. Example - my manager asks for a hotfix. If I implement it on master and then pick it into a release branch, it can (by Murphy's law, master will have code changes that affect the hotfix) turn out to be incompatible with the state of the release branch. So, now I have to spend time on rewriting the hotfix specifically for the release branch and also explain to the manager why I couldn't fix the issue on the release branch first to deliver it ASAP, and later deal with fixing the hotfix to fit master. May 6, 2020 at 13:01
  • @JustAMartin: either order works just as well, the master and release branch(es) are totally independent. If you have incompatibilities, though, the hotfix is NOT equally applicable, it can't be cherry-picked. May 6, 2020 at 15:51
11

Let's say you take out the master branch (you can rename develop to master to confuse your team if you like later) and simply use tags for releases either on develop or hotfix branches. You took out a branch, but the difference is just a change in syntax. Change for change sake.

Now let's say you actually take out develop with keeping the locked master branch. What will happen is that integration of code will slow, it will live longer separated in feature branches, especially close to release dates. This will Increase the difficulty of merging each time and slow the process down.

Within the constraints you have laid down I don't see any positive effects of making such change. It would require relaxing the constraints, especially the first one.

5

You are already building and testing code on each of the pull-request and hot-fix branches. This means that in aggregate, the sum of all branches pending on pull-request are your virtual develop branch.

You can create a system when in a test environment, several pull-requests are cherry picked into a temporary branch that is not published to the main repository. This branch is used to integrate a test environment that includes master and several additional pull-requests, but once the testing is done, this branch is no longer available anywhere.

When you create a release from master, you would usually create a tag on that release. Later hotfixes can use that tag to create a new hotfix branch from which a deployment will be made, even though the edge of master is already ahead. On this hotfix branch you would probably also tag a minor release, and make sure that the changes were merged into master.

Removing merged features from a release is quite hard to do with git. The best mechanism for this would be to use git revert on the merge commit. But that makes it almost impossible to get these features/changes back, and history becomes all muddled.

A much better way to handle separation for deployment of code, and release of features, is feature flags. If your developers can hide their features behind some conditions in the code itself, you could deploy their code, but turn off the feature. This is a separate topic, but a lot of information about this exists (including a Q&A on devops.SE).

3

Well @dan-cornilescu says it well for your particular problem, but the more general case for Trunk-Based Development (mentioned in the Continuous Delivery, Lean Enterprise, and The DevOps Handbook) is made here: https://trunkbaseddevelopment.com/

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.