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 commitsdevelop
is 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??