Overview
The SwatFlow git workflow is based on OneFlow, an alternative to GitFlow, which allows more flexible development and especially deployment (releases + hotfixes). The main advantage is that everything is independent, you can be in the middle of a release or a hotfix and other developers are still able to do active development without being blocked. This is achieved by having a single development branch (ex. develop) from where all other branches are created (feature, release, hotfix branches).
It can be seen that the standard ‘master’ git branch is not present in the attached image as it doesn’t have a functional role in this git workflow. Instead, it can optionally be added as a symbolic branch which points to the latest stable release.
Feature branches
Similar to GitFlow, feature branches are created from ‘develop’. The idea is to contain all the changes required for a certain issue (which could be a feature, enhancement, bugfix...) in a single branch separate from everything else. This allows multiple developers to simultaneously work on different functionalities independent of each other.
Once a feature has been finished and was approved by QA, it can be merged into develop via a Pull-Request.
In this illustration, we can see 2 developers working simultaneously and independently of each other on different features (F1, F2, F3, …).
Recommendations:
Merge feature branches into ‘develop’ as a single commit
During the implementation of a feature, a developer might have committed a large number of commits. If not squashed, all the individual commits will be merged into ‘develop’ separately, creating a very confusing commit history
By having a single commit for each feature on ‘develop’, it becomes easier to investigate the git history (ex. for pinpointing the origin of a bug)Rebase feature branches onto ‘develop’ before attempting to merge
As seen in the illustration above, developers work simultaneously and independent of each other on the same code base. This means that, while working on a feature branch, the state of the source branch ‘develop’ could have very well changed. Because of this, one or more developers could have made changes to the same files, which have already been merged into develop. This will cause merge conflicts when attempting the merge. To avoid this proactively, a developer should rebase onto develop, in case of a conflict, resolve it, make sure that the feature still works and, just then, attempt to merge into develop. (ex. feature ‘F1’ is the first branch created from ‘develop’; before it was merged, features F2 and F3 were created and already merged into ‘develop’). Rebasing a feature onto develop changes the feature commit-history in a way, as if the feature would have been started on the current state of develop. Hence, doing this frequently (e.g. daily), ensures that there will either be no conflicts, or at least the conflicts are minimal an easy to resolve (in contrast to solving all conflicts e.g. at the end of a 2-week sprint).
Release branches
One of the main advantages of SwatFlow is that releases are handled in such a way that it doesn’t affect development. This is done by handling the release branch the same way you do a feature branch. Once it is decided that the current ‘develop’ branch is ready for release, a new release branch is created from develop. From that point onward, developers are free to work on their feature branches without any worry of interfering with the release itself. During the release process, any improvements or fixes can be added on the release branch and once it has passed QA, the release gets tagged, merged into ‘develop’ and the branch can be deleted. In this workflow, we can see that a release (after it is finished) doesn’t exist as a branch, but, instead, as a tag.
Hotfix branches
Hotfix branches allow developers to provide fixes to existing releases. Similar to feature and release branches, they also don’t interfere with development.
As it is defined, a hotfix provides urgently required fixes and improvements to an existing release. It can be applied to any release, from the most recent to the oldest one.
A hotfix branch is created from an existing release or hotfix tag. During the hotfix process, additional fixes and improvements can still be added and once it has passed QA, it can be tagged. In the case of hotfixes to the most recent release, the hotfix is also merged into ‘develop’.
In the illustration above, version 1.1.0 and 1.2.0 were released. Afterwards, a hotfix was required to release 1.2.0, so hotfix 1.2.1 was done and merged into develop. Then, a hotfix was requested for 1.1.0, which was done as 1.1.1 and another one as 1.1.2.
Develop and Master
As opposed to GitFlow, SwatFlow only uses one main development branch, ‘develop’. This becomes the root for almost all operations. In this flow, ‘master’ is not required functionally, but can optionally be used as a symbolic branch which points to the latest stable release. The only advantage this provides is, if somebody clones the git repository, he/she is on the latest "official" release, as master is the standard branch git will use.
Extended workflow with Long Term Support ‘LTS’ branches
There are cases when projects need to provide support for older versions and do active development on it. Usually, this would be handled as a hotfix, but a hotfix is a short-lived branch. It is created, tested, improved or fixed by case and merged into develop. The LTS branches are meant as long-lived branches, similar to ‘develop’. LTS branches support the following child branch types: feature, release and hotfix. The LTS branches have the same functionality as the main development ‘develop’ branch. The only difference is that LTS branches provide fixes and improvements to an older release, which for certain reasons might need to be developed separately and ‘develop’ is used to develop the latest release.
Examples and use-cases
Starting and finishing a feature
Start feature
git checkout <development-branch> git checkout -b feature/<feature-id> |
Notes: development-branch is either ‘develop’ or an LTS branch feature-id is the id denoting the feature |
Finish feature
Finish feature with merge | Finish feature with pull request |
git checkout feature/<feature-id> git rebase origin/<development-branch> git checkout <development-branch> git merge --squash feature/<feature-id> | git checkout feature/<feature-id> git rebase origin/<development-branch> git checkout <development-branch> git request-pull feature/<feature-id> origin |
Notes: development-branch is either ‘develop’ or an LTS branch feature-id is the id denoting the feature |
Starting and finishing a release
Start release
git checkout <development-branch> git checkout -b release/<version> |
Notes: development-branch is either ‘develop’ or an LTS branch version is the current version being released |
Finish release
git checkout release/<version> git tag <version> git checkout <development-branch> git merge release/<version> |
Notes: development-branch is either ‘develop’ or an LTS branch version is the current version being released |
Starting and finishing a hotfix
Start hotfix
git checkout <base-version> |
Notes: base-version is the version which will be hotfixed hotfix-version is the version of the hotfix |
Finish hotfix
git checkout hotfix/<hotfix-version> git tag <hotfix-version> |
Notes: hotfix-version is the version of the hotfix |
Versioning
Maintaining the version of a single-project product
As seen above, whenever we finish a release or a hotfix, we tag the commit with a version (ex. 1.1.0, 1.3.2, ...).
Each tag represents a production-ready deployable version of the project.
This works fine when your product is maintained in a single git projects, but becomes more complex when it's spread among multiple ones.
Maintaining the version of a multi-project product
Regardless of having a single-project or multi-project product, each project should have an internal version.
In a single-project product, that internal project version can also be used as the product version, but this is not possible when multiple project are involved.
In this case, we need to have a separate product version. Similar to the project version, the product version can also be maintained through tags.
Below is an example for a product maintained in 3 different git projects:
The versions on the lines represent the corresponding project's internal release version, which is accesible through the corresponding tag. All the projects are tagged with the initial 1.0.0 version, which will be released as version 1.0.release of the product. A hotfix needs to be provided to 1.0.release, but the only required changes are in project1.
An additional hotfix is now required, so the next product version will be 1.0.hotfix.2.
It is decided that version 1.1.0 will be released. |