21

I am thinking of extending the git-flow model for my current workplace, due to a particular scenario. But my scenario is so common that I'm surprised no-one's done this before with the git-flow model, and this makes me think I've missed an obvious problem. My question is: Is my proposed extension flawed?

The scenario: I have a number of development teams who develop from a common codebase, and we push out releases through several (permanent) environments: first to the systems integration environment (SIT), then to the UAT environment, then to pre-prod, and finally to production. This is strictly sequential, although any release candidate may fail in any environment, and so not make it any further. Thus each later environment is simply a slower-moving version of the previous environment.

We are introducing git for source control, we need a workflow, and git-flow looks like a good start.

We asked ourselves how to capture (i.e. how to know) what's in each environment at any time. The git-flow model seems to have essentially two core states: main and develop. They have an "infinite lifespan". Other branches are just "supporting branches" with a "limited life time". They exist only to allow development and to go from development to production (via a temporary release state). The git-flow model is based around going from development to release.

However, this doesn't map logically onto our scenario, with its multi-stage release sequence. I'm fine with the develop branch, of course. And the main branch clearly does map to our production environment. The original git-flow description says this about main:

Therefore, each time when changes are merged back into main, this is a new production release by definition. We tend to be very strict at this, so that theoretically, we could use a Git hook script to automatically build and roll-out our software to our production servers everytime there was a commit on main.

Since main is a continuous record of production, it seems consistent that we should extend the git-flow model to have corresponding branches for SIT, UAT, and pre-prod. After all, they are permanent environments, with strict release procedures. They just change a bit quicker than production.

These additional, permanent, branches sit between develop and main, just as their corresponding environments do.

This now means it's easy to track releases to each environment, and the state of each environment. And merges for each are easier, too: the SIT branch requires a merge from develop, the UAT branch requires a merge from the SIT branch, the pre-prod branch requires a merge from the UAT branch, and finally the main branch (for production) requires a merge from the pre-prod branch. Each later branch is simply a slower-moving version of the previous branch.

Have I missed something?

Ali
  • 261,656
  • 265
  • 575
  • 769
Nik Silver
  • 364
  • 1
  • 2
  • 10
  • You could achieve the same thing by only doing fast-forward merges to your other branches. Now they are simply pointers at past states of `develop` and you actually didn’t really change the git-flow model :). – Chronial Jul 02 '13 at 23:47
  • I'm wondering if u were able to implement this branching strategy. I'm having the exact same requirements. I have the following environments: DEV - INT - QA - PROD. I was thinking to do exactly what you did. I'd like to have a branch for each environment with an infinite lifespan. Could you share your experience implementing this branching strategy? In your experience you think this is worth it? – Jupaol Jun 23 '14 at 19:03
  • Actually, we didn't implement this in the end. We went for no branches at all (well, other than master, and the occasional branch to fix a bug in a previous release). Every pushed change was rebased onto the end of master. It was much simpler, as the team was new to git. It forced individual devs to push small coherent changes frequently. Also, by having a single straight line it meant history was much easier to trace for the support team, which was separate from the dev team. Given the choice I'd do it this way again. – Nik Silver Jun 24 '14 at 20:17

1 Answers1

17

There is no reason I can see to adapt the flow against your model. You say you work sequentially SIT -> UAT -> Pre-Prod. Perfect. Once develop is stable (i.e. all features due for release are feature-finish[ed]) then do release start and move this to your SIT platform for QA. Once the release start has taken place, development can continue on the develop branch. master stays static until the release is completed.

Once QA is satisfied then the release branch gets moved to UAT. UAT passes and the code rolled to live and you carry out release finish to merge back to master / develop.

