Skip to content

feat: resolve increments from merged branches - #5140

Open
fzlzjerry wants to merge 22 commits into
GitTools:mainfrom
fzlzjerry:feat/4433-prevent-merged-branch-increment
Open

feat: resolve increments from merged branches#5140
fzlzjerry wants to merge 22 commits into
GitTools:mainfrom
fzlzjerry:feat/4433-prevent-merged-branch-increment

Conversation

@fzlzjerry

@fzlzjerry fzlzjerry commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Description

Moves merged-branch increment selection into IncrementStrategyFinder.DetermineIncrementedField, so every version strategy that already uses the finder receives the same behavior without adding a separate strategy or configuration surface.

For a branch with merge-message tracking enabled that is either an effective main branch or a compatible descendant preserving main-branch history through linear work and main-to-descendant updates, the finder separates first-parent target work from recognized two-parent merges. It calculates each source branch's effective increment from the merged history, preserves source +semver / =semver handling, and applies the target/source settings as follows:

Target of-merged-branch Source when-branch-merged Effective contribution
false false Target + source increment
false true Target increment
true false Source increment
true true Target increment

Main-to-descendant update merges carry main's recursively derived version floor rather than treating main as a completed source branch. Unrelated intervening merges still keep the descendant outside merge-history processing.

Direct target commits still contribute the target increment, unrecognized merge histories remain target-configured work, synthetic pull-request refs stay outside merge-history processing, and the highest contribution across multiple merges wins. Inherited source increments are resolved from the historical merged tip, including deleted or recreated topic refs and source branches that absorb the topic later. Per-merge and ancestry results use configuration-aware cache keys because the finder evaluates multiple base-version candidates for the same current commit.

Related Issue

Resolves #4433

Motivation and Context

Outside mainline calculation, a no-fast-forward merge currently falls back to the target branch's configured increment. This makes a patch hotfix merged into a minor-increment main branch produce a minor version, and a minor feature merged into a patch-increment main branch produce a patch version. The increment finder already owns configured and commit-message increment precedence, so handling merged histories there keeps the behavior consistent across dependent version strategies.

How Has This Been Tested?

Tested on Linux with .NET SDK 10.0.400 at b46b8201d:

  • Added 46 integration cases covering the four effective configuration combinations, GitFlow/GitHubFlow acceptance scenarios, multiple merges and reset directives, target work before and after a merge, source commit-message overrides, unrecognized and ignored-merge side histories including chronological directive ordering across recognized boundaries, tagged and future-dated source tips including selected stable tags across source labels, inherited prevention and effective main-branch settings including source-branch inheritance, ignored branches including current and compatible-descendant main-history exceptions, synthetic pull-request refs, intervening target tags, pruned target segments, and off-first-parent base boundaries, nested and sibling inheritance for historical and retained tips, descendant-branch version floors including main update merges and an unrelated-merge guard, historical/local/remote source resolution, and retained/deleted orphan fallback parity including unresolved-Inherit skipping.
  • Added a focused IncrementStrategyFinder unit case proving that commit-message cache entries are isolated by regex configuration.
  • Updated the existing GitFlow/GitHubFlow alignment and merge scenarios to assert the corrected results.
  • dotnet build ./src/GitVersion.slnx --no-restore --verbosity:minimal -m:1 — succeeded with 0 warnings and 0 errors.
  • dotnet test --solution ./src/GitVersion.slnx --no-build --no-restore --max-parallel-test-modules 1 --no-progress --output Normal with TMPDIR and RUNNER_TEMP set to a clean non-repository directory — 37,290 succeeded, 0 failed.
  • dotnet format --verify-no-changes ./src/GitVersion.slnx --no-restore — succeeded.
  • git diff --check — succeeded.

Screenshots (if appropriate):

N/A

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

