@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 static <T> Set<T> remove(@NotNull Set<T> original, @NotNull Set<T>... toRemove) {
   Set<T> result = newHashSet(original);
   for (Set<T> set : toRemove) {
     result.removeAll(set);
   }
   return result;
 }
 private static void addOldStillExistingTags(
     @NotNull Set<VcsRef> allRefs,
     @NotNull Set<String> currentTags,
     @NotNull Set<VcsRef> previousRefs) {
   for (VcsRef ref : previousRefs) {
     if (!allRefs.contains(ref) && currentTags.contains(ref.getName())) {
       allRefs.add(ref);
     }
   }
 }
 @NotNull
 public static Collection<String> getDescendingHeadsOfBranches(
     @NotNull Project project, @NotNull VirtualFile root, @NotNull Hash hash) throws VcsException {
   // hg log -r "descendants(659db54c1b6865c97c4497fa867194bcd759ca76) and head()" --template
   // "{branch}{bookmarks}"
   Set<String> branchHeads = new HashSet<String>();
   List<String> params = new ArrayList<String>();
   params.add("-r");
   params.add("descendants(" + hash.asString() + ") and head()");
   HgLogCommand hgLogCommand = new HgLogCommand(project);
   hgLogCommand.setLogFile(false);
   String template = HgChangesetUtil.makeTemplate("{branch}", "{bookmarks}");
   HgCommandResult logResult = hgLogCommand.execute(root, template, -1, null, params);
   if (logResult == null || logResult.getExitValue() != 0) {
     throw new VcsException("Couldn't get commit details: log command execution error.");
   }
   String output = logResult.getRawOutput();
   List<String> changeSets = StringUtil.split(output, HgChangesetUtil.CHANGESET_SEPARATOR);
   for (String line : changeSets) {
     List<String> attributes = StringUtil.split(line, HgChangesetUtil.ITEM_SEPARATOR);
     branchHeads.addAll(attributes);
   }
   return branchHeads;
 }
  @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);
  }