Skip to content

Commit 681782b

Browse files
committed
refactor GitRepository to use GitRepositoryCache
Replaces caching logic within `GitRepository` with a new dedicated `GitRepositoryCache` class. Updates related classes and collections to utilize the cache through `GetOrWrap` methods, improving maintainability and reducing duplication.
1 parent 19b0e9f commit 681782b

File tree

12 files changed

+99
-87
lines changed

12 files changed

+99
-87
lines changed

src/GitVersion.LibGit2Sharp/Git/Branch.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@ internal sealed class Branch : IBranch
1010

1111
private readonly LibGit2Sharp.Branch innerBranch;
1212

13-
internal Branch(LibGit2Sharp.Branch branch, LibGit2Sharp.Diff diff, GitRepository repo)
13+
internal Branch(LibGit2Sharp.Branch branch, LibGit2Sharp.Diff diff, GitRepositoryCache repositoryCache)
1414
{
1515
diff.NotNull();
16-
repo.NotNull();
16+
repositoryCache.NotNull();
1717
this.innerBranch = branch.NotNull();
1818
Name = new(branch.CanonicalName);
1919

2020
var commit = this.innerBranch.Tip;
21-
Tip = commit is null ? null : repo.GetOrCreate(commit, diff);
21+
Tip = commit is null ? null : repositoryCache.GetOrWrap(commit, diff);
2222

2323
var commits = this.innerBranch.Commits;
24-
Commits = new CommitCollection(commits, diff, repo);
24+
Commits = new CommitCollection(commits, diff, repositoryCache);
2525
}
2626

2727
public ReferenceName Name { get; }

src/GitVersion.LibGit2Sharp/Git/BranchCollection.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,17 @@ internal sealed class BranchCollection : IBranchCollection
88
private readonly LibGit2Sharp.BranchCollection innerCollection;
99
private readonly Lazy<IReadOnlyCollection<IBranch>> branches;
1010
private readonly Diff diff;
11-
private readonly GitRepository repo;
11+
private readonly GitRepositoryCache repositoryCache;
1212

13-
internal BranchCollection(LibGit2Sharp.BranchCollection collection, Diff diff, GitRepository repo)
13+
internal BranchCollection(LibGit2Sharp.BranchCollection collection, Diff diff, GitRepositoryCache repositoryCache)
1414
{
1515
this.innerCollection = collection.NotNull();
16-
this.branches = new Lazy<IReadOnlyCollection<IBranch>>(() => [.. this.innerCollection.Select(branch => repo.GetOrCreate(branch, diff))]);
16+
this.branches = new Lazy<IReadOnlyCollection<IBranch>>(() => [.. this.innerCollection.Select(branch => repositoryCache.GetOrWrap(branch, diff))]);
1717
this.diff = diff.NotNull();
18-
this.repo = repo.NotNull();
18+
this.repositoryCache = repositoryCache.NotNull();
1919
}
2020

21-
public IEnumerator<IBranch> GetEnumerator()
22-
=> this.branches.Value.GetEnumerator();
21+
public IEnumerator<IBranch> GetEnumerator() => this.branches.Value.GetEnumerator();
2322

2423
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
2524

@@ -29,7 +28,7 @@ public IBranch? this[string name]
2928
{
3029
name = name.NotNull();
3130
var branch = this.innerCollection[name];
32-
return branch is null ? null : this.repo.GetOrCreate(branch, this.diff);
31+
return branch is null ? null : this.repositoryCache.GetOrWrap(branch, this.diff);
3332
}
3433
}
3534

src/GitVersion.LibGit2Sharp/Git/Commit.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ internal sealed class Commit : ICommit
1414
private readonly LibGit2Sharp.Commit innerCommit;
1515
private readonly LibGit2Sharp.Diff repoDiff;
1616