Copilot AI lite review requested due to automatic review settings August 17, 2026 11:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 18f6910930

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copilot AI review requested due to automatic review settings August 17, 2026 12:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4e34bfa475

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@fzlzjerry
fzlzjerry force-pushed the feat/4433-prevent-merged-branch-increment branch from 4e34bfa to f6b83bb Compare August 17, 2026 12:57
Copilot AI review requested due to automatic review settings August 17, 2026 12:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f6b83bb5c1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copilot AI review requested due to automatic review settings August 17, 2026 13:44
@fzlzjerry
fzlzjerry force-pushed the feat/4433-prevent-merged-branch-increment branch from f6b83bb to 52598be Compare August 17, 2026 13:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 52598be177

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copilot AI review requested due to automatic review settings August 17, 2026 14:02
@fzlzjerry
fzlzjerry force-pushed the feat/4433-prevent-merged-branch-increment branch from 52598be to 1c8f29f Compare August 17, 2026 14:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@arturcic
arturcic requested a review from HHobeck August 17, 2026 16:41
Copilot AI review requested due to automatic review settings August 18, 2026 12:24
@fzlzjerry
fzlzjerry force-pushed the feat/4433-prevent-merged-branch-increment branch from 1c8f29f to 3f8211c Compare August 18, 2026 12:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3f8211c580

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copilot AI review requested due to automatic review settings August 18, 2026 12:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d8823790f7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Copilot AI review requested due to automatic review settings August 18, 2026 13:28

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5cee297f10

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docs/input/docs/reference/version-sources.md Outdated
Copilot AI review requested due to automatic review settings August 18, 2026 13:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Copilot AI review requested due to automatic review settings August 21, 2026 21:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bdafb9537f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs Outdated
Copilot AI review requested due to automatic review settings August 21, 2026 21:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9be4f76314

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs Outdated
Copilot AI review requested due to automatic review settings August 21, 2026 21:20

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2c4146240d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs Outdated
Copilot AI review requested due to automatic review settings August 21, 2026 21:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6d79ccee85

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs
Comment thread src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs
Comment thread src/GitVersion.Core/VersionCalculation/IncrementStrategyFinder.cs Outdated
Copilot AI review requested due to automatic review settings August 21, 2026 22:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@HHobeck

HHobeck commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

You are very fast implementing things :) Thank you. It feels a little bit like prototyping. Anyway, I think the table is wrong and I was thinking to remove the complexity with the null value. I'm not sure if we really need the use case where the result will be Increment.None. From the coneptual point of view the following table would make more sense:

Target of-merged-branch Source when-branch-merged Effective contribution
false false Target+Source increment
false true Target increment
true false Source increment
true true Target increment

What do you think?

@fzlzjerry

Copy link
Copy Markdown
Contributor Author

I agree with the four-case table.

The nullable value still has a useful role at the configuration boundary: an omitted branch value means "inherit". But it should be resolved before increment selection. EffectiveConfiguration.PreventIncrementWhenBranchMerged is already a bool, so carrying the raw bool? into SelectIncrement conflates configuration inheritance with merge behavior.

I would model the selector only with the two effective booleans:

  • false / false: consolidate target and source;
  • false / true: target;
  • true / false: source;
  • true / true: target as the non-None fallback.

That makes null a configuration-resolution concern rather than a third runtime state. The old nullable rows would collapse according to the inherited effective value, while the meaningful behavior change is the explicit false / false case now including the source contribution. Increment.None can still be a legitimate calculated increment elsewhere, but it does not need a separate case in this prevention matrix.

This is cleaner than the current six-case implementation. I would rework the selector types and matrix tests around the resolved source value rather than add another special case.

@HHobeck

HHobeck commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Hey @fzlzjerry, How is the rework going? Hope everything goes well. :)

Copilot AI review requested due to automatic review settings August 25, 2026 11:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@fzlzjerry

Copy link
Copy Markdown
Contributor Author

The rework is done in b46b8201d.

SelectIncrement now receives the two resolved boolean settings and implements the four cases directly. The nullable value remains only at the configuration boundary and is resolved through EffectiveConfiguration before selection. In particular, false / false now consolidates the target and source increments, and the matrix test has been reduced to the four effective cases.

