Skip to content

Commit 5496648

Browse files
authored
Merge pull request #659 from dotnet/fix658
Count merge commits in path filtered height if any parent changed it
2 parents 2a3260a + 96be5aa commit 5496648

File tree

3 files changed

+67
-25
lines changed

3 files changed

+67
-25
lines changed

src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs

+32
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,38 @@ public void GetVersion_PathFilterInTwoDeepSubDirAndVersionBump()
751751
Assert.Equal(1, this.GetVersionHeight(relativeDirectory));
752752
}
753753

754+
[Fact]
755+
public void GetVersion_PathFilterPlusMerge()
756+
{
757+
this.InitializeSourceControl(withInitialCommit: false);
758+
this.WriteVersionFile(new VersionOptions
759+
{
760+
Version = new SemanticVersion("1.0"),
761+
PathFilters = new FilterPath[] { new FilterPath(".", string.Empty) },
762+
});
763+
764+
string conflictedFilePath = Path.Combine(this.RepoPath, "foo.txt");
765+
766+
File.WriteAllText(conflictedFilePath, "foo");
767+
Commands.Stage(this.LibGit2Repository, conflictedFilePath);
768+
this.LibGit2Repository.Commit("Add foo.txt with foo content.", this.Signer, this.Signer);
769+
Branch originalBranch = this.LibGit2Repository.Head;
770+
771+
Branch topicBranch = this.LibGit2Repository.Branches.Add("topic", "HEAD~1");
772+
Commands.Checkout(this.LibGit2Repository, topicBranch);
773+
File.WriteAllText(conflictedFilePath, "bar");
774+
Commands.Stage(this.LibGit2Repository, conflictedFilePath);
775+
this.LibGit2Repository.Commit("Add foo.txt with bar content.", this.Signer, this.Signer);
776+
777+
Commands.Checkout(this.LibGit2Repository, originalBranch);
778+
MergeResult result = this.LibGit2Repository.Merge(topicBranch, this.Signer, new MergeOptions { FileConflictStrategy = CheckoutFileConflictStrategy.Ours });
779+
Assert.Equal(MergeStatus.Conflicts, result.Status);
780+
Commands.Stage(this.LibGit2Repository, conflictedFilePath);
781+
this.LibGit2Repository.Commit("Merge two branches", this.Signer, this.Signer);
782+
783+
Assert.Equal(3, this.GetVersionHeight());
784+
}
785+
754786
[Fact]
755787
public void GetVersionHeight_ProjectDirectoryDifferentToVersionJsonDirectory()
756788
{

src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -433,8 +433,8 @@ bool ContainsRelevantChanges(IEnumerable<TreeEntryChanges> changes) =>
433433
: includePaths;
434434

435435
// If the diff between this commit and any of its parents
436-
// does not touch a path that we care about, don't bump the
437-
// height.
436+
// touches a path that we care about, bump the height.
437+
// A no-parent commit is relevant if it introduces anything in the filtered path.
438438
var relevantCommit =
439439
commit.Parents.Any()
440440
? commit.Parents.Any(parent => ContainsRelevantChanges(commit.GetRepository().Diff

src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs

+33-23
Original file line numberDiff line numberDiff line change
@@ -169,22 +169,27 @@ bool TryCalculateHeight(GitCommit commit)
169169

170170
if (pathFilters is not null)
171171
{
172-
var relevantCommit = true;
173-
174-
foreach (var parentId in commit.Parents)
172+
// If the diff between this commit and any of its parents
173+
// touches a path that we care about, bump the height.
174+
bool relevantCommit = false, anyParents = false;
175+
foreach (GitObjectId parentId in commit.Parents)
175176
{
176-
var parent = repository.GetCommit(parentId);
177-
relevantCommit = IsRelevantCommit(repository, commit, parent, pathFilters);
178-
179-
// If the diff between this commit and any of its parents
180-
// does not touch a path that we care about, don't bump the
181-
// height.
182-
if (!relevantCommit)
177+
anyParents = true;
178+
GitCommit parent = repository.GetCommit(parentId);
179+
if (IsRelevantCommit(repository, commit, parent, pathFilters))
183180
{
181+
// No need to scan further, as a positive match will never turn negative.
182+
relevantCommit = true;
184183
break;
185184
}
186185
}
187186

187+
if (!anyParents)
188+
{
189+
// A no-parent commit is relevant if it introduces anything in the filtered path.
190+
relevantCommit = IsRelevantCommit(repository, commit, parent: default(GitCommit), pathFilters);
191+
}
192+
188193
if (!relevantCommit)
189194
{
190195
height = 0;
@@ -214,12 +219,12 @@ private static bool IsRelevantCommit(GitRepository repository, GitCommit commit,
214219
return IsRelevantCommit(
215220
repository,
216221
repository.GetTree(commit.Tree),
217-
repository.GetTree(parent.Tree),
222+
parent != default ? repository.GetTree(parent.Tree) : null,
218223
relativePath: string.Empty,
219224
filters);
220225
}
221226

222-
private static bool IsRelevantCommit(GitRepository repository, GitTree tree, GitTree parent, string relativePath, IReadOnlyList<FilterPath> filters)
227+
private static bool IsRelevantCommit(GitRepository repository, GitTree tree, GitTree? parent, string relativePath, IReadOnlyList<FilterPath> filters)
223228
{
224229
// Walk over all child nodes in the current tree. If a child node was found in the parent,
225230
// remove it, so that after the iteration the parent contains all nodes which have been
@@ -231,8 +236,9 @@ private static bool IsRelevantCommit(GitRepository repository, GitTree tree, Git
231236

232237
// If the entry is not present in the parent commit, it was added;
233238
// if the Sha does not match, it was modified.
234-
if (!parent.Children.TryGetValue(child.Key, out parentEntry)
235-
|| parentEntry.Sha != child.Value.Sha)
239+
if (parent is null ||
240+
!parent.Children.TryGetValue(child.Key, out parentEntry) ||
241+
parentEntry.Sha != child.Value.Sha)
236242
{
237243
// Determine whether the change was relevant.
238244
var fullPath = $"{relativePath}{entry.Name}";
@@ -264,23 +270,27 @@ private static bool IsRelevantCommit(GitRepository repository, GitTree tree, Git
264270

265271
if (parentEntry is not null)
266272
{
273+
Assumes.NotNull(parent);
267274
parent.Children.Remove(child.Key);
268275
}
269276
}
270277

271278
// Inspect removed entries (i.e. present in parent but not in the current tree)
272-
foreach (var child in parent.Children)
279+
if (parent is not null)
273280
{
274-
// Determine whether the change was relevant.
275-
var fullPath = Path.Combine(relativePath, child.Key);
281+
foreach (var child in parent.Children)
282+
{
283+
// Determine whether the change was relevant.
284+
var fullPath = Path.Combine(relativePath, child.Key);
276285

277-
bool isRelevant =
278-
filters.Any(f => f.Includes(fullPath, repository.IgnoreCase))
279-
&& !filters.Any(f => f.Excludes(fullPath, repository.IgnoreCase));
286+
bool isRelevant =
287+
filters.Any(f => f.Includes(fullPath, repository.IgnoreCase))
288+
&& !filters.Any(f => f.Excludes(fullPath, repository.IgnoreCase));
280289

281-
if (isRelevant)
282-
{
283-
return true;
290+
if (isRelevant)
291+
{
292+
return true;
293+
}
284294
}
285295
}
286296

0 commit comments

Comments
 (0)