17-
internal Commit(LibGit2Sharp.Commit innerCommit, LibGit2Sharp.Diff repoDiff, GitRepository repo)
17+
internal Commit(LibGit2Sharp.Commit innerCommit, LibGit2Sharp.Diff repoDiff, GitRepositoryCache repositoryCache)
1818
{
1919
repoDiff.NotNull();
20-
repo.NotNull();
20+
repositoryCache.NotNull();
2121
this.innerCommit = innerCommit.NotNull();
22-
this.parentsLazy = new(() => innerCommit.Parents.Select(parent => repo.GetOrCreate(parent, repoDiff)).ToList());
22+
this.parentsLazy = new(() => [.. innerCommit.Parents.Select(parent => repositoryCache.GetOrWrap(parent, repoDiff))]);
2323
Id = new ObjectId(innerCommit.Id);
2424
Sha = innerCommit.Sha;
2525
When = innerCommit.Committer.When;

src/GitVersion.LibGit2Sharp/Git/CommitCollection.cs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,17 @@ internal sealed class CommitCollection : ICommitCollection
88
private readonly ICommitLog innerCollection;
99
private readonly Lazy<IReadOnlyCollection<ICommit>> commits;
1010
private readonly Diff diff;
11-
private readonly GitRepository repo;
11+
private readonly GitRepositoryCache repositoryCache;
1212

13-
internal CommitCollection(ICommitLog collection, Diff diff, GitRepository repo)
13+
internal CommitCollection(ICommitLog collection, Diff diff, GitRepositoryCache repositoryCache)
1414
{
1515
this.innerCollection = collection.NotNull();
16-
this.commits = new Lazy<IReadOnlyCollection<ICommit>>(() => [.. this.innerCollection.Select(commit => repo.GetOrCreate(commit, diff))]);
16+
this.commits = new Lazy<IReadOnlyCollection<ICommit>>(() => [.. this.innerCollection.Select(commit => repositoryCache.GetOrWrap(commit, diff))]);
1717
this.diff = diff.NotNull();
18-
this.repo = repo.NotNull();
18+
this.repositoryCache = repositoryCache.NotNull();
1919
}
2020

21-
public IEnumerator<ICommit> GetEnumerator()
22-
=> this.commits.Value.GetEnumerator();
21+
public IEnumerator<ICommit> GetEnumerator() => this.commits.Value.GetEnumerator();
2322

2423
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
2524

@@ -38,7 +37,7 @@ public IEnumerable<ICommit> QueryBy(CommitFilter commitFilter)
3837
SortBy = (LibGit2Sharp.CommitSortStrategies)commitFilter.SortBy
3938
};
4039
var commitLog = ((IQueryableCommitLog)this.innerCollection).QueryBy(filter);
41-
return new CommitCollection(commitLog, this.diff, this.repo);
40+
return new CommitCollection(commitLog, this.diff, this.repositoryCache);
4241

4342
static object? GetReacheableFrom(object? item) =>
4443
item switch

src/GitVersion.LibGit2Sharp/Git/GitRepository.cs

