@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; }
@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); }