Versioning software artifacts (Assemblies, NuGet, or NPM packages) has been proved to be a challenging procedure. Today, Semantic Versioning is a practice that has been on the rise over the last few years, but how to apply it to your projects?. Here is were GitVersion come in place.
GitVersion is a tool that generates a Semantic Version number based on your Git history. The version number generated from GitVersion can then be used for various different purposes.
To test how GitVersion helps us get version numbers, today we are going to use GitFlow as a branching strategy. There are several ways to install GitVersion. Here we are using the .NET global tool option:
dotnet tool install --global GitVersion.Tool --version 5.*
Let's create a new Git repository:
mkdir gitversion-giflow
cd .\gitversion-giflow\
git init
Now it is time to see our first GitVersion command:
dotnet-gitversion init
We are going thru the configuration process depending on the branch strategy mentioned before:
GitVersion init will guide you through setting GitVersion up to work for you
Which would you like to change?
0) Save changes and exit
1) Exit without saving
2) Run getting started wizard
3) Set next version number
4) Branch specific configuration
5) Branch Increment mode (per commit/after tag) (Current: )
6) Assembly versioning scheme (Current: )
7) Setup build scripts
Select the option 2:
The way you will use GitVersion will change a lot based on your branching strategy. What branching strategy will you be using:
1) GitFlow (or similar)
2) GitHubFlow
3) Unsure, tell me more
Select the option 1:
By default GitVersion will only increment the version of the 'develop' branch every commit, all other branches will increment when tagged
What do you want the default increment mode to be (can be overriden per branch):
1) Follow SemVer and only increment when a release has been tagged (continuous delivery mode)
2) Increment based on branch config every commit (continuous deployment mode)
3) Each merged branch against main will increment the version (mainline mode)
4) Skip
Again option 1. As the last step, the wizard is going to show us to the first menu, select option 0 (Save changes and exit
). Run the following command to see the current GitVersion configuration:
dotnet-gitversion /showconfig
GitVersion added a file called GitVersion.yml.
mode: ContinuousDelivery
branches: {}
ignore:
sha: []
merge-message-formats: {}
Let's add the first commit with this file:
git add .
git commit -m 'initial commit'
Then run the dotnet-gitversion
command:
{
"Minor": 1,
"Patch": 0,
"PreReleaseTag": "",
"PreReleaseTagWithDash": "",
"PreReleaseLabel": "",
"PreReleaseLabelWithDash": "",
"PreReleaseNumber": null,
"WeightedPreReleaseNumber": 60000,
"BuildMetaData": 0,
"BuildMetaDataPadded": "0000",
"FullBuildMetaData": "0.Branch.master.Sha.17de78f354ad96dc7766c2d1242634cc903d8e2f",
"MajorMinorPatch": "0.1.0",
"SemVer": "0.1.0",
"LegacySemVer": "0.1.0",
"LegacySemVerPadded": "0.1.0",
"AssemblySemVer": "0.1.0.0",
"AssemblySemFileVer": "0.1.0.0",
"FullSemVer": "0.1.0+0",
"InformationalVersion": "0.1.0+0.Branch.master.Sha.17de78f354ad96dc7766c2d1242634cc903d8e2f",
"BranchName": "master",
"EscapedBranchName": "master",
"Sha": "17de78f354ad96dc7766c2d1242634cc903d8e2f",
"ShortSha": "17de78f",
"NuGetVersionV2": "0.1.0",
"NuGetVersion": "0.1.0",
"NuGetPreReleaseTagV2": "",
"NuGetPreReleaseTag": "",
"VersionSourceSha": "17de78f354ad96dc7766c2d1242634cc903d8e2f",
"CommitsSinceVersionSource": 0,
"CommitsSinceVersionSourcePadded": "0000",
"UncommittedChanges": 0,
"CommitDate": "2022-05-22"
}
There is a lot of information, but the one that we will use will be FullSemVer. Notice that GitVersion uses by default version number 0.1.0
. Create a develop
branch from master
:
git checkout -b develop
And then create a feature
branch from develop
:
git checkout -b feature/myFeatureA
Run the command dotnet-gitversion /showvariable FullSemVer
:
0.1.0-myFeatureA.1+0
Add another commit (we are going to use empty commits by practicality):
git commit -m 'featurea A: change 1' --allow-empty
Run again dotnet-gitversion /showvariable FullSemVer
to see how the last number is moving:
0.1.0-myFeatureA.1+1
Time to finalize the feature
branch:
git checkout develop
git merge --no-ff feature/myFeatureA
git branch -d feature/myFeatureA
Run dotnet-gitversion /showvariable FullSemVer
:
0.1.0-alpha.2
Create a new feature
branch and repeat all steps until finalizing it and see how the version number changes in the develop
branch:
0.1.0-alpha.4
Run the command git log --oneline --graph
to see the log history for the develop
branch:
* fe48f23 (HEAD -> develop) Merge branch 'feature/myFeatureB' into develop
|\
| * 4ad9aa8 featurea B: change 1
|/
* 20481b3 Merge branch 'feature/myFeatureA' into develop
|\
| * df2170f featurea A: change 1
|/
* 17de78f (master) initial commit
Now it is time to create a release
branch:
git checkout -b release/1.0.0 develop
Run dotnet-gitversion /showvariable FullSemVer
:
1.0.0-beta.1+0
Add a commit to simulate a bug fix under the release
branch:
git commit -m 'bug fix' --allow-empty
And check the version number:
1.0.0-beta.1+1
Assume that we want to release this branch to production:
git checkout master
git merge --no-ff release/1.0.0
git tag '1.0.0'
git checkout develop
git merge --no-ff release/1.0.0
git branch -d release/1.0.0
Now running dotnet-gitversion /showvariable FullSemVer
under master
will see 1.0.0
because the tag tells GitVersion that this is the new version number. If you check the version number in the develop
branch, GitVersion figures out 1.1.0-alpha.2
as a new value. Let's do a hotfix now:
git checkout master
git checkout -b hotfix/1.0.1
Add a commit:
git commit -m 'bug fix' --allow-empty
Run dotnet-gitversion /showvariable FullSemVer
:
1.0.1-beta.1+7
And finalize a hotfix
branch:
git checkout master
git merge --no-ff hotfix/1.0.1
git tag '1.0.1'
git checkout develop
git merge --no-ff hotfix/1.0.1
git branch -d hotfix/1.0.1
Run dotnet-gitversion /showvariable FullSemVer
under master
branch to see 1.0.1
as version number.
To see more examples using GitFlow, you can check the official documentation here.