Lines changed: 16 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
using System.Collections.Concurrent;
21
using GitVersion.Extensions;
32
using GitVersion.Helpers;
43
using LibGit2Sharp;
@@ -8,13 +7,7 @@ namespace GitVersion.Git;
87
internal sealed partial class GitRepository
98
{
109
private Lazy<IRepository>? repositoryLazy;
11-
12-
private readonly ConcurrentDictionary<string, Branch> cachedBranches = new();
13-
private readonly ConcurrentDictionary<string, Commit> cachedCommits = new();
14-
private readonly ConcurrentDictionary<string, Tag> cachedTags = new();
15-
private readonly ConcurrentDictionary<string, Remote> cachedRemotes = new();
16-
private readonly ConcurrentDictionary<string, Reference> cachedReferences = new();
17-
private readonly ConcurrentDictionary<string, RefSpec> cachedRefSpecs = new();
10+
private readonly GitRepositoryCache repositoryCache = new();
1811

1912
private IRepository RepositoryInstance
2013
{
@@ -28,13 +21,21 @@ private IRepository RepositoryInstance
2821
public string WorkingDirectory => RepositoryInstance.Info.WorkingDirectory;
2922
public bool IsHeadDetached => RepositoryInstance.Info.IsHeadDetached;
3023
public bool IsShallow => RepositoryInstance.Info.IsShallow;
31-
public IBranch Head => GetOrCreate(RepositoryInstance.Head, RepositoryInstance.Diff);
24+
public IBranch Head => this.repositoryCache.GetOrWrap(RepositoryInstance.Head, RepositoryInstance.Diff);
25+
26+
private ITagCollection? tags;
27+
public ITagCollection Tags => this.tags ??= new TagCollection(RepositoryInstance.Tags, RepositoryInstance.Diff, this.repositoryCache);
28+
29+
public IBranchCollection Branches => new BranchCollection(RepositoryInstance.Branches, RepositoryInstance.Diff, this.repositoryCache);
30+
31+
private ICommitCollection? commits;
32+
public ICommitCollection Commits => this.commits ??= new CommitCollection(RepositoryInstance.Commits, RepositoryInstance.Diff, this.repositoryCache);
3233

33-
public ITagCollection Tags => new TagCollection(RepositoryInstance.Tags, RepositoryInstance.Diff, this);
34-
public IBranchCollection Branches => new BranchCollection(RepositoryInstance.Branches, RepositoryInstance.Diff, this);
35-
public ICommitCollection Commits => new CommitCollection(RepositoryInstance.Commits, RepositoryInstance.Diff, this);
36-
public IRemoteCollection Remotes => new RemoteCollection(RepositoryInstance.Network.Remotes, this);
37-
public IReferenceCollection References => new ReferenceCollection(RepositoryInstance.Refs, this);
34+
private IRemoteCollection? remotes;
35+
public IRemoteCollection Remotes => this.remotes ??= new RemoteCollection(RepositoryInstance.Network.Remotes, this.repositoryCache);
36+
37+
private IReferenceCollection? references;
38+
public IReferenceCollection References => this.references ??= new ReferenceCollection(RepositoryInstance.Refs, this.repositoryCache);
3839

3940
public void DiscoverRepository(string? gitDirectory)
4041
{
@@ -56,7 +57,7 @@ public void DiscoverRepository(string? gitDirectory)
5657
var first = (Commit)commit;
5758
var second = (Commit)otherCommit;
5859
var mergeBase = RepositoryInstance.ObjectDatabase.FindMergeBase(first, second);
59-
return mergeBase == null ? null : GetOrCreate(mergeBase, RepositoryInstance.Diff);
60+
return mergeBase == null ? null : this.repositoryCache.GetOrWrap(mergeBase, RepositoryInstance.Diff);
6061
});
6162
}
6263

@@ -66,29 +67,6 @@ public int UncommittedChangesCount()
6667
return retryAction.Execute(GetUncommittedChangesCountInternal);
6768
}
6869

