Skip to content

Feature: Support shallow cloning of git repositories #4561

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
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: 3 additions & 2 deletions docs/input/docs/reference/requirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ build server, needs to adhere to the below requirements.

### Unshallow

The repository needs to be an [unshallow][git-unshallow] clone. This means
that the `fetch-depth` in GitHub Actions needs to be set to `0`, for instance.
The repository should be an [unshallow][git-unshallow] clone. This means
that the `fetch-depth` in GitHub Actions should set to `0`, unless
the `allowshallow` flag is used.
Check with your [build server][build-servers] to see how it can be configured
appropriately.

Expand Down
4 changes: 4 additions & 0 deletions docs/input/docs/usage/cli/arguments.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ GitVersion [path]
Currently supported config overrides: tag-prefix
/nocache Bypasses the cache, result will not be written to the cache.
/nonormalize Disables normalize step on a build server.
/allowshallow Allows GitVersion to run on a shallow clone.
This is not recommended, but can be used if you are sure
that the shallow clone contains all the information needed
to calculate the version.
/verbosity Specifies the amount of information to be displayed.
(Quiet, Minimal, Normal, Verbose, Diagnostic)
Default is Normal
Expand Down
8 changes: 5 additions & 3 deletions docs/input/docs/usage/msbuild.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ version information that is compiled into the resulting artifact.
Since version 6.0 only MSBuild running on .NET Core (`dotnet msbuild`) is supported.

Unfortunately, up until at least Visual Studio 2022 17.11, Visual Studio runs all builds
using the .NET Framework version of MSBuild, and therefore **Visual Studio is not supported**.
For more information see [this discussion](https://github.com/GitTools/GitVersion/discussions/4130).
using the .NET Framework version of MSBuild, and therefore **Visual Studio is not supported**.
For more information see [this discussion](https://github.com/GitTools/GitVersion/discussions/4130).

## TL;DR

Expand Down Expand Up @@ -261,7 +261,9 @@ There are properties that correspond to certain
In particular, setting `GitVersion_NoFetchEnabled` to `true` disables `git fetch`
during version calculation, setting `GitVersion_NoNormalizeEnabled` to `true` disables
normalize step on a build server, setting `GitVersion_NoCacheEnabled` to `true`
makes GetVersion ignore cache. All the rest command line arguments can be passed via
makes GetVersion ignore cache, setting `GitVersion_AllowShallowEnabled` to `true`
does not mandate a full clone of the repository to determine the version.
All the rest command line arguments can be passed via
`GitVersion_CommandLineArguments` variable.

## My Git repository requires authentication. What should I do?
Expand Down
46 changes: 40 additions & 6 deletions src/GitVersion.App.Tests/ArgumentParserTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,13 @@ public void NoNormalizeTrueWhenDefined()
arguments.NoNormalize.ShouldBe(true);
}

[Test]
public void AllowshallowTrueWhenDefined()
{
var arguments = this.argumentParser.ParseArguments("-allowshallow");
arguments.AllowShallow.ShouldBe(true);
}

[Test]
public void OtherArgumentsCanBeParsedBeforeNofetch()
{
Expand All @@ -653,18 +660,45 @@ public void OtherArgumentsCanBeParsedBeforeNocache()
arguments.NoCache.ShouldBe(true);
}

[TestCase("-nofetch -nonormalize -nocache")]
[TestCase("-nofetch -nocache -nonormalize")]
[TestCase("-nocache -nofetch -nonormalize")]
[TestCase("-nocache -nonormalize -nofetch")]
[TestCase("-nonormalize -nocache -nofetch")]
[TestCase("-nonormalize -nofetch -nocache")]
[Test]
public void OtherArgumentsCanBeParsedBeforeAllowshallow()
{
var arguments = this.argumentParser.ParseArguments("targetpath -allowshallow");
arguments.TargetPath.ShouldBe("targetpath");
arguments.AllowShallow.ShouldBe(true);
}

[TestCase("-nofetch -nonormalize -nocache -allowshallow")]
[TestCase("-nofetch -nonormalize -allowshallow -nocache")]
[TestCase("-nofetch -nocache -nonormalize -allowshallow")]
[TestCase("-nofetch -nocache -allowshallow -nonormalize")]
[TestCase("-nofetch -allowshallow -nonormalize -nocache")]
[TestCase("-nofetch -allowshallow -nocache -nonormalize")]
[TestCase("-nonormalize -nofetch -nocache -allowshallow")]
[TestCase("-nonormalize -nofetch -allowshallow -nocache")]
[TestCase("-nonormalize -nocache -nofetch -allowshallow")]
[TestCase("-nonormalize -nocache -allowshallow -nofetch")]
[TestCase("-nonormalize -allowshallow -nofetch -nocache")]
[TestCase("-nonormalize -allowshallow -nocache -nofetch")]
[TestCase("-nocache -nofetch -nonormalize -allowshallow")]
[TestCase("-nocache -nofetch -allowshallow -nonormalize")]
[TestCase("-nocache -nonormalize -nofetch -allowshallow")]
[TestCase("-nocache -nonormalize -allowshallow -nofetch")]
[TestCase("-nocache -allowshallow -nofetch -nonormalize")]
[TestCase("-nocache -allowshallow -nonormalize -nofetch")]
[TestCase("-allowshallow -nofetch -nonormalize -nocache")]
[TestCase("-allowshallow -nofetch -nocache -nonormalize")]
[TestCase("-allowshallow -nonormalize -nofetch -nocache")]
[TestCase("-allowshallow -nonormalize -nocache -nofetch")]
[TestCase("-allowshallow -nocache -nofetch -nonormalize")]
[TestCase("-allowshallow -nocache -nonormalize -nofetch")]
public void SeveralSwitchesCanBeParsed(string commandLineArgs)
{
var arguments = this.argumentParser.ParseArguments(commandLineArgs);
arguments.NoCache.ShouldBe(true);
arguments.NoNormalize.ShouldBe(true);
arguments.NoFetch.ShouldBe(true);
arguments.AllowShallow.ShouldBe(true);
}

[Test]
Expand Down
1 change: 1 addition & 0 deletions src/GitVersion.App.Tests/HelpWriterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ public void AllArgsAreInHelp()
{ nameof(Arguments.NoCache), "/nocache" },
{ nameof(Arguments.NoFetch), "/nofetch" },
{ nameof(Arguments.NoNormalize), "/nonormalize" },
{ nameof(Arguments.AllowShallow), "/allowshallow" },
};
var helpText = string.Empty;

