@NotNull
 private Set<VcsRef> readBranches(@NotNull GitRepository repository) {
   StopWatch sw = StopWatch.start("readBranches in " + repository.getRoot().getName());
   VirtualFile root = repository.getRoot();
   repository.update();
   Collection<GitLocalBranch> localBranches = repository.getBranches().getLocalBranches();
   Collection<GitRemoteBranch> remoteBranches = repository.getBranches().getRemoteBranches();
   Set<VcsRef> refs = new THashSet<VcsRef>(localBranches.size() + remoteBranches.size());
   for (GitLocalBranch localBranch : localBranches) {
     refs.add(
         myVcsObjectsFactory.createRef(
             localBranch.getHash(), localBranch.getName(), GitRefManager.LOCAL_BRANCH, root));
   }
   for (GitRemoteBranch remoteBranch : remoteBranches) {
     refs.add(
         myVcsObjectsFactory.createRef(
             remoteBranch.getHash(),
             remoteBranch.getNameForLocalOperations(),
             GitRefManager.REMOTE_BRANCH,
             root));
   }
   String currentRevision = repository.getCurrentRevision();
   if (currentRevision != null) { // null => fresh repository
     refs.add(
         myVcsObjectsFactory.createRef(
             HashImpl.build(currentRevision), "HEAD", GitRefManager.HEAD, root));
   }
   sw.report();
   return refs;
 }
 @NotNull
 private Set<String> readCurrentTagNames(@NotNull VirtualFile root) throws VcsException {
   StopWatch sw = StopWatch.start("reading tags in " + root.getName());
   Set<String> tags = newHashSet();
   GitTag.listAsStrings(myProject, root, tags, null);
   sw.report();
   return tags;
 }
 @NotNull
 private DetailedLogData loadSomeCommitsOnTaggedBranches(
     @NotNull VirtualFile root, int commitCount, @NotNull Collection<String> unmatchedTags)
     throws VcsException {
   StopWatch sw = StopWatch.start("loading commits on tagged branch in " + root.getName());
   List<String> params = new ArrayList<String>();
   params.add("--max-count=" + commitCount);
   params.addAll(unmatchedTags);
   sw.report();
   return GitHistoryUtils.loadMetadata(myProject, root, true, ArrayUtil.toStringArray(params));
 }
  private static void validateDataAndReportError(
      @NotNull final VirtualFile root,
      @NotNull final Set<VcsRef> allRefs,
      @NotNull final List<VcsCommitMetadata> sortedCommits,
      @NotNull final DetailedLogData firstBlockSyncData,
      @NotNull final Set<VcsRef> manuallyReadBranches,
      @Nullable final Set<String> currentTagNames,
      @Nullable final DetailedLogData commitsFromTags) {
    StopWatch sw = StopWatch.start("validating data in " + root.getName());
    final Set<Hash> refs =
        ContainerUtil.map2Set(
            allRefs,
            new Function<VcsRef, Hash>() {
              @Override
              public Hash fun(VcsRef ref) {
                return ref.getCommitHash();
              }
            });

    PermanentGraphImpl.newInstance(
        sortedCommits,
        new GraphColorManager<Hash>() {
          @Override
          public int getColorOfBranch(@NotNull Hash headCommit) {
            return 0;
          }

          @Override
          public int getColorOfFragment(@NotNull Hash headCommit, int magicIndex) {
            return 0;
          }

          @Override
          public int compareHeads(@NotNull Hash head1, @NotNull Hash head2) {
            if (!refs.contains(head1) || !refs.contains(head2)) {
              LOG.error(
                  "GitLogProvider returned inconsistent data",
                  new Attachment(
                      "error-details.txt",
                      printErrorDetails(
                          root,
                          allRefs,
                          sortedCommits,
                          firstBlockSyncData,
                          manuallyReadBranches,
                          currentTagNames,
                          commitsFromTags)));
            }
            return 0;
          }
        },
        refs);
    sw.report();
  }
 private void readCurrentUser() {
   StopWatch sw = StopWatch.start("readCurrentUser");
   for (Map.Entry<VirtualFile, VcsLogProvider> entry : myLogProviders.entrySet()) {
     VirtualFile root = entry.getKey();
     try {
       VcsUser me = entry.getValue().getCurrentUser(root);
       if (me != null) {
         myCurrentUser.put(root, me);
       } else {
         LOG.info("Username not configured for root " + root);
       }
     } catch (VcsException e) {
       LOG.warn("Couldn't read the username from root " + root, e);
     }
   }
   sw.report();
 }
  @NotNull
  @Override
  public DetailedLogData readFirstBlock(
      @NotNull VirtualFile root, @NotNull Requirements requirements) throws VcsException {
    if (!isRepositoryReady(root)) {
      return LogDataImpl.empty();
    }
    GitRepository repository =
        ObjectUtils.assertNotNull(myRepositoryManager.getRepositoryForRoot(root));

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

    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 handled below.

    boolean refresh =
        requirements instanceof VcsLogProviderRequirementsEx
            && ((VcsLogProviderRequirementsEx) requirements).isRefresh();

    DetailedLogData data = GitHistoryUtils.loadMetadata(myProject, root, true, params);

    Set<VcsRef> safeRefs = data.getRefs();
    Set<VcsRef> allRefs = new OpenTHashSet<VcsRef>(safeRefs, DONT_CONSIDER_SHA);
    Set<VcsRef> branches = readBranches(repository);
    addNewElements(allRefs, branches);

    Collection<VcsCommitMetadata> allDetails;
    Set<String> currentTagNames = null;
    DetailedLogData commitsFromTags = null;
    if (!refresh) {
      allDetails = data.getCommits();
    } else {
      // 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.
      VcsLogProviderRequirementsEx rex = (VcsLogProviderRequirementsEx) requirements;

      currentTagNames = readCurrentTagNames(root);
      addOldStillExistingTags(allRefs, currentTagNames, rex.getPreviousRefs());

      allDetails = newHashSet(data.getCommits());

      Set<String> previousTags =
          newHashSet(ContainerUtil.mapNotNull(rex.getPreviousRefs(), GET_TAG_NAME));
      Set<String> safeTags = newHashSet(ContainerUtil.mapNotNull(safeRefs, GET_TAG_NAME));
      Set<String> newUnmatchedTags = remove(currentTagNames, previousTags, safeTags);

      if (!newUnmatchedTags.isEmpty()) {
        commitsFromTags = loadSomeCommitsOnTaggedBranches(root, commitCount, newUnmatchedTags);
        addNewElements(allDetails, commitsFromTags.getCommits());
        addNewElements(allRefs, commitsFromTags.getRefs());
      }
    }

    StopWatch sw = StopWatch.start("sorting commits in " + root.getName());
    List<VcsCommitMetadata> sortedCommits = VcsLogSorter.sortByDateTopoOrder(allDetails);
    sortedCommits =
        sortedCommits.subList(0, Math.min(sortedCommits.size(), requirements.getCommitCount()));
    sw.report();

    if (LOG.isDebugEnabled()) {
      validateDataAndReportError(
          root, allRefs, sortedCommits, data, branches, currentTagNames, commitsFromTags);
    }

    return new LogDataImpl(allRefs, sortedCommits);
  }