69-
public Branch GetOrCreate(LibGit2Sharp.Branch innerBranch, Diff repoDiff)
70-
{
71-
var cacheKey = innerBranch.Tip is null
72-
? $"{innerBranch.RemoteName}/{innerBranch.CanonicalName}"
73-
: $"{innerBranch.RemoteName}/{innerBranch.CanonicalName}@{innerBranch.Tip.Sha}";
74-
return cachedBranches.GetOrAdd(cacheKey, _ => new Branch(innerBranch, repoDiff, this));
75-
}
76-
77-
public Commit GetOrCreate(LibGit2Sharp.Commit innerCommit, Diff repoDiff)
78-
=> cachedCommits.GetOrAdd(innerCommit.Sha, _ => new Commit(innerCommit, repoDiff, this));
79-
80-
public Tag GetOrCreate(LibGit2Sharp.Tag innerTag, Diff repoDiff)
81-
=> cachedTags.GetOrAdd(innerTag.CanonicalName, _ => new Tag(innerTag, repoDiff, this));
82-
83-
public Remote GetOrCreate(LibGit2Sharp.Remote innerRemote)
84-
=> cachedRemotes.GetOrAdd(innerRemote.Name, _ => new Remote(innerRemote, this));
85-
86-
public Reference GetOrCreate(LibGit2Sharp.Reference innerReference)
87-
=> cachedReferences.GetOrAdd(innerReference.CanonicalName, _ => new Reference(innerReference));
88-
89-
public RefSpec GetOrCreate(LibGit2Sharp.RefSpec innerRefSpec)
90-
=> cachedRefSpecs.GetOrAdd(innerRefSpec.Specification, _ => new RefSpec(innerRefSpec));
91-
9270
public void Dispose()
9371
{
9472
if (this.repositoryLazy is { IsValueCreated: true }) RepositoryInstance.Dispose();
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using System.Collections.Concurrent;
2+
using LibGit2Sharp;
3+
4+
namespace GitVersion.Git;
5+
6+
internal class GitRepositoryCache
7+
{
8+
private readonly ConcurrentDictionary<string, Branch> cachedBranches = new();
9+
private readonly ConcurrentDictionary<string, Commit> cachedCommits = new();
10+
private readonly ConcurrentDictionary<string, Tag> cachedTags = new();
11+
private readonly ConcurrentDictionary<string, Remote> cachedRemotes = new();
12+
private readonly ConcurrentDictionary<string, Reference> cachedReferences = new();
13+
private readonly ConcurrentDictionary<string, RefSpec> cachedRefSpecs = new();
14+
15+
public Branch GetOrWrap(LibGit2Sharp.Branch innerBranch, Diff repoDiff)
16+
{
17+
var cacheKey = innerBranch.Tip is null
18+
? $"{innerBranch.RemoteName}/{innerBranch.CanonicalName}"
19+
: $"{innerBranch.RemoteName}/{innerBranch.CanonicalName}@{innerBranch.Tip.Sha}";
20+
return cachedBranches.GetOrAdd(cacheKey, _ => new Branch(innerBranch, repoDiff, this));
21+
}
22+
23+
public Commit GetOrWrap(LibGit2Sharp.Commit innerCommit, Diff repoDiff)
24+
=> cachedCommits.GetOrAdd(innerCommit.Sha, _ => new Commit(innerCommit, repoDiff, this));
25+
26+
public Tag GetOrWrap(LibGit2Sharp.Tag innerTag, Diff repoDiff)
27+
=> cachedTags.GetOrAdd(innerTag.CanonicalName, _ => new Tag(innerTag, repoDiff, this));
28+
29+
public Remote GetOrWrap(LibGit2Sharp.Remote innerRemote)
30+
=> cachedRemotes.GetOrAdd(innerRemote.Name, _ => new Remote(innerRemote, this));
31+
32+
public Reference GetOrWrap(LibGit2Sharp.Reference innerReference)
33+
=> cachedReferences.GetOrAdd(innerReference.CanonicalName, _ => new Reference(innerReference));
34+
35+
public RefSpec GetOrWrap(LibGit2Sharp.RefSpec innerRefSpec)
36+
=> cachedRefSpecs.GetOrAdd(innerRefSpec.Specification, _ => new RefSpec(innerRefSpec));
37+
}

src/GitVersion.LibGit2Sharp/Git/RefSpecCollection.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ internal sealed class RefSpecCollection : IRefSpecCollection
66
{
77
private readonly Lazy<IReadOnlyCollection<IRefSpec>> refSpecs;
88

9-
internal RefSpecCollection(LibGit2Sharp.RefSpecCollection innerCollection, GitRepository repo)
9+
internal RefSpecCollection(LibGit2Sharp.RefSpecCollection innerCollection, GitRepositoryCache repositoryCache)
1010
{
1111
innerCollection = innerCollection.NotNull();
12-
this.refSpecs = new Lazy<IReadOnlyCollection<IRefSpec>>(() => [.. innerCollection.Select(repo.GetOrCreate)]);
12+
this.refSpecs = new Lazy<IReadOnlyCollection<IRefSpec>>(() => [.. innerCollection.Select(repositoryCache.GetOrWrap)]);
1313
}
1414

1515
public IEnumerator<IRefSpec> GetEnumerator() => this.refSpecs.Value.GetEnumerator();

src/GitVersion.LibGit2Sharp/Git/ReferenceCollection.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ namespace GitVersion.Git;
55
internal sealed class ReferenceCollection : IReferenceCollection
66
{
77
private readonly LibGit2Sharp.ReferenceCollection innerCollection;
8-
private readonly GitRepository repo;
8+
private readonly GitRepositoryCache repositoryCache;
99
private Lazy<IReadOnlyCollection<IReference>> references = null!;
1010

11-
internal ReferenceCollection(LibGit2Sharp.ReferenceCollection collection, GitRepository repo)
11+
internal ReferenceCollection(LibGit2Sharp.ReferenceCollection collection, GitRepositoryCache repositoryCache)
1212
{
1313
this.innerCollection = collection.NotNull();
14-
this.repo = repo.NotNull();
14+
this.repositoryCache = repositoryCache.NotNull();
1515
InitializeReferencesLazy();
1616
}
1717

@@ -24,7 +24,7 @@ public IReference? this[string name]
2424
get
2525
{
2626
var reference = this.innerCollection[name];
27-
return reference is null ? null : this.repo.GetOrCreate(reference);
27+
return reference is null ? null : this.repositoryCache.GetOrWrap(reference);
2828
}
2929
}
3030

@@ -33,7 +33,7 @@ public IReference? this[string name]
3333
public IReference? Head => this["HEAD"];
3434

3535
public IEnumerable<IReference> FromGlob(string prefix)
36-
=> this.innerCollection.FromGlob(prefix).Select(reference => this.repo.GetOrCreate(reference));
36+
=> this.innerCollection.FromGlob(prefix).Select(reference => this.repositoryCache.GetOrWrap(reference));
3737

3838
public void Add(string name, string canonicalRefNameOrObject, bool allowOverwrite = false) =>
3939
RepositoryExtensions.RunSafe(() =>
@@ -50,5 +50,5 @@ public void UpdateTarget(IReference directRef, IObjectId targetId) =>
5050
});
5151

5252
private void InitializeReferencesLazy()
53-
=> this.references = new Lazy<IReadOnlyCollection<IReference>>(() => [.. this.innerCollection.Select(repo.GetOrCreate)]);
53+
=> this.references = new Lazy<IReadOnlyCollection<IReference>>(() => [.. this.innerCollection.Select(repositoryCache.GetOrWrap)]);
5454
}

