Exemplo n.º 1
0
        private static void AddEmptyBranchesVirtualTipCommits(MRepository repository)
        {
            IEnumerable <MBranch> emptyBranches = repository.Branches.Values
                                                  .Where(b => !b.Commits.Any() && !b.IsLocalPart);

            foreach (MBranch branch in emptyBranches)
            {
                string virtualShaText = (Guid.NewGuid() + Guid.NewGuid().ToString()).Replace("-", "")
                                        .Substring(0, 40);
                CommitSha virtualSha = new CommitSha(virtualShaText);
                CommitId  virtualId  = new CommitId(virtualShaText);

                MCommit commit = AddVirtualCommit(repository, virtualId);


                commit.IsVirtual = true;
                commit.BranchId  = branch.Id;
                commit.SetBranchName(branch.Name);
                CopyToVirtualCommit(repository, branch, commit, virtualSha);
                SetChildOfParents(commit);

                //repository.Commits[commit.Id] = commit;

                branch.CommitIds.Add(commit.Id);
                branch.TipCommitId   = commit.Id;
                branch.FirstCommitId = commit.Id;

                branch.TipCommit.BranchTips = $"{branch.Name} branch tip";
            }
        }
        /// <summary>
        /// Builds a <see cref="FilterDefinition{BsonDocument}" /> corresponding to the <see cref="CommitId" /> supplied
        /// </summary>
        /// <param name="commit">A <see cref="CommitId" /></param>
        /// <returns>A <see cref="FilterDefinition{BsonDocument}" /> corresponding to the <see cref="CommitId" /></returns>
        public static FilterDefinition <BsonDocument> ToFilter(this CommitId commit)
        {
            var builder = Builders <BsonDocument> .Filter;
            var filter  = builder.Eq(CommitConstants.COMMIT_ID, commit.Value);

            return(filter);
        }
Exemplo n.º 3
0
        private static void SetMasterBranchCommits(MRepository repository, MSubBranch subBranch)
        {
            CommitId commitId = subBranch.TipCommitId;

            while (commitId != CommitId.None)
            {
                MCommit commit = repository.Commits[commitId];

                if (commit.BranchName == subBranch.Name && commit.SubBranchId != null)
                {
                    // Do not break if commit is the tip
                    if (!(commit.Id == subBranch.TipCommitId && commit.SubBranchId == subBranch.SubBranchId))
                    {
                        break;
                    }
                }

                if (commit.HasBranchName && commit.BranchName != subBranch.Name)
                {
                    Log.Warn($"commit {commit} already has branch {commit.BranchName} != {subBranch.Name}");
                    break;
                }

                commit.SetBranchName(subBranch.Name);
                commit.SubBranchId = subBranch.SubBranchId;
                commitId           = commit.FirstParentId;
            }
        }
Exemplo n.º 4
0
        public static void CommitId_equality()
        {
            var commitId1 = new CommitId(Sha1.Hash("abc"));
            var commitId2 = new CommitId(Sha1.Hash("abc"));
            var commitId3 = new CommitId(Sha1.Hash("def"));

            Assert.True(commitId1 == commitId2);
            Assert.False(commitId1 != commitId2);
            Assert.True(commitId1.Equals((object)commitId2));

            Assert.Equal(commitId1.Sha1.ToString(), commitId1.ToString());
            Assert.Equal(commitId2.Sha1.ToString(), commitId2.ToString());
            Assert.Equal(commitId3.Sha1.ToString(), commitId3.ToString());

            Assert.Equal(commitId1, commitId2);
            Assert.Equal(commitId1.GetHashCode(), commitId2.GetHashCode());
            Assert.Equal(commitId1.ToString(), commitId2.ToString());

            Assert.NotEqual(CommitId.Empty, commitId1);
            Assert.NotEqual(CommitId.Empty.GetHashCode(), commitId1.GetHashCode());
            Assert.NotEqual(CommitId.Empty.ToString(), commitId1.ToString());

            Assert.NotEqual(commitId3, commitId1);
            Assert.NotEqual(commitId3.GetHashCode(), commitId1.GetHashCode());
            Assert.NotEqual(commitId3.ToString(), commitId1.ToString());
        }
