Skip to content

Commit fd4de96

Browse files
authored
Merge pull request #1334 from dotnet/better-case-insensitivity
Fix case insensitivity for the managed engine on git worktrees, and implement for libgit2
2 parents c903f2e + e6198dc commit fd4de96

3 files changed

Lines changed: 47 additions & 19 deletions

File tree

src/NerdBank.GitVersioning/LibGit2/LibGit2VersionFile.cs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ internal LibGit2VersionFile(LibGit2Context context)
3737
/// <returns>The version information read from the file.</returns>
3838
internal VersionOptions? GetVersion(Commit commit, string repoRelativeProjectDirectory, Dictionary<ObjectId, VersionOptions?>? blobVersionCache, VersionFileRequirements requirements, out VersionFileLocations locations)
3939
{
40-
repoRelativeProjectDirectory = TrimTrailingPathSeparator(repoRelativeProjectDirectory);
40+
repoRelativeProjectDirectory = this.NormalizeTreeDirectoryPath(commit, TrimTrailingPathSeparator(repoRelativeProjectDirectory));
4141
locations = default;
4242

4343
string? searchDirectory = repoRelativeProjectDirectory ?? string.Empty;
@@ -153,4 +153,36 @@ internal LibGit2VersionFile(LibGit2Context context)
153153

154154
/// <inheritdoc/>
155155
protected override VersionOptions? GetVersionCore(VersionFileRequirements requirements, out VersionFileLocations locations) => this.GetVersion(this.Context.Commit!, this.Context.RepoRelativeProjectDirectory, null, requirements, out locations);
156+
157+
private string NormalizeTreeDirectoryPath(Commit commit, string repoRelativeProjectDirectory)
158+
{
159+
if (string.IsNullOrEmpty(repoRelativeProjectDirectory) || !this.IsIgnoreCaseEnabled())
160+
{
161+
return repoRelativeProjectDirectory;
162+
}
163+
164+
Tree currentTree = commit.Tree;
165+
string[] pathSegments = repoRelativeProjectDirectory.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
166+
var resolvedSegments = new List<string>(pathSegments.Length);
167+
168+
foreach (string segment in pathSegments)
169+
{
170+
TreeEntry? entry = currentTree[segment] ?? currentTree.FirstOrDefault(candidate => string.Equals(candidate.Name, segment, StringComparison.OrdinalIgnoreCase));
171+
if (entry?.TargetType != TreeEntryTargetType.Tree || entry.Target is not Tree childTree)
172+
{
173+
return repoRelativeProjectDirectory;
174+
}
175+
176+
resolvedSegments.Add(entry.Name);
177+
currentTree = childTree;
178+
}
179+
180+
return string.Join("/", resolvedSegments);
181+
}
182+
183+
private bool IsIgnoreCaseEnabled()
184+
{
185+
ConfigurationEntry<bool>? ignoreCaseSetting = this.Context.Repository.Config.Get<bool>("core.ignorecase");
186+
return ignoreCaseSetting?.Value ?? false;
187+
}
156188
}

src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -866,11 +866,17 @@ private bool ReadIgnoreCaseFromConfig()
866866
{
867867
try
868868
{
869-
// Try to read from .git/config first (repository-specific)
870-
string repoConfigPath = Path.Combine(this.GitDirectory, "config");
871-
if (File.Exists(repoConfigPath))
869+
string[] configPaths = this.GitDirectory == this.CommonDirectory
870+
? new[] { Path.Combine(this.CommonDirectory, "config") }
871+
: new[]
872+
{
873+
Path.Combine(this.CommonDirectory, "config"),
874+
Path.Combine(this.GitDirectory, "config"),
875+
};
876+
877+
foreach (string repoConfigPath in configPaths)
872878
{
873-
if (TryReadIgnoreCaseFromConfigFile(repoConfigPath, out bool ignoreCase))
879+
if (File.Exists(repoConfigPath) && TryReadIgnoreCaseFromConfigFile(repoConfigPath, out bool ignoreCase))
874880
{
875881
return ignoreCase;
876882
}

test/Nerdbank.GitVersioning.Tests/VersionFileTests.cs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -696,20 +696,10 @@ public void GetVersion_CaseInsensitivePathMatching()
696696
// to case-insensitive matching
697697
VersionOptions actualVersionOptionsWithDifferentCase = this.GetVersionOptions("myproject");
698698

699-
// This should also find the version file despite the case difference
700-
// NOTE: This currently only works for the managed implementation, not LibGit2
701-
if (this is VersionFileManagedTests)
702-
{
703-
Assert.NotNull(actualVersionOptionsWithDifferentCase);
704-
Assert.Equal("1.2.3", actualVersionOptionsWithDifferentCase.Version.ToString());
705-
Assert.Equal(10, actualVersionOptionsWithDifferentCase.VersionHeightOffset);
706-
}
707-
else
708-
{
709-
// LibGit2 implementation doesn't yet support case-insensitive fallback
710-
// This test documents the current limitation
711-
Assert.Null(actualVersionOptionsWithDifferentCase);
712-
}
699+
// This should also find the version file despite the case difference.
700+
Assert.NotNull(actualVersionOptionsWithDifferentCase);
701+
Assert.Equal("1.2.3", actualVersionOptionsWithDifferentCase.Version.ToString());
702+
Assert.Equal(10, actualVersionOptionsWithDifferentCase.VersionHeightOffset);
713703
}
714704

715705
[Fact]

0 commit comments

Comments
 (0)