Git Flow allows more structured releases, and GitVersion will derive sensible SemVer compatible versions from this structure.
Assumptions:
- Using GitFlow branching model which always has a main and a develop branch
- Following Semantic Versioning
- Planned releases (bumps in major or minor) are done on release branches prefixed with release-. Eg: release-4.1 (or release-4.1.0)
- Hotfixes are prefixed with hotfix- Eg. hotfix-4.0.4
- The original GitFlow model specifies branches with a "-" separator while the git flow extensions default to a "/" separator. Either work with GitVersion.
- Tags are used on the main branch and reflects the SemVer of each stable release eg 3.3.8 , 4.0.0, etc
- Tags can also be used to override versions while we transition repositories over to GitVersion
- Using a build server with multi-branch building enabled eg TeamCity 8
How Branches are handled
The descriptions of how commits and branches are versioned can be considered a type of pseudopod. With that in mind there are a few common "variables" that we will refer to:
targetBranch=> the branch we are targeting-
targetCommit=> the commit we are targeting ontargetbranch
Main branch
Commits on main will always be a merge commit (Either from a
hotfix or a release branch) or a tag. As
such we can simply take the commit message or tag message.
If we try to build from a commit that is no merge and no tag then
assume 0.1.0
mergeVersion => the SemVer extracted from
targetCommit.Message
- major:
mergeVersion.Major - minor:
mergeVersion.Minor - patch:
mergeVersion.Patch - pre-release: 0 (perhaps count ahead commits later)
- stability: final
Optional Tags (only when transitioning existing repository):
- TagOnHeadCommit.Name= => overrides the version to be
Long version:
{major}.{minor}.{patch} Sha:'{sha}'
1.2.3 Sha:'a682956dccae752aa24597a0f5cd939f93614509'
Develop branch
targetCommitDate => the date of the
targetCommit mainVersionCommit => the
first version (merge commit or SemVer tag) on main that
is older than the targetCommitDate
mainMergeVersion => the SemVer extracted from
mainVersionCommit.Message
- major:
mainMergeVersion.Major -
minor:
mainMergeVersion.Minor + 1(0 if the override above is used) - patch: 0
-
pre-release:
alpha.{n}where n = how many commitsdevelopis in front ofmainVersionCommit.Date('0' padded to 4 characters)
Long version:
{major}.{minor}.{patch}-{pre-release} Branch:'{branchName}' Sha:'{sha}'
1.2.3-alpha.645 Branch:'develop' Sha:'a682956dccae752aa24597a0f5cd939f93614509'
Hotfix branches
Named: hotfix-{versionNumber} eg
hotfix-1.2
branchVersion => the SemVer extracted from
targetBranch.Name
- major:
mergeVersion.Major - minor:
mergeVersion.Minor - patch:
mergeVersion.Patch -
pre-release:
beta{n}where n = number of commits on branch ('0' padded to 4 characters)
Long version:
{major}.{minor}.{patch}-{pre-release} Branch:'{branchName}' Sha:'{sha}'
1.2.3-beta645 Branch:'hotfix-foo' Sha:'a682956dccae752aa24597a0f5cd939f93614509'
Release branches
- May branch off from: develop
- Must merge back into: develop and main
-
Branch naming convention:
release-{n}egrelease-1.2
releaseVersion => the SemVer extracted from
targetBranch.Name releaseTag => the
first version tag placed on the branch. Note that at least one
version tag is required on the branch. The recommended initial tag
is {releaseVersion}.0-alpha1. So for a branch named
release-1.2 the recommended tag would be
1.2.0-alpha1
- major:
mergeVersion.Major - minor:
mergeVersion.Minor - patch: 0
-
pre-release:
{releaseTag.preRelease}.{n}where n = 1 + the number of commits sincereleaseTag.
So on a branch named release-1.2 with a tag
1.2.0-alpha1 and 4 commits after that tag the version
would be 1.2.0-alpha1.4
Long version:
{major}.{minor}.{patch}-{pre-release} Branch:'{branchName}' Sha:'{sha}'
1.2.3-alpha2.4 Branch:'release-1.2' Sha:'a682956dccae752aa24597a0f5cd939f93614509'
1.2.3-rc2 Branch:'release-1.2' Sha:'a682956dccae752aa24597a0f5cd939f93614509'
Feature branches
May branch off from: develop Must merge back into:
develop Branch naming convention: anything except
main, develop, release-{n},
or hotfix-{n}.
TODO: feature branches cannot start with a SemVer. to stop people from create branches named like "4.0.3"
- major:
mainMergeVersion.Major -
minor:
mainMergeVersion.Minor + 1(0 if the override above is used) - patch: 0
-
pre-release:
alpha.feature-{n}where n = First 8 characters of the commit SHA of the first commit
Long version:
{major}.{minor}.{patch}-{pre-release} Branch:'{branchName}' Sha:'{sha}'
1.2.3-alpha.feature-a682956d Branch:'feature1' Sha:'a682956dccae752aa24597a0f5cd939f93614509'
Pull-request branches
May branch off from: develop Must merge back into:
develop Branch naming convention: anything except
main, develop, release-{n},
or hotfix-{n}. Canonical branch name contains
/pull/.
- major:
mainMergeVersion.Major -
minor:
mainMergeVersion.Minor + 1(0 if the override above is used) - patch: 0
-
pre-release:
alpha.pull{n}where n = the pull request number ('0' padded to 4 characters)
Nightly Builds
develop, feature and pull-request builds are considered nightly builds and as such are not in strict adherence to SemVer.
Release Candidates
How do we do release candidates?? Perhaps tag a release branch and then count commits forward from the tag to get RC1, RC2 etc??