Expand Down
6 changes: 6 additions & 0 deletions src/GitVersion.App/ArgumentParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,12 @@ private static bool ParseSwitches(Arguments arguments, string? name, IReadOnlyLi
return true;
}

if (name.IsSwitch("allowshallow"))
{
arguments.AllowShallow = true;
return true;
}

if (name.IsSwitch("verbosity"))
{
ParseVerbosity(arguments, value);
Expand Down
2 changes: 1 addition & 1 deletion src/GitVersion.App/ArgumentParserExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public static bool IsSwitch(this string? value, string switchName)

public static bool ArgumentRequiresValue(this string argument, int argumentIndex)
{
var booleanArguments = new[] { "updateassemblyinfo", "ensureassemblyinfo", "nofetch", "nonormalize", "nocache" };
var booleanArguments = new[] { "updateassemblyinfo", "ensureassemblyinfo", "nofetch", "nonormalize", "nocache", "allowshallow" };

var argumentMightRequireValue = !booleanArguments.Contains(argument[1..], StringComparer.OrdinalIgnoreCase);

Expand Down
4 changes: 3 additions & 1 deletion src/GitVersion.App/Arguments.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ internal class Arguments
public bool NoFetch;
public bool NoCache;
public bool NoNormalize;
public bool AllowShallow;

public string? LogFilePath;
public string? ShowVariable;
Expand Down Expand Up @@ -77,7 +78,8 @@ public GitVersionOptions ToOptions()
{
NoFetch = NoFetch,
NoCache = NoCache,
NoNormalize = NoNormalize
NoNormalize = NoNormalize,
AllowShallow = AllowShallow,
},

WixInfo =
Expand Down
73 changes: 73 additions & 0 deletions src/GitVersion.Core.Tests/Core/GitVersionExecutorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,79 @@ public void CalculateVersionVariables_ShallowFetch_ThrowException()
exception?.Message.ShouldBe("Repository is a shallow clone. Git repositories must contain the full history. See https://gitversion.net/docs/reference/requirements#unshallow for more info.");
}

[Test]
public void CalculateVersionVariables_ShallowFetch_WithAllowShallow_ShouldNotThrowException()
{
// Setup
using var fixture = new RemoteRepositoryFixture();
fixture.LocalRepositoryFixture.MakeShallow();

using var worktreeFixture = new LocalRepositoryFixture(new(fixture.LocalRepositoryFixture.RepositoryPath));
var gitVersionOptions = new GitVersionOptions
{
WorkingDirectory = worktreeFixture.RepositoryPath,
Settings = { AllowShallow = true }
};

var environment = new TestEnvironment();
environment.SetEnvironmentVariable(AzurePipelines.EnvironmentVariableName, "true");

this.sp = GetServiceProvider(gitVersionOptions, environment: environment);

sp.DiscoverRepository();

var sut = sp.GetRequiredService<IGitVersionCalculateTool>();

// Execute
var version = sut.CalculateVersionVariables();

// Verify
version.ShouldNotBeNull();
var commits = worktreeFixture.Repository.Head.Commits;
version.Sha.ShouldBe(commits.First().Sha);
}

[Test]
public void CalculateVersionVariables_WithLimitedCloneDepth_AndAllowShallowTrue_ShouldCalculateVersionCorrectly()
{
// Setup
using var fixture = new RemoteRepositoryFixture();
fixture.LocalRepositoryFixture.MakeShallow();

fixture.LocalRepositoryFixture.Repository.MakeACommit("Initial commit");
fixture.LocalRepositoryFixture.Repository.MakeATaggedCommit("1.0.0");
var latestCommit = fixture.LocalRepositoryFixture.Repository.MakeACommit("+semver:major");

using var worktreeFixture = new LocalRepositoryFixture(new(fixture.LocalRepositoryFixture.RepositoryPath));

var gitVersionOptions = new GitVersionOptions
{
WorkingDirectory = worktreeFixture.RepositoryPath,
Settings = { AllowShallow = true }
};

var environment = new TestEnvironment();
environment.SetEnvironmentVariable(AzurePipelines.EnvironmentVariableName, "true");

this.sp = GetServiceProvider(gitVersionOptions, environment: environment);
sp.DiscoverRepository();
var sut = sp.GetRequiredService<IGitVersionCalculateTool>();

// Execute
var version = sut.CalculateVersionVariables();

// Verify
version.ShouldNotBeNull();

// Verify that the correct commit is used
version.Sha.ShouldBe(latestCommit.Sha);
version.MajorMinorPatch.ShouldBe("2.0.0");

// Verify repository is still recognized as shallow
var repository = this.sp.GetRequiredService<IGitRepository>();
repository.IsShallow.ShouldBeTrue("Repository should still be shallow after version calculation");
}

private string GetWorktreePath(EmptyRepositoryFixture fixture)
{
var worktreePath = FileSystemHelper.Path.Combine(this.fileSystem.Directory.GetParent(fixture.RepositoryPath)?.FullName, Guid.NewGuid().ToString());
Expand Down
9 changes: 8 additions & 1 deletion src/GitVersion.Core/Core/GitPreparer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,14 @@ private void NormalizeGitDirectory(bool noFetch, string? currentBranchName, bool

if (this.repository.IsShallow)
{
throw new WarningException("Repository is a shallow clone. Git repositories must contain the full history. See https://gitversion.net/docs/reference/requirements#unshallow for more info.");
if (this.options.Value.Settings.AllowShallow)
{
this.log.Info("Repository is a shallow clone. GitVersion will continue, but it is recommended to use a full clone for accurate versioning.");
}
else
{
throw new WarningException("Repository is a shallow clone. Git repositories must contain the full history. See https://gitversion.net/docs/reference/requirements#unshallow for more info.");
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/GitVersion.Core/Options/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ public record Settings
public bool NoCache;
public bool NoNormalize;
public bool OnlyTrackedBranches = false;
public bool AllowShallow = false;
}
1 change: 1 addition & 0 deletions src/GitVersion.Core/PublicAPI.Shipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,7 @@ GitVersion.Settings.NoCache -> bool
GitVersion.Settings.NoFetch -> bool
GitVersion.Settings.NoNormalize -> bool
GitVersion.Settings.OnlyTrackedBranches -> bool
GitVersion.Settings.AllowShallow -> bool
GitVersion.VersionCalculation.BaseVersion
GitVersion.VersionCalculation.BaseVersion.BaseVersion() -> void
GitVersion.VersionCalculation.BaseVersion.BaseVersion(GitVersion.VersionCalculation.BaseVersionOperand! Operand) -> void
Expand Down
10 changes: 6 additions & 4 deletions src/GitVersion.MsBuild/msbuild/tools/GitVersion.MsBuild.props
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,22 @@
<GitVersion_NoFetchEnabled Condition="$(GitVersion_NoFetchEnabled) == ''">false</GitVersion_NoFetchEnabled>
<GitVersion_NoNormalizeEnabled Condition="$(GitVersion_NoNormalizeEnabled) == ''">false</GitVersion_NoNormalizeEnabled>
<GitVersion_NoCacheEnabled Condition="$(GitVersion_NoCacheEnabled) == ''">false</GitVersion_NoCacheEnabled>
<GitVersion_AllowShallowEnabled Condition="$(GitVersion_AllowShallowEnabled) == ''">false</GitVersion_AllowShallowEnabled>

<GitVersion_ToolArgments>$(GitVersion_CommandLineArguments) -output file -outputfile &quot;$(GitVersionOutputFile)&quot;</GitVersion_ToolArgments>
<GitVersion_ToolArgments Condition=" '$(GitVersion_NoFetchEnabled)' == 'true' ">$(GitVersion_ToolArgments) -nofetch</GitVersion_ToolArgments>
<GitVersion_ToolArgments Condition=" '$(GitVersion_NoNormalizeEnabled)' == 'true' ">$(GitVersion_ToolArgments) -nonormalize</GitVersion_ToolArgments>
<GitVersion_ToolArgments Condition=" '$(GitVersion_NoCacheEnabled)' == 'true' ">$(GitVersion_ToolArgments) -nocache</GitVersion_ToolArgments>
<GitVersion_ToolArgments Condition=" '$(GitVersion_AllowShallowEnabled)' == 'true' ">$(GitVersion_ToolArgments) -allowshallow</GitVersion_ToolArgments>
</PropertyGroup>

<PropertyGroup>
<!-- The GitVersion task is explicitly disabled when running on the .NET Framework because it's no longer supported.
If a project that uses GitVersion.MsBuild is opened in Visual Studio,
the task will be turned off because Visual Studio operates on the .NET Framework's version of MSBuild.
<!-- The GitVersion task is explicitly disabled when running on the .NET Framework because it's no longer supported.
If a project that uses GitVersion.MsBuild is opened in Visual Studio,
the task will be turned off because Visual Studio operates on the .NET Framework's version of MSBuild.
However, you can still execute GitVersion.MsBuild as part of the `dotnet build` or `dotnet msbuild` commands. -->
<DisableGitVersionTask Condition=" '$(MSBuildRuntimeType)' != 'Core' ">true</DisableGitVersionTask>

<DisableGitVersionTask Condition=" '$(DisableGitVersionTask)' == '' ">false</DisableGitVersionTask>

<!-- Property that enables WriteVersionInfoToBuildLog -->
Expand Down