Skip to content

Add HEAD support #3241

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

Closed
Closed
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
5 changes: 5 additions & 0 deletions docs/input/docs/reference/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,11 @@ Example of invalid `Strict`, but valid `Loose`
1.2.3.4
```

### handle-detached-branch
Copy link
Member

Choose a reason for hiding this comment

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

Since you're targeting main, this is going to be rolled into v6. To target v5, you need to rebase and retarget against support/5.x, but I would like to avoid the introduction of new configuration properties. As such, I don't think we need any new configuration properties to add support for detached HEAD?

Copy link
Author

Choose a reason for hiding this comment

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

For me it's ok to go for v6. Are you proposing to change the beaviour and always handle detached branches? Will I remove the handle-detached-branch option and every changes correlated?


Avoid to strickly request to refer to a branch. If detached, the `no-branch`
reference will be used.

[1145]: https://github.com/GitTools/GitVersion/issues/1145
[1366]: https://github.com/GitTools/GitVersion/issues/1366
[2506]: https://github.com/GitTools/GitVersion/pull/2506#issuecomment-754754037
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,4 @@ increment: Inherit
commit-date-format: yyyy-MM-dd
merge-message-formats: {}
update-build-number: true
handle-detached-branch: false
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ private GitFlowConfigurationBuilder()
CommitDateFormat = "yyyy-MM-dd",
UpdateBuildNumber = true,
SemanticVersionFormat = SemanticVersionFormat.Strict,
HandleDetachedBranch = false,
TagPreReleaseWeight = 60000,
Increment = IncrementStrategy.Inherit
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ private GitHubFlowConfigurationBuilder()
CommitDateFormat = "yyyy-MM-dd",
UpdateBuildNumber = true,
SemanticVersionFormat = SemanticVersionFormat.Strict,
HandleDetachedBranch = false,
TagPreReleaseWeight = 60000,
Increment = IncrementStrategy.Inherit
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ internal abstract class TestConfigurationBuilderBase<TConfigurationBuilder>
private string? commitDateFormat;
private bool? updateBuildNumber;
private SemanticVersionFormat semanticVersionFormat = SemanticVersionFormat.Strict;
private bool? handleDetachedBranch;
private Dictionary<string, string>? mergeMessageFormats;
protected readonly Dictionary<string, TestBranchConfigurationBuilder> branchConfigurationBuilders = new();

Expand Down Expand Up @@ -164,6 +165,12 @@ public virtual TConfigurationBuilder WithSemanticVersionFormat(SemanticVersionFo
return (TConfigurationBuilder)this;
}

public virtual TConfigurationBuilder WithHandleDetachedBranch(bool? value)
{
this.handleDetachedBranch = value;
return (TConfigurationBuilder)this;
}

public virtual TConfigurationBuilder WithMergeMessageFormats(Dictionary<string, string> value)
{
this.mergeMessageFormats = value;
Expand Down Expand Up @@ -214,6 +221,7 @@ public virtual TConfigurationBuilder WithConfiguration(GitVersionConfiguration v
WithCommitDateFormat(value.CommitDateFormat);
WithUpdateBuildNumber(value.UpdateBuildNumber);
WithSemanticVersionFormat(value.SemanticVersionFormat);
WithHandleDetachedBranch(value.HandleDetachedBranch);
WithMergeMessageFormats(value.MergeMessageFormats);
foreach (var (name, branchConfiguration) in value.Branches)
{
Expand Down Expand Up @@ -246,6 +254,7 @@ public virtual GitVersionConfiguration Build()
CommitDateFormat = this.commitDateFormat,
UpdateBuildNumber = this.updateBuildNumber,
SemanticVersionFormat = this.semanticVersionFormat,
HandleDetachedBranch = this.handleDetachedBranch,
MergeMessageFormats = this.mergeMessageFormats ?? new()
};
Dictionary<string, BranchConfiguration> branches = new();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using GitTools.Testing;
using GitVersion.BuildAgents;
using GitVersion.Configuration;
using GitVersion.Core.Tests.Helpers;
using LibGit2Sharp;
using Microsoft.Extensions.DependencyInjection;
Expand Down Expand Up @@ -98,6 +99,22 @@ public void GivenARemoteGitRepositoryWhenCheckingOutDetachedHeadUsingExistingImp
$"It looks like the branch being examined is a detached Head pointing to commit '{fixture.LocalRepositoryFixture.Repository.Head.Tip.Id.ToString(7)}'. Without a proper branch name GitVersion cannot determine the build version.");
}

[Test]
[TestCase(true)]
[TestCase(false)]
public void GivenARemoteGitRepositoryWhenCheckingOutDetachedHeadUsingExistingImplementationHandleDetachedBranch(bool handleDetachedBranch)
{
using var fixture = new RemoteRepositoryFixture();
fixture.LocalRepositoryFixture.Checkout(fixture.LocalRepositoryFixture.Repository.Head.Tip.Sha);

var configuration = new GitVersionConfiguration { HandleDetachedBranch = handleDetachedBranch };
if (handleDetachedBranch)
fixture.AssertFullSemver("0.0.1--no-branch-.1+5", configuration: configuration, repository: fixture.LocalRepositoryFixture.Repository, onlyTrackedBranches: false);
else
Should.Throw<WarningException>(() => fixture.AssertFullSemver("0.1.0+4", repository: fixture.LocalRepositoryFixture.Repository, onlyTrackedBranches: false),
$"It looks like the branch being examined is a detached Head pointing to commit '{fixture.LocalRepositoryFixture.Repository.Head.Tip.Id.ToString(7)}'. Without a proper branch name GitVersion cannot determine the build version.");
}

[Test]
[Ignore("Needs more investigations.")]
public void GivenARemoteGitRepositoryWhenCheckingOutDetachedHeadUsingTrackingBranchOnlyBehaviourShouldReturnVersion014Plus5()
Expand Down
2 changes: 2 additions & 0 deletions src/GitVersion.Core/Configuration/ConfigurationBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ private static void ApplyOverrides(GitVersionConfiguration targetConfig, GitVers
targetConfig.MergeMessageFormats = overrideConfiguration.MergeMessageFormats.Any() ? overrideConfiguration.MergeMessageFormats : targetConfig.MergeMessageFormats;
targetConfig.UpdateBuildNumber = overrideConfiguration.UpdateBuildNumber ?? targetConfig.UpdateBuildNumber;
targetConfig.SemanticVersionFormat = overrideConfiguration.SemanticVersionFormat;
targetConfig.HandleDetachedBranch = overrideConfiguration.HandleDetachedBranch ?? targetConfig.HandleDetachedBranch;

if (overrideConfiguration.Ignore is { IsEmpty: false })
{
Expand Down Expand Up @@ -187,6 +188,7 @@ private static GitVersionConfiguration CreateDefaultConfiguration()
CommitDateFormat = "yyyy-MM-dd",
UpdateBuildNumber = true,
SemanticVersionFormat = SemanticVersionFormat.Strict,
HandleDetachedBranch = false,
TagPreReleaseWeight = DefaultTagPreReleaseWeight,
Increment = IncrementStrategy.Inherit
};
Expand Down
3 changes: 3 additions & 0 deletions src/GitVersion.Core/Configuration/GitVersionConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ public string? NextVersion
[YamlMember(Alias = "semver-format")]
public SemanticVersionFormat SemanticVersionFormat { get; set; } = SemanticVersionFormat.Strict;

[YamlMember(Alias = "handle-detached-branch")]
public bool? HandleDetachedBranch { get; set; }

public override string ToString()
{
var stringBuilder = new StringBuilder();
Expand Down
2 changes: 1 addition & 1 deletion src/GitVersion.Core/Core/Abstractions/IRepositoryStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public interface IRepositoryStore

IEnumerable<IBranch> GetSourceBranches(IBranch branch, GitVersionConfiguration configuration, IEnumerable<IBranch> excludedBranches);

SemanticVersion? GetCurrentCommitTaggedVersion(ICommit? commit, string? tagPrefix);
SemanticVersion? GetCurrentCommitTaggedVersion(ICommit? commit, GitVersionConfiguration configuration);

IEnumerable<SemanticVersion> GetVersionTagsOnBranch(IBranch branch, string? tagPrefixRegex);
IEnumerable<(ITag Tag, SemanticVersion Semver, ICommit Commit)> GetValidVersionTags(string? tagPrefixRegex, DateTimeOffset? olderThan = null);
Expand Down
2 changes: 1 addition & 1 deletion src/GitVersion.Core/Core/GitVersionContextFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public GitVersionContext Create(GitVersionOptions gitVersionOptions)
currentBranch = branchForCommit ?? currentBranch;
}

var currentCommitTaggedVersion = this.repositoryStore.GetCurrentCommitTaggedVersion(currentCommit, configuration.TagPrefix);
var currentCommitTaggedVersion = this.repositoryStore.GetCurrentCommitTaggedVersion(currentCommit, configuration);
var numberOfUncommittedChanges = this.repositoryStore.GetNumberOfUncommittedChanges();

return new GitVersionContext(currentBranch, currentCommit, configuration, currentCommitTaggedVersion, numberOfUncommittedChanges);
Expand Down
30 changes: 18 additions & 12 deletions src/GitVersion.Core/Core/RepositoryStore.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,17 +146,16 @@ public IEnumerable<IBranch> GetSourceBranches(IBranch branch, GitVersionConfigur
var referenceLookup = this.repository.Refs.ToLookup(r => r.TargetIdentifier);

var returnedBranches = new HashSet<IBranch>();
if (referenceLookup.Any())
if (!referenceLookup.Any())
yield break;
foreach (var branchCommit in FindCommitBranchesWasBranchedFrom(branch, configuration, excludedBranches))
{
foreach (var branchCommit in FindCommitBranchesWasBranchedFrom(branch, configuration, excludedBranches))
foreach (var _ in referenceLookup[branchCommit.Commit.Sha]
.Where(r => r.Name.Friendly == branchCommit.Branch.Name.Friendly))
{
foreach (var _ in referenceLookup[branchCommit.Commit.Sha]
.Where(r => r.Name.Friendly == branchCommit.Branch.Name.Friendly))
if (returnedBranches.Add(branchCommit.Branch))
{
if (returnedBranches.Add(branchCommit.Branch))
{
yield return branchCommit.Branch;
}
yield return branchCommit.Branch;
}
}
}
Expand Down Expand Up @@ -219,9 +218,9 @@ public IEnumerable<BranchCommit> FindCommitBranchesWasBranchedFrom(IBranch branc
}
}

public SemanticVersion? GetCurrentCommitTaggedVersion(ICommit? commit, string? tagPrefix)
public SemanticVersion? GetCurrentCommitTaggedVersion(ICommit? commit, GitVersionConfiguration configuration)
=> this.repository.Tags
.SelectMany(t => GetCurrentCommitSemanticVersions(commit, tagPrefix, t))
.SelectMany(t => GetCurrentCommitSemanticVersions(commit, configuration.TagPrefix, t, configuration.HandleDetachedBranch ?? false))
.Max();

public IEnumerable<SemanticVersion> GetVersionTagsOnBranch(IBranch branch, string? tagPrefixRegex)
Expand Down Expand Up @@ -290,12 +289,19 @@ public bool IsCommitOnBranch(ICommit? baseVersionSource, IBranch branch, ICommit
private static bool IsReleaseBranch(INamedReference branch, IEnumerable<KeyValuePair<string, BranchConfiguration>> releaseBranchConfig)
=> releaseBranchConfig.Any(c => c.Value?.Regex != null && Regex.IsMatch(branch.Name.Friendly, c.Value.Regex));

private static IEnumerable<SemanticVersion> GetCurrentCommitSemanticVersions(ICommit? commit, string? tagPrefix, ITag tag)
private IEnumerable<SemanticVersion> GetCurrentCommitSemanticVersions(ICommit? commit, string? tagPrefix, ITag tag, bool handleDetachedBranch)
{
if (commit == null)
return Array.Empty<SemanticVersion>();

var targetCommit = tag.PeeledTargetCommit();
if (targetCommit == null)
return Array.Empty<SemanticVersion>();

var commitToCompare = handleDetachedBranch ? FindMergeBase(commit, targetCommit) : commit;
var tagName = tag.Name.Friendly;

return targetCommit != null && Equals(targetCommit, commit) && SemanticVersion.TryParse(tagName, tagPrefix, out var version)
return Equals(targetCommit, commitToCompare) && SemanticVersion.TryParse(tagName, tagPrefix, out var version)
? new[] { version }
: Array.Empty<SemanticVersion>();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ private void UpdatePreReleaseTag(EffectiveBranchConfiguration configuration, Sem

private static void EnsureHeadIsNotDetached(GitVersionContext context)
{
if (context.CurrentBranch.IsDetachedHead != true)
if (context.CurrentBranch.IsDetachedHead != true || (context.Configuration.HandleDetachedBranch ?? false))
{
return;
}
Expand Down