src/GitVersion.LibGit2Sharp/Git/Remote.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ internal sealed class Remote : IRemote
99
private static readonly LambdaKeyComparer<IRemote, string> comparerHelper = new(x => x.Name);
1010

1111
private readonly LibGit2Sharp.Remote innerRemote;
12-
private readonly GitRepository repo;
12+
private readonly GitRepositoryCache repositoryCache;
1313

14-
internal Remote(LibGit2Sharp.Remote remote, GitRepository repo)
14+
internal Remote(LibGit2Sharp.Remote remote, GitRepositoryCache repositoryCache)
1515
{
1616
this.innerRemote = remote.NotNull();
17-
this.repo = repo.NotNull();
17+
this.repositoryCache = repositoryCache.NotNull();
1818
}
1919

2020
public int CompareTo(IRemote? other) => comparerHelper.Compare(this, other);
@@ -29,7 +29,7 @@ private IEnumerable<IRefSpec> RefSpecs
2929
var refSpecs = this.innerRemote.RefSpecs;
3030
return refSpecs is null
3131
? []
32-
: new RefSpecCollection((LibGit2Sharp.RefSpecCollection)refSpecs, repo);
32+
: new RefSpecCollection((LibGit2Sharp.RefSpecCollection)refSpecs, this.repositoryCache);
3333
}
3434
}
3535

src/GitVersion.LibGit2Sharp/Git/RemoteCollection.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@ namespace GitVersion.Git;
55
internal sealed class RemoteCollection : IRemoteCollection
66
{
77
private readonly LibGit2Sharp.RemoteCollection innerCollection;
8-
private readonly GitRepository repo;
8+
private readonly GitRepositoryCache repositoryCache;
99
private Lazy<IReadOnlyCollection<IRemote>> remotes = null!;
1010

11-
internal RemoteCollection(LibGit2Sharp.RemoteCollection collection, GitRepository repo)
11+
internal RemoteCollection(LibGit2Sharp.RemoteCollection collection, GitRepositoryCache repositoryCache)
1212
{
1313
this.innerCollection = collection.NotNull();
14-
this.repo = repo.NotNull();
14+
this.repositoryCache = repositoryCache.NotNull();
1515
InitializeRemotesLazy();
1616
}
1717

@@ -24,7 +24,7 @@ public IRemote? this[string name]
2424
get
2525
{
2626
var remote = this.innerCollection[name];
27-
return remote is null ? null : this.repo.GetOrCreate(remote);
27+
return remote is null ? null : this.repositoryCache.GetOrWrap(remote);
2828
}
2929
}
3030

@@ -43,5 +43,5 @@ public void Update(string remoteName, string refSpec) =>
4343
});
4444

4545
private void InitializeRemotesLazy()
46-
=> this.remotes = new Lazy<IReadOnlyCollection<IRemote>>(() => [.. this.innerCollection.Select(repo.GetOrCreate)]);
46+
=> this.remotes = new Lazy<IReadOnlyCollection<IRemote>>(() => [.. this.innerCollection.Select(repositoryCache.GetOrWrap)]);
4747
}

0 commit comments

Comments
 (0)