Gitflow is a best-practice branching model for Git. It is not a simple model, but it becomes really sophisticated when you try to combine it with Maven, which has its own release workflow.
What I am trying to do here is to automate the Gitflow release actions (release-start, release-finish, hotfix-start, and hotfix-finish) for a mavenized project.

Lets take a look at the basic workflows:
(Note: have a look at the Gitflow diagramm again before continuing)

The Release Workflow

Suppose the pom.xml of the “develop” branch has version 1.5.0-SNAPSHOT (in my case, the second part contains the release version, and the third part contains the build or hotfix number).

release-start should create the branch “release/1.5” (based on “develop”) and bump the “develop” version to 1.6.0-SNAPSHOT. Next it performs a release-prepare on the release branch, which means:
  • setting the version to 1.5.0 and tagging it
  • building and publishing to the Maven releases-repository
  • bumping the version to 1.5.1-SNAPSHOT
Now the release branch is the place to perform all changes (bugfixes) to make the release stable (which probably includes the creation of subsequent versions 1.5.1, 1.5.2... as described above.

release-finish first checks if the HEAD of the "release/1.5" branch is tagged (to make sure there are no commits after the most recent release plugin execution), then merges it to “master” as well as back to “develop”, and finally deletes the release branch.

The Hotfix Workflow

Now our release (let's say it has version 1.5.3) is in production, and (whilst development on version 1.6.0-SNAPSHOT proceeds) we must apply an hotfix.

hotfix-start would create the branch “hotfix/1.5.3” (based on “master”) and bump its version from 1.5.3 to 1.5.4-SNAPSHOT. All hotfix changes are now applied to this branch.
Every time we think we are ready for release, we again use the a Release plugin to build a new version.

hotfix-finish is similar to release-finish: it cehcks if the HEAD of the hotfix branch is tagged, then  merges it to “master” and “develop”. Furthermore, if the next release has already been started, the hotfix branch must also be merged to “release/1.6.0”. At the end, the branch is deleted.

Showstoppers

  • On both release-finish and hotfix-finish, the merge back to “develop” will ultimately fail, because both branches have modified the version number in the pom.xml file.
  • Besides this conflict, there is always the possibility of other merge conflicts, which prevents the release-finish and hotfix-finish steps from being executed non-interactive (e.g. on a CI server).
  • The merge from a hotfix branch to any pending release branch is not included in Gitflow (or maybe I have missed something?)
 

Workaround: Scripting

There is some discussion, but no real solution to these problems: Some suggest to always use SNAPSHOT versions to avoid the release merging conflict, or even reverting the versionnumber before merging, but most seem to avoid the Gitflow commands in these cases and use the corresponding Git commands directly.
So I wrote my own wrapper scripts for release-start, release-finish, hotfix-start, and hotfix-finish that bypass the showstoppers mentioned above:
  • Before merging a release or hotfix back to “develop”, the version is set to the version of the target branch (e.g. on branch "release/1.5", after merging to "master", I use "mvn version:set -DnewVersion=1.6.0-SNAPSHOT", commit this, and then do the merge.
  • Generally, if a merge back to “develop” fails, the script will carry on, but it won’t delete the branch and will raise an alert – now the developer nows that there is a dangling release (or hotfix) branch that needs a manual merge.
There is no advantage in using Gitflow commands in these scripts - just the opposite: the scripts become more readable when avoiding Gitflow alltogether and sticking to the plan Git commands...