I also updated the PR description to match the new table. Validation on this commit:

  • full solution build: 0 warnings, 0 errors
  • full solution tests: 37,290 passed, 0 failed
  • format verification and git diff --check: passed

@sonarqubecloud

Copy link
Copy Markdown

@HHobeck

HHobeck commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

The rework is done in b46b8201d.

SelectIncrement now receives the two resolved boolean settings and implements the four cases directly. The nullable value remains only at the configuration boundary and is resolved through EffectiveConfiguration before selection. In particular, false / false now consolidates the target and source increments, and the matrix test has been reduced to the four effective cases.

I also updated the PR description to match the new table. Validation on this commit:

  • full solution build: 0 warnings, 0 errors
  • full solution tests: 37,290 passed, 0 failed
  • format verification and git diff --check: passed

Great thank you. I'm goign to execute some test scenarios and do the code review. I will inform you about the outcome soon.

@arturcic

Copy link
Copy Markdown
Member

@fzlzjerry make sure to rewrite the git history in an atomic and logically grouped way. Make it more fluent to read

@HHobeck

HHobeck commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

@fzlzjerry make sure to rewrite the git history in an atomic and logically grouped way. Make it more fluent to read

I think for now it is important to ge this working. At the end we can do one single commit with a nice commit message.

