Skip to content

Automatic Versioning with GitVersion

GitVersion takes the pain out of manual versioning and arguing with your colleagues by automatically generating version numbers based on your Git history and Semantic Versioning (SemVer) principles. Instead of remembering to bump version numbers manually (and inevitably forgetting), GitVersion analyzes your commits and branches to determine the next logical version number.

This eliminates the classic "oops, forgot to update the version" moments and ensures every build gets a consistent, meaningful version number. When integrated with your CI/CD pipeline, it means every commit-even on feature branches-gets its own unique, traceable version.

INFO

Every commit gets a version number! GitVersion generates unique pre-release versions for every commit on feature branches (e.g., 1.1.0-JIRA-1234-user-login-form.1, then .2, and so on). This means you can create testable builds from any point in your development process.

GitFlow with SemVer

Since any commit in your Git repository could potentially be deployed, GitVersion can calculate a proper SemVer number for any branch and commit. GitVersion provides a configurable way to automate this process while keeping your version numbers SemVer-compliant.

Installation

Install GitVersion locally using Chocolatey:

bash
choco install gitversion

Or integrate it into your CI/CD pipeline using these templates:

Configuration

You'll need to add a GitVersion.yml file at the root of your repository to configure GitVersion for your specific workflow. The configuration below is tailored for the trunk-based workflow presented in this documentation, but you may need to adjust it based on your project's constraints.

The complete GitVersion.yml configuration is shown below:

yaml
mode: ContinuousDelivery
assembly-file-versioning-scheme: MajorMinorPatchTag
assembly-versioning-scheme: MajorMinorPatchTag
major-version-bump-message: "^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\\([\\w\\s-]*\\))?(!:|:.*\\n\\n((.+\\n)+\\n)?BREAKING CHANGE:\\s.+)"
minor-version-bump-message: "^(feat)(\\([\\w\\s-]*\\))?:"
patch-version-bump-message: "^(build|chore|ci|docs|fix|perf|refactor|revert|style|test)(\\([\\w\\s-]*\\))?:"
commit-message-incrementing: Enabled
branches:
  main:
    label: beta
  feature:
    regex: ^((task)|(feat(ure)?))[/-](?<BranchName>.{1,25})
    label: '{BranchName}'
    increment: Minor
    source-branches: ["main", "feature"]
    mode: ContinuousDelivery
  support:
    regex: ^support[/-](?<BranchName>.+)
    label: RC
    increment: Patch
    source-branches: ["main"]
    mode: ContinuousDelivery
  fix:
    regex: ^(bug|hot)?fix[/-](?<BranchName>.{1,25})
    label: '{BranchName}'
    increment: Patch
    source-branches: ["main", "support"]
    mode: ContinuousDelivery

Support branches and minor/patch digits

The configuration above works pretty well and relies on commit messages (following conventional commits formatting) to bump the right digit. There's a small caveat when using support branches:

In this example, since the commit on the support branch is using the feat: type, GitVersion will bump the minor digit, ending with a potential 1.1.0 future release... Which we could rather see on main.

There are two ways to avoid it:

  • Prevent feat: commits and feature branches on support workflow, and use any other type - After all, you're not supposed to add features on support branches, right?
  • Set commit-message-incrementing: Disabled and rely on branch types only. But you'll lose the conventional commit support.