@NotNull
  public static <CommitInfo> List<CommitInfo> getCommitRecords(
      @NotNull Project project,
      @Nullable HgCommandResult result,
      @NotNull Function<String, CommitInfo> converter,
      boolean silent) {
    final List<CommitInfo> revisions = new LinkedList<CommitInfo>();
    if (result == null) {
      return revisions;
    }

    List<String> errors = result.getErrorLines();
    if (errors != null && !errors.isEmpty()) {
      if (result.getExitValue() != 0) {
        if (silent) {
          LOG.warn(errors.toString());
        } else {
          VcsNotifier.getInstance(project)
              .notifyError(
                  HgVcsMessages.message("hg4idea.error.log.command.execution"), errors.toString());
        }
        return Collections.emptyList();
      }
      LOG.warn(errors.toString());
    }
    String output = result.getRawOutput();
    List<String> changeSets = StringUtil.split(output, HgChangesetUtil.CHANGESET_SEPARATOR);
    return ContainerUtil.mapNotNull(changeSets, converter);
  }
  @NotNull
  @Override
  public List<? extends VcsCommitMetadata> readFirstBlock(
      @NotNull VirtualFile root, @NotNull Requirements requirements) throws VcsException {
    if (!isRepositoryReady(root)) {
      return Collections.emptyList();
    }

    int commitCount = requirements.getCommitCount();
    if (requirements.isOrdered()) {
      commitCount *=
          2; // need to query more to sort them manually; this doesn't affect performance: it is
      // equal for -1000 and -2000
    }

    String[] params =
        new String[] {"HEAD", "--branches", "--remotes", "--max-count=" + commitCount};
    // NB: not specifying --tags, because it introduces great slowdown if there are many tags,
    // but makes sense only if there are heads without branch or HEAD labels (rare case). Such cases
    // are partially handles below.
    List<VcsCommitMetadata> firstBlock = GitHistoryUtils.loadMetadata(myProject, root, params);

    if (requirements instanceof VcsLogProviderRequirementsEx) {
      VcsLogProviderRequirementsEx rex = (VcsLogProviderRequirementsEx) requirements;
      // on refresh: get new tags, which point to commits not from the first block; then get
      // history, walking down just from these tags
      // on init: just ignore such tagged-only branches. The price for speed-up.
      if (!rex.isOrdered()) {
        Collection<VcsRef> newTags = getNewTags(rex.getCurrentRefs(), rex.getPreviousRefs());
        if (!newTags.isEmpty()) {
          final Set<Hash> firstBlockHashes =
              ContainerUtil.map2Set(
                  firstBlock,
                  new Function<VcsCommitMetadata, Hash>() {
                    @Override
                    public Hash fun(VcsCommitMetadata metadata) {
                      return metadata.getHash();
                    }
                  });
          List<VcsRef> unmatchedHeads = getUnmatchedHeads(firstBlockHashes, newTags);
          if (!unmatchedHeads.isEmpty()) {
            List<VcsCommitMetadata> detailsFromTaggedBranches =
                loadSomeCommitsOnTaggedBranches(root, commitCount, unmatchedHeads);
            Collection<VcsCommitMetadata> unmatchedCommits =
                getUnmatchedCommits(firstBlockHashes, detailsFromTaggedBranches);
            firstBlock.addAll(unmatchedCommits);
          }
        }
      }
    }

    if (requirements.isOrdered()) {
      firstBlock = VcsLogSorter.sortByDateTopoOrder(firstBlock);
      firstBlock =
          new ArrayList<VcsCommitMetadata>(
              firstBlock.subList(0, Math.min(firstBlock.size(), requirements.getCommitCount())));
    }
    return firstBlock;
  }
  public static List<? extends VcsFullCommitDetails> createFullCommitsFromResult(
      @NotNull Project project,
      @NotNull VirtualFile root,
      @Nullable HgCommandResult result,
      @NotNull HgVersion version,
      boolean silent) {
    final VcsLogObjectsFactory factory = getObjectsFactoryWithDisposeCheck(project);
    if (factory == null) {
      return Collections.emptyList();
    }
    List<HgFileRevision> hgRevisions =
        getCommitRecords(
            project,
            result,
            new HgFileRevisionLogParser(project, getOriginalHgFile(project, root), version),
            silent);
    List<VcsFullCommitDetails> vcsFullCommitDetailsList = new ArrayList<VcsFullCommitDetails>();
    for (HgFileRevision revision : hgRevisions) {

      HgRevisionNumber vcsRevisionNumber = revision.getRevisionNumber();
      List<HgRevisionNumber> parents = vcsRevisionNumber.getParents();
      HgRevisionNumber firstParent =
          parents.isEmpty() ? null : parents.get(0); // can have no parents if it is a root
      List<Hash> parentsHash = new SmartList<Hash>();
      for (HgRevisionNumber parent : parents) {
        parentsHash.add(factory.createHash(parent.getChangeset()));
      }

      final Collection<Change> changes = new ArrayList<Change>();
      for (String file : revision.getModifiedFiles()) {
        changes.add(
            createChange(
                project, root, file, firstParent, file, vcsRevisionNumber, FileStatus.MODIFIED));
      }
      for (String file : revision.getAddedFiles()) {
        changes.add(
            createChange(project, root, null, null, file, vcsRevisionNumber, FileStatus.ADDED));
      }
      for (String file : revision.getDeletedFiles()) {
        changes.add(
            createChange(
                project, root, file, firstParent, null, vcsRevisionNumber, FileStatus.DELETED));
      }
      for (Map.Entry<String, String> copiedFile : revision.getCopiedFiles().entrySet()) {
        changes.add(
            createChange(
                project,
                root,
                copiedFile.getKey(),
                firstParent,
                copiedFile.getValue(),
                vcsRevisionNumber,
                FileStatus.ADDED));
      }

      vcsFullCommitDetailsList.add(
          factory.createFullDetails(
              factory.createHash(vcsRevisionNumber.getChangeset()),
              parentsHash,
              revision.getRevisionDate().getTime(),
              root,
              vcsRevisionNumber.getSubject(),
              vcsRevisionNumber.getAuthor(),
              vcsRevisionNumber.getEmail(),
              vcsRevisionNumber.getCommitMessage(),
              vcsRevisionNumber.getAuthor(),
              vcsRevisionNumber.getEmail(),
              revision.getRevisionDate().getTime(),
              new ThrowableComputable<Collection<Change>, Exception>() {
                @Override
                public Collection<Change> compute() throws Exception {
                  return changes;
                }
              }));
    }
    return vcsFullCommitDetailsList;
  }