@fzlzjerry: I'm cursios about IncrementStrategyFinder::HasCompatibleMainBranchHistory. Can you check the following scenarios please? (This is a basis for discussion)

    [TestCase(false, IncrementStrategy.Patch, false, "1.1.0-2")]
    [TestCase(false, IncrementStrategy.Patch, true, "1.1.0-2")]
    [TestCase(true, IncrementStrategy.Patch, false, "1.0.1-2")]
    [TestCase(true, IncrementStrategy.Patch, true, "1.1.0-2")]
    [TestCase(false, IncrementStrategy.Major, false, "2.0.0-2")]
    [TestCase(false, IncrementStrategy.Major, true, "1.1.0-2")]
    [TestCase(true, IncrementStrategy.Major, false, "2.0.0-2")]
    [TestCase(true, IncrementStrategy.Major, true, "1.1.0-2")]
    public void HonorsPreventIncrement1(
        bool preventIncrementOfMergedBranch,
        IncrementStrategy incrementStrategy,
        bool preventIncrementWhenBranchMerged, string expected)
    {
        var configuration = GitFlowConfigurationBuilder.New
            .WithBranch("main", builder => builder
                .WithDeploymentMode(DeploymentMode.ContinuousDelivery)
                .WithIncrement(IncrementStrategy.Minor)
                .WithPreventIncrementOfMergedBranch(preventIncrementOfMergedBranch)
            ).WithBranch("hotfix", builder => builder
                .WithIncrement(incrementStrategy)
                .WithPreventIncrementWhenBranchMerged(preventIncrementWhenBranchMerged)
            ).Build();

        using var fixture = new EmptyRepositoryFixture("main");
        fixture.MakeATaggedCommit("1.0.0");
        fixture.BranchTo("hotfix/foo");
        fixture.MakeACommit();
        fixture.MergeTo("main");

        fixture.AssertFullSemver(expected, configuration);
    }

    [TestCase(false, IncrementStrategy.Patch, false, "1.1.0-2")]
    [TestCase(false, IncrementStrategy.Patch, true, "1.1.0-2")]
    [TestCase(true, IncrementStrategy.Patch, false, "1.0.1-2")]
    [TestCase(true, IncrementStrategy.Patch, true, "1.1.0-2")]
    [TestCase(false, IncrementStrategy.Major, false, "2.0.0-2")]
    [TestCase(false, IncrementStrategy.Major, true, "1.1.0-2")]
    [TestCase(true, IncrementStrategy.Major, false, "2.0.0-2")]
    [TestCase(true, IncrementStrategy.Major, true, "1.1.0-2")]
    public void HonorsPreventIncrement2(
        bool preventIncrementOfMergedBranch,
        IncrementStrategy incrementStrategy,
        bool preventIncrementWhenBranchMerged, string expected)
    {
        var configuration = TrunkBasedConfigurationBuilder.New
            .WithBranch("main", builder => builder
                .WithDeploymentMode(DeploymentMode.ContinuousDelivery)
                .WithIncrement(IncrementStrategy.Minor)
                .WithPreventIncrementOfMergedBranch(preventIncrementOfMergedBranch)
            ).WithBranch("hotfix", builder => builder
                .WithIncrement(incrementStrategy)
                .WithPreventIncrementWhenBranchMerged(preventIncrementWhenBranchMerged)
            ).Build();

        using var fixture = new EmptyRepositoryFixture("main");
        fixture.MakeATaggedCommit("1.0.0");
        fixture.BranchTo("hotfix/foo");
        fixture.MakeACommit();
        fixture.MergeTo("main");

        fixture.AssertFullSemver(expected, configuration);
    }

    [TestCase(false, IncrementStrategy.Patch, false, "1.1.0-foo.2")]
    [TestCase(false, IncrementStrategy.Patch, true, "1.1.0-foo.2")]
    [TestCase(true, IncrementStrategy.Patch, false, "1.0.1-foo.2")]
    [TestCase(true, IncrementStrategy.Patch, true, "1.1.0-foo.2")]
    [TestCase(false, IncrementStrategy.Major, false, "2.0.0-foo.2")]
    [TestCase(false, IncrementStrategy.Major, true, "1.1.0-foo.2")]
    [TestCase(true, IncrementStrategy.Major, false, "2.0.0-foo.2")]
    [TestCase(true, IncrementStrategy.Major, true, "1.1.0-foo.2")]
    public void HonorsPreventIncrement3(
        bool preventIncrementOfMergedBranch,
        IncrementStrategy incrementStrategy,
        bool preventIncrementWhenBranchMerged, string expected)
    {
        var configuration = GitFlowConfigurationBuilder.New
            .WithBranch("feature", builder => builder
                .WithDeploymentMode(DeploymentMode.ContinuousDelivery)
                .WithIncrement(IncrementStrategy.Minor)
                .WithPreventIncrementOfMergedBranch(preventIncrementOfMergedBranch)
            ).WithBranch("hotfix", builder => builder
                .WithIncrement(incrementStrategy)
                .WithPreventIncrementWhenBranchMerged(preventIncrementWhenBranchMerged)
            ).Build();

        using var fixture = new EmptyRepositoryFixture("main");
        fixture.MakeATaggedCommit("1.0.0");
        fixture.BranchTo("feature/foo");
        fixture.BranchTo("hotfix/next");
        fixture.MakeACommit();
        fixture.MergeTo("feature/foo");

        fixture.AssertFullSemver(expected, configuration);
    }

    [TestCase(false, IncrementStrategy.Patch, false, "1.1.0-foo.2")]
    [TestCase(false, IncrementStrategy.Patch, true, "1.1.0-foo.2")]
    [TestCase(true, IncrementStrategy.Patch, false, "1.0.1-foo.2")]
    [TestCase(true, IncrementStrategy.Patch, true, "1.1.0-foo.2")]
    [TestCase(false, IncrementStrategy.Major, false, "2.0.0-foo.2")]
    [TestCase(false, IncrementStrategy.Major, true, "1.1.0-foo.2")]
    [TestCase(true, IncrementStrategy.Major, false, "2.0.0-foo.2")]
    [TestCase(true, IncrementStrategy.Major, true, "1.1.0-foo.2")]
    public void HonorsPreventIncrement4(
        bool preventIncrementOfMergedBranch,
        IncrementStrategy incrementStrategy,
        bool preventIncrementWhenBranchMerged, string expected)
    {
        var configuration = TrunkBasedConfigurationBuilder.New
            .WithBranch("feature", builder => builder
                .WithDeploymentMode(DeploymentMode.ContinuousDelivery)
                .WithIncrement(IncrementStrategy.Minor)
                .WithPreventIncrementOfMergedBranch(preventIncrementOfMergedBranch)
            ).WithBranch("hotfix", builder => builder
                .WithIncrement(incrementStrategy)
                .WithPreventIncrementWhenBranchMerged(preventIncrementWhenBranchMerged)
            ).Build();

        using var fixture = new EmptyRepositoryFixture("main");
        fixture.MakeATaggedCommit("1.0.0");
        fixture.BranchTo("feature/foo");
        fixture.BranchTo("hotfix/next");
        fixture.MakeACommit();
        fixture.MergeTo("feature/foo");

        fixture.AssertFullSemver(expected, configuration);
    }

    [TestCase(false, IncrementStrategy.Patch, false, "0.3.0-foo.2")]
    [TestCase(false, IncrementStrategy.Patch, true, "0.3.0-foo.2")]
    [TestCase(true, IncrementStrategy.Patch, false, "0.2.1-foo.2")]
    [TestCase(true, IncrementStrategy.Patch, true, "0.3.0-foo.2")]
    [TestCase(false, IncrementStrategy.Major, false, "1.0.0-foo.2")]
    [TestCase(false, IncrementStrategy.Major, true, "0.3.0-foo.2")]
    [TestCase(true, IncrementStrategy.Major, false, "1.0.0-foo.2")]
    [TestCase(true, IncrementStrategy.Major, true, "0.3.0-foo.2")]
    public void HonorsPreventIncrement5(
        bool preventIncrementOfMergedBranch,
        IncrementStrategy incrementStrategy,
        bool preventIncrementWhenBranchMerged, string expected)
    {
        var configuration = GitFlowConfigurationBuilder.New
            .WithBranch("feature", builder => builder
                .WithDeploymentMode(DeploymentMode.ContinuousDelivery)
                .WithIncrement(IncrementStrategy.Minor)
                .WithPreventIncrementOfMergedBranch(preventIncrementOfMergedBranch)
            ).WithBranch("main", builder => builder
                .WithIncrement(incrementStrategy)
                .WithPreventIncrementWhenBranchMerged(preventIncrementWhenBranchMerged)
            ).Build();

        using var fixture = new EmptyRepositoryFixture();

        fixture.MakeACommit("A");
        fixture.ApplyTag("0.1.0");
        fixture.BranchTo("feature/foo");
        fixture.MakeACommit("B");
        fixture.Checkout("main");
        fixture.MakeACommit("C");
        fixture.ApplyTag("0.2.0");
        fixture.MergeTo("feature/foo");

        fixture.AssertFullSemver(expected, configuration);
    }