Exemplo n.º 5
0
        public override string ToString(BotElement bot, Func <string, string> transform)
        {
            string formattedTime = String.IsNullOrEmpty(bot.Text.DateTimeFormat) ? AuthorTime.ToString() : AuthorTime.ToString(bot.Text.DateTimeFormat);
            var    sb            = new StringBuilder();

            if (RefNames != null)
            {
                sb.AppendFormat("{0} ", transform(String.Concat(RefNames)));
            }

            sb.Append(bot.Text.CommitFormat.FormatWith(new
            {
                Action       = Type == CommitRowType.Commit ? bot.Text.Commit : bot.Text.RefPointer,
                CommitUri    = CommitUri,
                CommitId     = transform(CommitId.ToHexString(settings.HashLength)),
                ChangeCounts = (ChangeCounts != null) ? String.Join(", ", ChangeCounts.Select(c => ChangeCountToString(bot, c))) : "",
                AuthorTime   = formattedTime,
                Author       = transform(Author),
                AuthorName   = transform(AuthorName),
                AuthorEmail  = transform(AuthorEmail),
                Comment      = transform(Comment.Truncate(settings.CommentMaxLength))
            }));

            return(sb.ToString());
        }
Exemplo n.º 6
0
        public virtual async ValueTask <Commit?> ReadCommitAsync(CommitId commitId, CancellationToken cancellationToken)
        {
            var buffer = await ReadObjectAsync(commitId.Sha1, cancellationToken).ConfigureAwait(false);

            if (buffer == null)
            {
                return(default);
Exemplo n.º 7
0
        private async Task Commit()
        {
            var headers = new Dictionary <string, string>
            {
                [$"{Defaults.PrefixHeader}.{Defaults.CommitIdHeader}"] = CommitId.ToString(),
                [$"{Defaults.PrefixHeader}.Instance"] = Defaults.Instance.ToString()
                                                        // Todo: what else can we put in here?
            };

            var allRepos =
                _repositories.Values.Cast <IRepositoryCommit>().ToArray();

            var changedStreams = allRepos.Sum(x => x.ChangedStreams);

            Logger.DebugEvent("Changed", "{Changed} streams {CommitId}", changedStreams, CommitId);
            // Only prepare if multiple changed streams, which will quickly check all changed streams to see if they are all the same version as when we read them
            // Not 100% guarenteed to eliminate writing 1 stream then failing the other one but will help - and we also tell the user to not do this..
            if (changedStreams > 1)
            {
                Logger.WarnEvent("BestPractices", "{Changed} changed streams. We highly discourage this https://github.com/volak/Aggregates.NET/wiki/Changing-Multiple-Streams", changedStreams, CommitId);
                // First check all streams read but not modified - if the store has a different version a VersionException will be thrown
                await allRepos.WhenAllAsync(x => x.Prepare(CommitId)).ConfigureAwait(false);
            }

            Logger.DebugEvent("Commit", "{CommitId} for {Repositories} repositories", CommitId, allRepos.Length);
            try
            {
                await allRepos.WhenAllAsync(x => x.Commit(CommitId, headers)).ConfigureAwait(false);
            }
            finally
            {
                Guid eventId;
                EventIds.TryRemove(CommitId, out eventId);
            }
        }
Exemplo n.º 8
0
        private string TryGetCommitId(string id)
        {
            if (CommitId.TryParse(id, out CommitId commitId))
            {
                return(id);
            }
            else
            {
                var gitCommits = repositoryMgr.Value.Repository?.MRepository?.GitCommits;
                if (gitCommits == null)
                {
                    return(id);
                }

                var commits = gitCommits.ToList();
                foreach (var pair in commits)
                {
                    if (pair.Value.Sha.Sha.StartsWithOic(id))
                    {
                        commitId = new CommitId(pair.Value.Sha);
                        return(commitId.Id);
                    }
                }
            }

            return(id);
        }
 /// <summary>
 ///
 /// </summary>
 /// <param name="sequence"></param>
 /// <param name="source"></param>
 /// <param name="id"></param>
 /// <param name="timestamp"></param>
 /// <param name="correlationId"></param>
 public CommitMetadata(CommitSequenceNumber sequence, VersionedEventSource source, CommitId id, DateTimeOffset timestamp, CorrelationId correlationId)
 {
     Sequence      = sequence;
     Source        = source;
     Id            = id;
     Timestamp     = timestamp;
     CorrelationId = correlationId;
 }
Exemplo n.º 10
0
        public static JsonObject Convert(this CommitId model)
        {
            var wire = new JsonObject
            {
                [_id] = model.Sha1.ToString("N")
            };

            return(wire);
        }
Exemplo n.º 11
0
        public static CommitId ConvertCommitId(this string wire)
        {
            if (string.IsNullOrWhiteSpace(wire)) return default;

            var sha1 = Sha1.Parse(wire);

            var model = new CommitId(sha1);
            return model;
        }
        private void UpdateMerges(
            IEnumerable <Branch> sourceBranches,
            RepositoryViewModel repositoryViewModel)
        {
            var branches    = repositoryViewModel.Branches;
            var commits     = repositoryViewModel.Commits;
            var commitsById = repositoryViewModel.CommitsById;
            var merges      = repositoryViewModel.Merges;

            var mergePoints = commits
                              .Where(c => c.IsMergePoint && c.Commit.HasSecondParent && sourceBranches.Contains(c.Commit.SecondParent.Branch))
                              .ToList();

            var branchStarts = branches.Where(b =>
                                              b.Branch.HasParentBranch && sourceBranches.Contains(b.Branch.ParentCommit.Branch))
                               .Select(b => b.Branch.FirstCommit)
                               .ToList();

            bool isMergeInProgress =
                repositoryMgr.Repository.Status.IsMerging &&
                branches.Any(b => b.Branch == repositoryMgr.Repository.CurrentBranch) &&
                repositoryViewModel.MergingBranch != null &&
                branches.Any(b => b.Branch.Id == repositoryViewModel.MergingBranch.Id) &&
                repositoryMgr.Repository.UnComitted != null;

            int mergeCount = mergePoints.Count + branchStarts.Count + (isMergeInProgress ? 1 : 0);

            SetNumberOfItems(merges, mergeCount, _ => new MergeViewModel());

            int index = 0;

            foreach (CommitViewModel childCommit in mergePoints)
            {
                CommitViewModel parentCommit = commitsById[childCommit.Commit.SecondParent.Id];

                MergeViewModel merge = merges[index++];

                SetMerge(merge, branches, childCommit, parentCommit);
            }

            foreach (Commit childCommit in branchStarts)
            {
                CommitViewModel parentCommit = commitsById[childCommit.FirstParent.Id];

                MergeViewModel merge = merges[index++];

                SetMerge(merge, branches, commitsById[childCommit.Id], parentCommit, false);
            }

            if (isMergeInProgress)
            {
                CommitId        mergeSourceId = new CommitId(repositoryViewModel.MergingCommitSha);
                CommitViewModel parentCommit  = commitsById[mergeSourceId];
                MergeViewModel  merge         = merges[index++];
                SetMerge(merge, branches, commitsById[parentCommit.Commit.Repository.UnComitted.Id], parentCommit);
            }
        }
        static UncommittedEventStream BuildStreamFrom(EventStream stream)
        {
            var now                  = DateTimeOffset.UtcNow;
            var lastEvent            = stream.Last();
            var versionedEventSource = lastEvent.Metadata.VersionedEventSource;
            var correlationId        = lastEvent.Metadata.CorrelationId;

            return(new UncommittedEventStream(CommitId.New(), correlationId, versionedEventSource, now, stream));
        }
Exemplo n.º 14
0
        public static CommitIdWire Convert(this CommitId model)
        {
            var wire = new CommitIdWire
            {
                Id = model.Sha1.Convert()
            };

            return(wire);
        }
Exemplo n.º 15
0
        void ThrowIfDuplicate(CommitId commitId)
        {
            if (!_duplicates.Contains(commitId))
            {
                return;
            }

            throw new CommitIsADuplicate();
        }
Exemplo n.º 16
0
        private async Task Commit()
        {
            Guid eventId;

            EventIds.TryRemove(CommitId, out eventId);
            var headers = new Dictionary <string, string>
            {
                [CommitHeader]             = CommitId.ToString(),
                [TerminatingEventIdHeader] = eventId.ToString()
                                             // Todo: what else can we put in here?
            };

            var allRepos =
                _repositories.Values.Concat(_entityRepositories.Values).Concat(_pocoRepositories.Values).ToArray();


            var changedStreams = _repositories.Sum(x => x.Value.ChangedStreams) + _entityRepositories.Sum(x => x.Value.ChangedStreams);

            Logger.Write(LogLevel.Debug, () => $"Detected {changedStreams} changed streams in commit {CommitId}");
            if (changedStreams > 1)
            {
                Logger.Write(LogLevel.Info, () =>
                             $"Starting prepare for commit id {CommitId} with {_repositories.Count + _entityRepositories.Count + _pocoRepositories.Count} tracked repositories");
                using (PrepareTime.NewContext())
                {
                    // First check all streams read but not modified - if the store has a different version a VersionException will be thrown
                    await allRepos.SelectAsync(x => x.Prepare(CommitId)).ConfigureAwait(false);
                }
            }

            // this log message can be expensive as the list is computed for a check
            // so only warn users about multiple stream commits when debugging
            Logger.Write(LogLevel.Debug, () =>
            {
                var orderedRepos = _repositories.Select(x => new Tuple <int, IRepository>(x.Value.ChangedStreams, x.Value))
                                   .Concat(_entityRepositories.Select(x => new Tuple <int, IRepository>(x.Value.ChangedStreams, x.Value)));
                if (orderedRepos.Count(x => x.Item1 != 0) > 1)
                {
                    return($"Starting commit id {CommitId} with {_repositories.Count + _entityRepositories.Count + _pocoRepositories.Count} tracked repositories. You changed {orderedRepos.Sum(x => x.Item1)} streams.  We highly discourage this https://github.com/volak/Aggregates.NET/wiki/Changing-Multiple-Streams");
                }

                return($"Starting commit id {CommitId} with {_repositories.Count + _entityRepositories.Count + _pocoRepositories.Count} tracked repositories");
            });


            using (var ctx = CommitTime.NewContext())
            {
                await allRepos.SelectAsync(x => x.Commit(CommitId, headers)).ConfigureAwait(false);

                if (ctx.Elapsed > TimeSpan.FromSeconds(1))
                {
                    SlowLogger.Write(LogLevel.Warn, () => $"Commit id {CommitId} took {ctx.Elapsed.TotalSeconds} seconds!");
                }
                Logger.Write(LogLevel.Info, () => $"Commit id {CommitId} took {ctx.Elapsed.TotalMilliseconds} ms");
            }
        }
Exemplo n.º 17
0
        public static void ChasmSerializer_Roundtrip_CommitId(IChasmSerializer ser)
        {
            var expected = new CommitId(Sha1.Hash("abc"));

            using (var buf = ser.Serialize(expected))
            {
                var actual = ser.DeserializeCommitId(buf.Result);
                Assert.Equal(expected, actual);
            }
        }
Exemplo n.º 18
0
        public MCommit Commit(CommitId commitId)
        {
            MCommit commit;

            if (!Commits.TryGetValue(commitId, out commit))
            {
                commit = AddNewCommit(commitId);
            }

            return(commit);
        }
Exemplo n.º 19
0
        private MCommit AddNewCommit(CommitId commitId)
        {
            MCommit commit = new MCommit()
            {
                Repository = this,
                Id         = commitId,
            };

            Commits[commitId] = commit;

            return(commit);
        }
Exemplo n.º 20
0
 private void SetNoteBranches(
     string nameSpace, CommitSha commitSha, BranchName branchName)
 {
     try
     {
         string   file = Path.Combine(workingFolder, ".git", nameSpace);
         CommitId id   = new CommitId(commitSha);
         File.AppendAllText(file, $"{id} {branchName}\n");
     }
     catch (Exception e)
     {
         Log.Exception(e, $"Failed to add commit name for {commitSha} {branchName}");
     }
 }
Exemplo n.º 21
0
        private async Task Commit()
        {
            var headers = new Dictionary <string, string>
            {
                [CommitHeader] = CommitId.ToString(),
                // Todo: what else can we put in here?
            };

            var allRepos =
                _repositories.Values.Concat(_pocoRepositories.Values).ToArray();


            var changedStreams = _repositories.Sum(x => x.Value.ChangedStreams) + _pocoRepositories.Sum(x => x.Value.ChangedStreams);

            Logger.Write(LogLevel.Debug, () => $"Detected {changedStreams} changed streams in commit {CommitId}");
            // Only prepare if multiple changed streams, which will quickly check all changed streams to see if they are all the same version as when we read them
            // Not 100% guarenteed to eliminate writing 1 stream then failing the other one but will help - and we also tell the user to not do this..
            if (changedStreams > 1)
            {
                Logger.Write(LogLevel.Warn, $"Starting prepare for commit id {CommitId} with {_repositories.Count + _pocoRepositories.Count} tracked repositories. You changed {changedStreams} streams.  We highly discourage this https://github.com/volak/Aggregates.NET/wiki/Changing-Multiple-Streams");

                using (PrepareTime.NewContext())
                {
                    // First check all streams read but not modified - if the store has a different version a VersionException will be thrown
                    await allRepos.WhenAllAsync(x => x.Prepare(CommitId)).ConfigureAwait(false);
                }
            }

            Logger.Write(LogLevel.Debug, () => $"Starting commit id {CommitId} with {_repositories.Count + _pocoRepositories.Count} tracked repositories");

            try
            {
                using (var ctx = CommitTime.NewContext())
                {
                    await allRepos.WhenAllAsync(x => x.Commit(CommitId, headers)).ConfigureAwait(false);

                    if (ctx.Elapsed > TimeSpan.FromSeconds(1))
                    {
                        SlowLogger.Write(LogLevel.Warn,
                                         () => $"Commit id {CommitId} took {ctx.Elapsed.TotalSeconds} seconds!");
                    }
                    Logger.Write(LogLevel.Debug, () => $"Commit id {CommitId} took {ctx.Elapsed.TotalMilliseconds} ms");
                }
            }
            finally
            {
                Guid eventId;
                EventIds.TryRemove(CommitId, out eventId);
            }
        }
Exemplo n.º 22
0
        public BufferSession Serialize(CommitId model)
        {
            var json = model.Write();

            var maxLen = Encoding.UTF8.GetMaxByteCount(json.Length); // Utf8 is 1-4 bpc
            var rented = BufferSession.RentBuffer(maxLen);

            var count = Encoding.UTF8.GetBytes(json, 0, json.Length, rented, 0);

            var seg     = new ArraySegment <byte>(rented, 0, count);
            var session = new BufferSession(seg);

            return(session);
        }
Exemplo n.º 23
0
        private static MCommit AddVirtualCommit(
            MRepository repository,
            CommitId virtualId)
        {
            MCommit commit = new MCommit()
            {
                Repository = repository,
                Id         = virtualId,
            };

            repository.Commits[virtualId] = commit;

            return(commit);
        }
Exemplo n.º 24
0
        private void AddVirtualEmptyCommit(MRepository repository)
        {
            CommitSha virtualSha = CommitSha.NoCommits;
            CommitId  virtualId  = new CommitId(virtualSha);

            GitCommit gitCommit = new GitCommit(
                virtualSha,
                "<Repository with no commits yet ...>",
                "<Repository with no commits yet ...>",
                "",
                DateTime.Now,
                DateTime.Now,
                new List <CommitId>());

            repository.GitCommits[virtualId] = gitCommit;
        }
        public BufferSession Serialize(CommitId model)
        {
            var wire = model.Convert();

            var size   = wire.CalculateSize();
            var buffer = BufferSession.RentBuffer(size);

            using (var cos = new CodedOutputStream(buffer))
            {
                wire.WriteTo(cos);

                var segment = new ArraySegment <byte>(buffer, 0, (int)cos.Position);

                var session = new BufferSession(buffer, segment);
                return(session);
            }
        }
Exemplo n.º 26
0
        public static void CommitId_Compare()
        {
            var comparer = CommitIdComparer.Default;

            var commitId1 = new CommitId(Sha1.Hash("abc"));
            var commitId2 = new CommitId(Sha1.Hash("abc"));
            var commitId3 = new CommitId(Sha1.Hash("def"));
            var list      = new[] { commitId1, commitId2, commitId3 };

            Assert.True(commitId1.CompareTo(commitId2) == 0);
            Assert.True(commitId1.CompareTo(commitId3) != 0);

            Array.Sort(list, comparer.Compare);

            Assert.True(list[0] <= list[1]);
            Assert.True(list[2] >= list[1]);
        }
Exemplo n.º 27
0
        private static void TrySetBranchNameFromSubject(
            CommitId commitId,
            GitCommit gitCommit,
            IDictionary <CommitId, BranchName> branchNameByCommitId,
            IDictionary <CommitId, BranchName> subjectBranchNameByCommitId)
        {
            // Trying to parse source and target branch names from subject. They can be like
            // "Merge branch 'branch-name' of remote-repository-path"
            // This is considered a "pull merge", where branch-name is both source and target. These are
            // usually automatically created by tools and thus more trustworthy.
            // Other merge merge subjects are less trustworthy since they sometiems are manually edited
            // like:
            // "Merge source-branch"
            // which contains a source branch name, but sometimes they contain a target like
            // "Merge source-branch into target-branch"
            MergeBranchNames mergeNames = BranchNameParser.ParseBranchNamesFromSubject(gitCommit.Subject);

            if (IsPullMergeCommit(mergeNames))
            {
                // Pull merge subjects (source branch same as target) (trust worthy, so use branch name
                branchNameByCommitId[commitId] = mergeNames.SourceBranchName;
                branchNameByCommitId[gitCommit.ParentIds[0]] = mergeNames.SourceBranchName;
                branchNameByCommitId[gitCommit.ParentIds[1]] = mergeNames.SourceBranchName;

                // But also note the barnch name from subjects
                subjectBranchNameByCommitId[commitId] = mergeNames.SourceBranchName;
                subjectBranchNameByCommitId[gitCommit.ParentIds[0]] = mergeNames.SourceBranchName;
                subjectBranchNameByCommitId[gitCommit.ParentIds[1]] = mergeNames.SourceBranchName;
            }
            else
            {
                // Normal merge subject (less trustworthy)
                if (mergeNames.TargetBranchName != null)
                {
                    // There was a target branch name
                    subjectBranchNameByCommitId[commitId] = mergeNames.TargetBranchName;
                }

                if (mergeNames.SourceBranchName != null)
                {
                    // There was a source branch name
                    subjectBranchNameByCommitId[gitCommit.ParentIds[1]] = mergeNames.SourceBranchName;
                }
            }
        }
 private void SetDetails()
 {
     if (CommitViewModel != null)
     {
         if (filesCommitId != CommitViewModel.Commit.RealCommitId ||
             filesCommitId == GitModel.CommitId.Uncommitted)
         {
             files.Clear();
             filesCommitId = CommitViewModel.Commit.RealCommitId;
             SetFilesAsync(commitViewModel.Commit).RunInBackground();
         }
     }
     else
     {
         files.Clear();
         filesCommitId = null;
     }
 }
        private Repository ToRepository(MRepository mRepository)
        {
            Timing t = new Timing();
            KeyedList <string, Branch>    rBranches = new KeyedList <string, Branch>(b => b.Id);
            Dictionary <CommitId, Commit> rCommits  = new Dictionary <CommitId, Commit>();
            Branch   currentBranch = null;
            Commit   currentCommit = null;
            CommitId rootCommitId  = mRepository.RootCommitId;

            Repository repository = new Repository(
                mRepository,
                new Lazy <IReadOnlyKeyedList <string, Branch> >(() => rBranches),
                new Lazy <IReadOnlyDictionary <CommitId, Commit> >(() => rCommits),
                new Lazy <Branch>(() => currentBranch),
                new Lazy <Commit>(() => currentCommit),
                commitsDetailsService,
                mRepository.Status,
                rootCommitId,
                mRepository.Uncommitted?.Id ?? CommitId.None);

            foreach (var mCommit in mRepository.Commits.Values)
            {
                Commit commit = Converter.ToCommit(repository, mCommit);
                rCommits[commit.Id] = commit;
                if (mCommit == mRepository.CurrentCommit)
                {
                    currentCommit = commit;
                }
            }

            foreach (var mBranch in mRepository.Branches)
            {
                Branch branch = Converter.ToBranch(repository, mBranch.Value);
                rBranches.Add(branch);

                if (mBranch.Value == mRepository.CurrentBranch)
                {
                    currentBranch = branch;
                }
            }

            t.Log($"Created repository {repository.Commits.Count} commits");
            return(repository);
        }
Exemplo n.º 30
0
        public async Task AddNewCommitsAsync(MRepository repository)
        {
            int addedCount = 0;
            CancellationTokenSource cts = new CancellationTokenSource();
            int seenCount = 0;

            void OnCommit(GitCommit commit)
            {
                CommitId commitId = new CommitId(commit.Sha);

                if (repository.GitCommits.TryGetValue(commitId, out _))
                {
                    if (commit.ParentIds.All(p => repository.GitCommits.TryGetValue(commitId, out _)))
                    {
                        seenCount++;
                        if (seenCount > 5000)
                        {
                            Log.Debug($"Commit {commitId} already cached");
                            cts.Cancel();
                        }
                    }
                    else
                    {
                        seenCount = 0;
                    }
                }
                else
                {
                    seenCount = 0;
                    repository.GitCommits[commitId] = commit;
                    addedCount++;
                }
            }

            R result = await gitLogService.GetLogAsync(OnCommit, cts.Token);

            if (result.IsFaulted)
            {
                Log.Warn($"Failed to add new commits, {result}");
            }

            Log.Debug($"Added {addedCount} to cache");
        }