Skip to content

[ISSUE]: Hotfix branch merge resulting in pre-release number reset #4632

@CSymes

Description

@CSymes

Prerequisites

  • I have written a descriptive issue title
  • I have searched issues to ensure it has not already been reported

GitVersion package

GitVersion.MsBuild

GitVersion version

v6

Operating system

Windows

What are you seeing?

Under some scenarios, merging a hotfix branch back to develop prior to merging into main causes the prerelease number of the commits on develop to regress.

Image

#4501 discussed a very similar issue, however the resolution there was limited to version numbers being sourced from commit messages, whereas we are reliant on conventional commits to determine our numbers in our case.

Some additional notes:

  • We are using a mildly modified GitFlow configuration, although the issue occurs even using the default GitFlow config
  • In our live system where we have experienced this, the skip backwards was much greater than one (22->5 or thereabouts), likely due to additional feature branches which I have not included in this reproduction, for simplicity.
  • Merging in the other order (into main, then into develop) avoids the issue.
    • As does merging into develop from main instead of the hotfix
    • Unfortunately we can't rely on developers remembering to merge with the correct order or source brounches
  • If the hotfix release is not tagged, develop is not affected.

Is this behaving as intended? The behaviouir's dependence on order of merges seems to indicate an issue to me, but if there isn't, is there a way to configure our way around the problem?

What is expected?

develop's commits' prerelease numbers should monotonically increase.

Steps to Reproduce

Make a merge from a hotfix branch to develop prior to merging to main and tagging a release using GitFlow.

RepositoryFixture Test

    [Test]
    public static void RunFixtureSimpleMinimal()
    {
        const string developBranch = "develop";
        const string hotfixBranch = "hotfix/hf";

        var configuration = GitFlowConfigurationBuilder.New
            .WithMajorVersionBumpMessage("BREAKING CHANGE")
            .WithMinorVersionBumpMessage("^(feat)")
            .WithPatchVersionBumpMessage("^(build|chore|ci|docs|fix|perf|refactor|revert|style|test)")
            .WithCommitMessageIncrementing(CommitMessageIncrementMode.Enabled)
            .WithBranch("develop", b => b
                .WithLabel("develop")
                .WithRegularExpression("develop")
            )
            .WithBranch("main", b => b
                .WithLabel("")
                .WithRegularExpression("main")
            )
            .WithBranch("hotfix", b => b
                .WithLabel("hotfix")
                .WithRegularExpression("^hotfix?[/-]")
                .WithDeploymentMode(DeploymentMode.ContinuousDelivery)
            )
            .Build();

        using var fixture = new BaseGitFlowRepositoryFixture("1.0.0");
        fixture.NoteVersion(configuration);

        // Feature
        fixture.MakeACommit("feat: f1");
        fixture.NoteVersion(configuration);

        // Release 1.1.0
        fixture.Checkout(MainBranch);
        fixture.MergeNoFF(developBranch);
        fixture.NoteVersion(configuration);
        fixture.ApplyTag("1.1.0");
        fixture.NoteVersion(configuration);

        // Hotfix
        fixture.Checkout(MainBranch);
        fixture.BranchTo(hotfixBranch);
        fixture.MakeACommit("fix: applied hotfix");
        fixture.NoteVersion(configuration);

        // Merge hotfix->develop
        fixture.Checkout(developBranch);
        fixture.MakeACommit("feat: f2");
        fixture.NoteVersion(configuration);
        fixture.MergeNoFF(hotfixBranch);
        fixture.NoteVersion(configuration);
        fixture.MakeACommit("chore: foobar");
        fixture.NoteVersion(configuration);

        // Merge hotfix->main
        fixture.Checkout(MainBranch);
        fixture.MergeNoFF(hotfixBranch);
        fixture.Remove(hotfixBranch);
        fixture.NoteVersion(configuration);
        // tag release
        fixture.ApplyTag("1.1.1");
        fixture.NoteVersion(configuration);

        // Feature 5
        fixture.Checkout(developBranch);
        fixture.NoteVersion(configuration);
        fixture.MakeACommit("feat: f3");
        fixture.NoteVersion(configuration);
    }

Note this is using a variant of the AssertFullSemver method to provide debug graphs without asserting, but these can easily be swapped out for assertions or removed.

    public static GitVersionVariables NoteVersion(this RepositoryFixtureBase fixture, IGitVersionConfiguration? configuration)
    {
        var variables = GetVersion(fixture, configuration);
        fixture.SequenceDiagram.NoteOver(variables.FullSemVer, fixture.Repository.Head.FriendlyName, color: "#D3D3D3");
        return variables;
    }

Output log or link to your CI build (if appropriate).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions