Skip to content

Topological commit sort causes issues when master is merged into a feature branch #4356

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 8, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/input/docs/reference/modes/continuous-delivery.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Continuous delivery is good when you deploy continuously to an testing system.
* 1.1.0-3
* 1.1.0-2 (tag: 1.1.0-2) <-- This is the version which has been deployed on testing
* 1.1.0-1
* 1.1.1-0
* 1.1.0-0

Tags are not required but optional in this mode to communicate when the release
is done as it's an automated process.
Expand Down
2 changes: 1 addition & 1 deletion docs/input/docs/reference/modes/continuous-deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ to deploy on production. This means that GitVersion will build
* 1.2.0
* 1.1.0 (tag: 1.1.0) <-- This is the version which has been deployed on production
* 1.1.0
* 1.1.1
* 1.1.0

Tags are required in this mode to communicate when the deployment happens on production.

Expand Down
2 changes: 1 addition & 1 deletion docs/input/docs/reference/modes/manual-deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ deployed. For instance:
* 1.1.0-2+1
* 1.1.0-1+2 (tag: 1.1.0-1) <-- This is the version which has been deployed on testing
* 1.1.0-1+1
* 1.1.1-1+0
* 1.1.0-1+0

Tags are required in this mode to communicate when the release is done as it's
an external manual process.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public static void AssertFullSemver(this RepositoryFixtureBase fixture, string f
/// <summary>
/// Simulates running on build server
/// </summary>
public static void InitializeRepo(this RemoteRepositoryFixture fixture)
public static void InitializeRepository(this RemoteRepositoryFixture fixture)
{
var gitVersionOptions = new GitVersionOptions
{
Expand Down
23 changes: 13 additions & 10 deletions src/GitVersion.Core.Tests/IntegrationTests/OtherScenarios.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public void DoNotBlowUpWhenMainAndDevelopPointAtSameCommit()
Commands.Fetch(fixture.LocalRepositoryFixture.Repository, fixture.LocalRepositoryFixture.Repository.Network.Remotes.First().Name, [], new(), null);
Commands.Checkout(fixture.LocalRepositoryFixture.Repository, fixture.Repository.Head.Tip);
fixture.LocalRepositoryFixture.Repository.Branches.Remove(MainBranch);
fixture.InitializeRepo();
fixture.InitializeRepository();
fixture.AssertFullSemver("1.0.1-1");
}

Expand Down Expand Up @@ -92,15 +92,15 @@ public void DoNotBlowUpWhenDevelopAndFeatureBranchPointAtSameCommit()
Commands.Fetch(fixture.LocalRepositoryFixture.Repository, fixture.LocalRepositoryFixture.Repository.Network.Remotes.First().Name, [], new(), null);
Commands.Checkout(fixture.LocalRepositoryFixture.Repository, fixture.Repository.Head.Tip);
fixture.LocalRepositoryFixture.Repository.Branches.Remove(MainBranch);
fixture.InitializeRepo();
fixture.InitializeRepository();
fixture.AssertFullSemver("1.1.0-alpha.1");
}

[TestCase(true, 1)]
[TestCase(false, 1)]
[TestCase(true, 5)]
[TestCase(false, 5)]
public void HasDirtyFlagWhenUncommittedChangesAreInRepo(bool stageFile, int numberOfFiles)
public void HasDirtyFlagWhenUncommittedChangesAreInRepository(bool stageFile, int numberOfFiles)
{
using var fixture = new EmptyRepositoryFixture();
fixture.MakeACommit();
Expand Down Expand Up @@ -133,7 +133,7 @@ public void NoDirtyFlagInCleanRepository()

[TestCase(false, "1.1.0-alpha.2")]
[TestCase(true, "1.2.0-alpha.1")]
public void EnsureTrackMergeTargetStrategyWhichWillLookForTaggedMergecommits(bool trackMergeTarget, string expectedVersion)
public void EnsureTrackMergeTargetStrategyWhichWillLookForTaggedMergeCommits(bool trackMergeTarget, string expectedVersion)
{
// * 9daa6ea 53 minutes ago (HEAD -> develop)
// | * 85536f2 55 minutes ago (tag: 1.1.0, main)
Expand Down Expand Up @@ -1283,7 +1283,7 @@ public void EnsureVersionAfterMainIsMergedBackToDevelopIsCorrectForMainline(bool
}

[TestCase(false, "2.0.0-alpha.3")]
[TestCase(true, "2.0.0-alpha.3")]
[TestCase(true, "3.0.0-alpha.2")]
public void EnsureVersionAfterMainIsMergedBackToDevelopIsCorrectForGitFlow(bool applyTag, string semanticVersion)
{
var configuration = GitFlowConfigurationBuilder.New.Build();
Expand All @@ -1300,7 +1300,7 @@ public void EnsureVersionAfterMainIsMergedBackToDevelopIsCorrectForGitFlow(bool

fixture.Checkout("main");
fixture.MakeACommit("C");
if (applyTag) fixture.ApplyTag("1.0.1");
if (applyTag) fixture.ApplyTag("2.0.0");
fixture.Checkout("develop");
fixture.MergeNoFF("main");

Expand Down Expand Up @@ -1380,7 +1380,8 @@ public void AlternativeSemanticVersionsShouldBeConsidered()
}

[TestCase(null, "6.0.0-beta.6")]
[TestCase("beta", "6.0.0-beta.21")]
[TestCase("beta", "6.0.0-beta.6")]
[TestCase("gamma", "6.0.0-gamma.21")]
public void AlternativeSemanticVersionsShouldBeConsidered(string? labelOnMain, string version)
{
var configuration = GitFlowConfigurationBuilder.New
Expand All @@ -1391,14 +1392,16 @@ public void AlternativeSemanticVersionsShouldBeConsidered(string? labelOnMain, s
using var fixture = new EmptyRepositoryFixture();

fixture.MakeATaggedCommit("1.0.0");
fixture.MakeATaggedCommit("4.0.0-beta.14");
fixture.MakeACommit("A");
fixture.ApplyTag("4.0.0-beta.14");
fixture.ApplyTag("4.0.0-gamma.14");
fixture.MakeACommit("B");
fixture.MakeATaggedCommit("6.0.0-alpha.1");
fixture.MakeATaggedCommit("6.0.0-alpha.2");
fixture.MakeATaggedCommit("6.0.0-alpha.3");
fixture.MakeACommit("B");
fixture.MakeATaggedCommit("6.0.0-beta.5");
fixture.MakeACommit("C");
fixture.MakeATaggedCommit("6.0.0-beta.5");
fixture.MakeACommit("D");

fixture.AssertFullSemver(version, configuration);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,23 @@ public void RepositoryWithALotOfTags()

using var fixture = new EmptyRepositoryFixture();

const int maxCommits = 500;
for (int i = 0; i < maxCommits; i++)
Random random = new(4711);
SemanticVersion semanticVersion = SemanticVersion.Empty;
for (int i = 0; i < 500; i++)
{
fixture.MakeATaggedCommit($"1.0.{i}");
VersionField versionField = (VersionField)random.Next(1, 4);
semanticVersion = semanticVersion.Increment(versionField, string.Empty, forceIncrement: true);
fixture.MakeATaggedCommit(semanticVersion.ToString("j"));
}

fixture.BranchTo("feature");
fixture.MakeACommit();

var sw = Stopwatch.StartNew();

fixture.AssertFullSemver($"1.0.{maxCommits}-feature.1+1", configuration);
fixture.AssertFullSemver("170.3.3-feature.1+1", configuration);
sw.Stop();

sw.ElapsedMilliseconds.ShouldBeLessThan(5000);
sw.ElapsedMilliseconds.ShouldBeLessThan(2500);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ private IReadOnlyCollection<ICommit> GetCommitHistory(string? tagPrefix, Semanti
.ToHashSet()
);

var intermediateCommits = GetIntermediateCommits(baseVersionSource, currentCommit, ignore).ToArray();
var intermediateCommits = this.repositoryStore.GetCommitLog(baseVersionSource, currentCommit, ignore);
var commitLog = intermediateCommits.ToDictionary(element => element.Id.Sha);

foreach (var intermediateCommit in intermediateCommits.Reverse())
Expand Down Expand Up @@ -197,7 +197,6 @@ public IEnumerable<ICommit> GetMergedCommits(ICommit mergeCommit, int index, IIg

ICommit findMergeBase = this.repositoryStore.FindMergeBase(baseCommit, mergedCommit)
?? throw new InvalidOperationException("Cannot find the base commit of merged branch.");

return GetIntermediateCommits(findMergeBase, mergedCommit, ignore);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using GitVersion.Configuration;
using GitVersion.Core;
using GitVersion.Extensions;
using GitVersion.Logging;

namespace GitVersion.VersionCalculation;

Expand All @@ -10,11 +11,13 @@ namespace GitVersion.VersionCalculation;
/// Increments if the tag is not the current commit.
/// </summary>
internal sealed class TaggedCommitVersionStrategy(
ILog log,
Lazy<GitVersionContext> contextLazy,
ITaggedSemanticVersionService taggedSemanticVersionService,
IIncrementStrategyFinder incrementStrategyFinder)
: IVersionStrategy
{
private readonly ILog log = log.NotNull();
private readonly ITaggedSemanticVersionService taggedSemanticVersionService = taggedSemanticVersionService.NotNull();
private readonly Lazy<GitVersionContext> contextLazy = contextLazy.NotNull();
private readonly IIncrementStrategyFinder incrementStrategyFinder = incrementStrategyFinder.NotNull();
Expand All @@ -41,33 +44,48 @@ private IEnumerable<BaseVersion> GetBaseVersionsInternal(EffectiveBranchConfigur

var label = configuration.Value.GetBranchSpecificLabel(Context.CurrentBranch.Name, null);

var semanticVersionTreshold = SemanticVersion.Empty;
List<SemanticVersionWithTag> alternativeSemanticVersionsWithTag = [];
foreach (var semanticVersionWithTag in taggedSemanticVersions)
foreach (var semanticVersion in taggedSemanticVersions)
{
if (!semanticVersionWithTag.Value.IsMatchForBranchSpecificLabel(label))
if (!semanticVersion.Value.IsMatchForBranchSpecificLabel(label))
{
alternativeSemanticVersionsWithTag.Add(semanticVersionWithTag);
alternativeSemanticVersionsWithTag.Add(semanticVersion);
continue;
}

var baseVersionSource = semanticVersionWithTag.Tag.Commit;
var alternativeSemanticVersionMax = alternativeSemanticVersionsWithTag.Max()?.Value;
var highestPossibleSemanticVersion = semanticVersion.Value.Increment(
VersionField.Major, null, forceIncrement: true, alternativeSemanticVersionMax
);
if (highestPossibleSemanticVersion.IsLessThan(semanticVersionTreshold, includePreRelease: false))
{
this.log.Info(
$"The tag '{semanticVersion.Value}' is skipped because it provides a lower base version than other tags."
);
alternativeSemanticVersionsWithTag.Clear();
continue;
}

var baseVersionSource = semanticVersion.Tag.Commit;
var increment = incrementStrategyFinder.DetermineIncrementedField(
currentCommit: Context.CurrentCommit,
baseVersionSource: baseVersionSource,
shouldIncrement: true,
configuration: configuration.Value,
label: label
);
semanticVersionTreshold = semanticVersion.Value.Increment(increment, null, forceIncrement: true);

yield return new BaseVersion(
$"Git tag '{semanticVersionWithTag.Tag.Name.Friendly}'", semanticVersionWithTag.Value, baseVersionSource)
$"Git tag '{semanticVersion.Tag.Name.Friendly}'", semanticVersion.Value, baseVersionSource)
{
Operator = new BaseVersionOperator
{
Increment = increment,
ForceIncrement = false,
Label = label,
AlternativeSemanticVersion = alternativeSemanticVersionsWithTag.Max()?.Value
AlternativeSemanticVersion = alternativeSemanticVersionMax
}
};
alternativeSemanticVersionsWithTag.Clear();
Expand Down
Loading