@HHobeck

HHobeck commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

In MergeCommitOnNonTrunkBase and MergeCommitOnTrunkBase use the following method to determine the increment. We need to align the desired behavior for the sceanrio true / true on all workflows:

context.Increment = ConsolidateIncrement(commit, context, baseVersion);
...

and

    private static VersionField ConsolidateIncrement(
        MainlineCommit commit, MainlineContext context, BaseVersion baseVersion)
    {
        var increment = VersionField.None;

        var effectiveConfiguration1 = commit.GetEffectiveConfiguration(context.Configuration);
        if (!effectiveConfiguration1.PreventIncrementOfMergedBranch)
        {
            increment = increment.Consolidate(context.Increment);
        }

        var effectiveConfiguration2 = commit.ChildIteration!.GetEffectiveConfiguration(context.Configuration);
        if (!effectiveConfiguration2.PreventIncrementWhenBranchMerged)
        {
            increment = increment.Consolidate(baseVersion.Operator?.Increment);
        }

        if (effectiveConfiguration1.PreventIncrementOfMergedBranch &&
            effectiveConfiguration2.PreventIncrementWhenBranchMerged)
        {
            increment = increment.Consolidate(context.Increment);
        }

        if (effectiveConfiguration1.CommitMessageIncrementing != CommitMessageIncrementMode.Disabled)
        {
            increment = increment.Consolidate(commit.Increment);
        }

        return increment;
    }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE]: Support of prevent increment of merged branch in GitHub workflow

5 participants