private async RecursiveCallResult <Commit?> ReferenceOrCopyCommitImpl(
            Repository sourceRepo,
            Commit commit,
            Repository targetRepo,
            int maxDepth)
        {
            if (maxDepth == 0)
            {
                return(null);
            }
            // fastest way: use copied commit
            if (TryGetCopiedCommit(commit, targetRepo, out var newCommit))
            {
                return(newCommit);
            }

            switch (_callback.GetCommitCopyKind(commit))
            {
            case CommitCopyKind.NoCommit:
            {
                // if source tree not found: this commit will be parent of top commit.
                newCommit = null;
            }
            break;

            case CommitCopyKind.UseParent:
            {
                // if maxDepth == 1 means deepest commit: parent never exists so force copy commit
                if (maxDepth == 1)
                {
                    goto case CommitCopyKind.CopyCommit;
                }

                // if no difference: this commit is same as parent's commit
                _progressHandler?.OnFoundNewCommit(1);
                newCommit = await ReferenceOrCopyCommit(sourceRepo, commit.Parents.First(), targetRepo,
                                                        NextDepth(maxDepth));
            }
            break;

            case CommitCopyKind.CopyCommit:
            {
                // otherwise: copies commit

                // Count() will be fast because Parents implements Collection
                var parentCount = commit.Parents.Count();
                _progressHandler?.OnFoundNewCommit(parentCount);

                Commit[] parentArray  = new Commit[parentCount];
                var      parentsIndex = 0;

                RecursiveCallResult <Commit?>[] promises = new RecursiveCallResult <Commit?> [parentCount];
                var promisesIndex = 0;

                foreach (var commitParent in commit.Parents)
                {
                    promises[promisesIndex++] =
                        ReferenceOrCopyCommit(sourceRepo, commitParent, targetRepo, NextDepth(maxDepth));
                }

                foreach (var promise in promises)
                {
                    var newParent = await promise;
                    if (newParent != null)
                    {
                        parentArray[parentsIndex++] = newParent;
                    }
                }

                Commit[] parents = parentArray.AsSpan().Slice(0, parentsIndex).ToArray();

                targetRepo.Index.Clear();
                var targetRepoIndexTree = _callback.CreateCommitTree(commit, parents, targetRepo);

                var message   = _callback.GenerateCommitMessage(commit);
                var author    = commit.Author;
                var committer = commit.Committer;

                newCommit = targetRepo.ObjectDatabase.CreateCommit(author, committer, message,
                                                                   targetRepoIndexTree, parents, false);


                _objectMapping[newCommit.Id] = commit.Id;
            }
            break;

            default:
                throw new ArgumentOutOfRangeException("", "result of GetCommitCopyKind");
            }

            _objectMapping[commit.Id] = newCommit?.Id ?? PreDefinedHash.EmptyTreeId;

            return(newCommit);
        }