In our previous article, we investigate how to version our Nuget packages using some classes as AssemblyInfo.cs. Following this versioning type, we never had problems, even if, as we adopted git, we are wondering if there would be a better way to organize our job and thus the versioning process. For this reason, we examined different branching strategies used with git, and the approach that better meet our requirements is the one of GitFlow.
GitFlow essentially permits to give a semantical meaning to git’s branches, in relation to what you are working on. For example, if we are developing something on a branch feature, we know we are working on a new feature to insert in next release of our software. Below a GitFlow overview:
In GitFlow we have 2 branches, defined as main or historical , which will exist for the whole life of our repository. These branches are:
- master: it contains the totality of the releases we created for our software. Commits are generated from release or hotfix branches, before they are merged to that (merge);
- develop: it contains integrations essential for next release, and new release branches start from its. Commits of this repository have their origin in feature branches.
Together with these branches, we can find other branches that have a short life:
- feature: they include the totality of new functionality to integrate in next release. They *start* and are *merged back* with branch develop, when functionality *development ends*;
- release: they include the totality of features, that would belong to next release. Branches *start* from *Develop* and they will be *merged* both to master and to develop (after the fixes on the branch itself). Release Branches are also tagged just a moment before the merge with the master and the develop;
- hotfix: they include the totality of fixes implemented on production code. Branches *start* from master and they will be *merged* both to master and to develop.
An important characteristic of GitFlow emerges from this information: there are tight associations between different branches. We can consider this characteristic a strong point of this approach, even if in some cases it let it seems too arduous.
SourceTree or Fork already include it among their functionalities.
Let’s look to a short example of the use of GitFlow through the CLI, starting from a feature’s implementation and finishing with its release.
The first step is to initialize the repository with the command
git flow init. This command configures the repository and the branches’ names, through the request of some information.
We are ready to create our first feature: with the command
git flow feature start <nomeFeature> we can merge new code into the develop branch, where we will develop new functionalities in our project. As this step is completed, we can unify new modifications with the branch develop with the command
git flow feature finish <featureName> This operation updates the develop, but it also removes our feature’s branch, because it is no more useful to us.
As soon as we are ready to release a new software version, we can use the command:
git flow release start <numero_release>. This command creates a new release branch, that will be used mainly to testing and will contain bugfix, in case of any problem.
The last step is to release a product and merge all the changes to branch master.
git flow release finish <releaseNumber>, is the command to be used: it executes many operations:
- merge into master;
- tag of release with its name;
- back-merge into develop;
- Removal of releases branch
With these simple steps and thanks to an excellent integration with the CLI, we can create intuitively a well-defined development process.
Now a question may occur: in this process, how can we establish the version number associated to the name of the branch release? And can we use the same number to define “intermediate” branches that we will use to integrate new releases? The answer to both questions is SemVer.
GitFlow is often related to semantic versioning concept. It offers thus a set of rules, that make easy the versioning of branches, which already have their own meaning inside the job process.
The adoption of SemVer and GitVersion
SemVer helps to define the software versioning, thanks to a set of regulations based on 3 numbers: major, minor and patch.
As the image illustrates, every number is incremented depending on which modification we are making inside our software. The more interesting aspect is that, in addition to these numbers, we can provide also for the existance of intermediate releases, to diversify those releases, that come from branches different from the master:
These numbers, and particularly pre-release and metadata sections, can be generated based to the branch we are considering, and support testing and automation processes.
Following the rules concerning branches, which we saw in GitFlow, and understood how SemVer works to have to version numbers, we can standardize the distribution process of a new release number. A tool named GitVersion comes and help us. It is a command-line executable, that permits us to generate next version number, based on our repository history and on the branch we are using.
The installation is easy: if we are in Windows, in fact, we can install it with Chocolatey.
gitversion init starts an initialization wizard, that guides us to choose the versioning type we need, through a set of questions. Once we chose the GitFlow approach, we save in the wizard the configuration
gitversion.yml that will be present in the repository and will help versions management. To generate the next version number, you only need to execute
gitversion in the console, and a JSON payload will appear. It contains a set of information and the next version number in different formats:
In order to make the versioning of our Nuget packages, the property to considerate for next value to assign in the AssemblyInfo.cs is NugetVersionV2.
A problem arises: in our previous article, we have used
AssemblyFileVersion for example, these attributes are not valid anymore! The reason Is that these two attributes don’t accept characters, but only numbers. For this reason, we need to use an attribute compatible with SemVer called
AssemblyInformationalVersion. Then, after we created the Nuget package with number generated from GitVersion, we can find also the pre-release part or metadata compatible with SemVer..
After we established a well consolidated process and adopted GitFlow, SemVer and GitVersion, the next step is to automate the whole procedure through the use of a pipeline of Continuous Deployment. In next article, we will see how we can do that with Azure Devops.
GitFlow explained: https://nvie.com/posts/a-successful-git-branching-model/
GitFlow step-by-step: https://danielkummer.github.io/git-flow-cheatsheet/
GitVersion use and configuration: https://gitversion.readthedocs.io/en/latest/configuration/#configuration
Different workflows for git: https://www.atlassian.com/git/tutorials/comparing-workflows