master should always be a reflection of what is currently on the live platform whilst develop is a reflection of code under active development. release branches contain a static cut of develop against which bug fixes are applied (no new features ever get pushed into this branch or you're not using git-flow).

Based on your description I'd be inclined to say you have mis-understood the git-flow model because from what I can see it fits perfectly into the scenario you describe, all you need to care about during SIT -> UAT -> Pre-Prod is the release branch, "forget" master / develop even exist at this stage.

Response to comments

Since I first posted this answer there have been a number of comments which have raised questions about how the model works in a number of different scenarios.

  1. Client has requested improvements to existing features

Answer:

DO NOT (I cannot stress this strongly enough) allow new features / enhancements to be added to the release branch. This is scope creep. New features are new work. They need to be costed for separately and must be treated separately. Whether your client is your own company or a 3rd party, the one thing they understand is cost. Point out to them that if they interrupt the release it will delay it [indefinitely] or existing testing will suffer. Treat the release branch as you would master. It is sacred. Only bug fixes are allowed against it.

  1. Branch longevity

If your release branch is lasting months, your release cycle is too long. I've worked in places where the release cycle is, on average every 3 weeks and other places where we released every couple of days. 3 weeks should be ample time to QA and UAT a release branch. If you're looking at a longer cycle then I would argue that the company isn't agile and

  1. git-flow is the wrong branching strategy (doubtable, it works in almost any scenario as long as it's carefully managed)

  2. You seriously need to challenge the company on why they have such a long cycle

  3. (most likely) - you don't understand Git-Flow

    1. CI

I have used Git-Flow very successfully with CI. Although this has mainly been Jenkins and Bamboo, it also works with Travis CI.

A Git Hook based on commits is exactly how any branch build works. The best examples I have used automatically build as soon as a commit (or series of commits) is pushed to the remote, then the hook kicks in and calls the CI platform. The CI platform then finds the related job (either using in-built templates or using a 3rd party module) to trigger the build.

My own personal setup is to trigger a local Jenkins instance when:

  • I create a branch (creates new job in local install of jenkins targeted for the current branch)
  • I commit (triggers local instance build of the current branch)
  • Local build passes, can auto-push to remote
  • I push new branch (creates targeted build in remote CI
  • I push commits (triggers remote CI targeted instance)
  • I delete local branch (deletes local job)
  • I delete remote branch (deletes remote job)
  • I raise merge request (soft merges feature/A into develop and tests - tests fail, merge rejects automatically)

This takes some configuration but it is possible with any modern CI platform.

Like anything else, the rules for using Git-Flow are only guidelines. There are no hard and fast rules. If you want a long lived release branch then that's your choice BUT unless you pay attention to them you will end up with a divergent codebase which will be hell to merge back together.

Git-Flow, like anything else that is born from *nix tooling, is simply a way of working and with it comes a great deal of choice. The tool and the workflow is nothing more than a wrapper on to GIT. How you choose to implement it is entirely up to you.

mproffitt
  • 2,409
  • 18
  • 24
  • Thanks for your thoughts. I should be clear that my extension is not the _same_ git-flow model as originally described. The original model had only two permanent branches (`develop` and `master`) while this has three extra permanent branches (`sit`, `uat` and `pre-prod`). Therefore this model has to adapt rules about merging and branching. Non-permanent release branches continue to exist in this model as before: to enable releases to each of those permanent branches. – Nik Silver Jul 03 '13 at 05:26
  • 1
    Actually, having re-read your answer I think you're saying there's no need to change the git-flow model for my scenario. The original motivation was to have a permanent record of what's in each of the environments, not just production. But the question is not "do I need to change the git-flow model?". After all, I can probably get away without changing it. The question is "Is there a _problem_ with the proposed change?" – Nik Silver Jul 03 '13 at 15:28
  • Sorry I was hoping to get a response back to you at lunch today but it's been a bit hectic here. To answer your last question first then the answer is 'No but it will cause you more problems than it is worth'. The reason here is you are likely to end up with divergant codebases in each of the branches you wish to introduce. Bugs found during UAT might have actually been fixed in SIT but unless you are diligent in ensuring each of the branches is merging continually your proposed model is likely to result in a complex stream of conflicts which need resolving. – mproffitt Jul 03 '13 at 15:33
  • Primarily your flow suggests that you do not need to change the model, you only need the release branch to go through SIT/UAT/PreProd after which it gets merged back to develop and a new release branch is cut and pushed through the same flow. This ensures that the release branch always has the latest changes / fixes in place and you haven't got a complex n-way merge to attempt every time a new bug fix is carried out during hardening. – mproffitt Jul 03 '13 at 15:38
  • Thanks for that feedback, that's good. In our case the environments are likely to be running a different snapshots of the codebase at any time (effectively a queue of release candidates). So a single release branch going through SIT/UAT/PreProd doesn't capture our real-life workflow, because another release branch will also be going through the same sequence (just a bit behind). And we must be strict with the deployment sequence, to avoid those complex n-way merges. I will take on board your caution, though. Thanks. – Nik Silver Jul 03 '13 at 16:20
  • Sometimes, UAT (performed by customers) results in new features. This is unavoidable. Half way through UAT they may request small alterations to features, or new small improvements, or features themselves. "Oh by the way let's add this...". Are you saying that gitflow breaks if you commit features to the release branch? – void.pointer Sep 02 '15 at 13:37
  • Another concern is branch longevity. Release branches in gitflow are not supposed to be long lived. They are preparation branches for release. Going through UAT process means it may remain alive for weeks or even months. – void.pointer Sep 02 '15 at 13:37
  • @void.pointer: Per git-flow new features should not be added to a release branch, rather they should be released with a future release. – gligoran Oct 10 '15 at 17:58
  • @mplf: What about CI? For example Visual Studio Online build system only supports triggers based on commits to branches, so multiple running branches between develop and master seem like the best way to go. – gligoran Oct 10 '15 at 18:02