From 0feb2dc60298ea6a18586347e2dfb989953761b7 Mon Sep 17 00:00:00 2001 From: "Nikolay.Rykunov" Date: Tue, 18 Jun 2019 11:07:49 +0300 Subject: [PATCH] IDEA-216114 Filter history by HEAD Our index may contain commits which were removed by git gc, so "bad object" error may occur. To avoid this error, we can filter the commits by HEAD GitOrigin-RevId: 6a77848d41c4af0db0a484084f63770033356e50 --- .../intellij.vcs.changeReminder.iml | 1 + .../predict/PredictionService.kt | 2 +- .../repository/FilesHistoryProvider.kt | 37 +++++++++++++++++-- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/plugins/changeReminder/intellij.vcs.changeReminder.iml b/plugins/changeReminder/intellij.vcs.changeReminder.iml index eb78b7b7f042..e8803fe039f4 100644 --- a/plugins/changeReminder/intellij.vcs.changeReminder.iml +++ b/plugins/changeReminder/intellij.vcs.changeReminder.iml @@ -11,6 +11,7 @@ + diff --git a/plugins/changeReminder/src/com/jetbrains/changeReminder/predict/PredictionService.kt b/plugins/changeReminder/src/com/jetbrains/changeReminder/predict/PredictionService.kt index 5b8500fd1985..c65dc151a17b 100644 --- a/plugins/changeReminder/src/com/jetbrains/changeReminder/predict/PredictionService.kt +++ b/plugins/changeReminder/src/com/jetbrains/changeReminder/predict/PredictionService.kt @@ -100,7 +100,7 @@ class PredictionService(val project: Project, dataManager.addDataPackChangeListener(dataPackChangeListener) dataManager.index.addListener(indexingFinishedListener) - val filesHistoryProvider = dataManager.index.dataGetter?.let { FilesHistoryProvider(project, it) } ?: return + val filesHistoryProvider = dataManager.index.dataGetter?.let { FilesHistoryProvider(project, dataManager, it) } ?: return predictionRequirements = PredictionRequirements(dataManager, filesHistoryProvider) calculatePrediction() } diff --git a/plugins/changeReminder/src/com/jetbrains/changeReminder/repository/FilesHistoryProvider.kt b/plugins/changeReminder/src/com/jetbrains/changeReminder/repository/FilesHistoryProvider.kt index a26b44e4cd43..d1c93f3fba00 100644 --- a/plugins/changeReminder/src/com/jetbrains/changeReminder/repository/FilesHistoryProvider.kt +++ b/plugins/changeReminder/src/com/jetbrains/changeReminder/repository/FilesHistoryProvider.kt @@ -1,18 +1,26 @@ // Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.jetbrains.changeReminder.repository +import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.project.Project import com.intellij.openapi.vcs.FilePath import com.intellij.openapi.vcs.changes.ChangesUtil import com.intellij.openapi.vfs.VirtualFile +import com.intellij.vcs.log.data.VcsLogData import com.intellij.vcs.log.data.index.IndexDataGetter +import com.intellij.vcs.log.graph.impl.facade.PermanentGraphImpl +import com.intellij.vcs.log.graph.utils.DfsWalk +import com.intellij.vcs.log.util.VcsLogUtil import com.intellij.vcs.log.visible.filters.VcsLogFilterObject import com.jetbrains.changeReminder.processCommitsFromHashes import com.jetbrains.changeReminder.retainAll +import gnu.trove.TIntHashSet data class Commit(val id: Int, val time: Long, val author: String, val files: Set) -internal class FilesHistoryProvider(private val project: Project, private val dataGetter: IndexDataGetter) { +internal class FilesHistoryProvider(private val project: Project, + private val dataManager: VcsLogData, + private val dataGetter: IndexDataGetter) { private val filesHistoryCache = HashMap>() private fun getCommitHashesWithFile(file: FilePath): Collection { @@ -42,11 +50,32 @@ internal class FilesHistoryProvider(private val project: Project, private val da return commitsData } + private fun getCommitsFromHead(root: VirtualFile): TIntHashSet { + val dataPack = dataManager.dataPack + val branchName = dataManager.getLogProvider(root).getCurrentBranch(root) ?: return TIntHashSet() + val branchRef = VcsLogUtil.findBranch(dataPack.refsModel, root, branchName) ?: return TIntHashSet() + val branchIndex = dataManager.getCommitIndex(branchRef.commitHash, branchRef.root) + + val permanentGraph = dataPack.permanentGraph as? PermanentGraphImpl ?: return TIntHashSet() + + val branchNodeId = permanentGraph.permanentCommitsInfo.getNodeId(branchIndex) + val commitsFromHead = TIntHashSet() + DfsWalk(listOf(branchNodeId), permanentGraph.linearGraph).walk(true) { + ProgressManager.checkCanceled() + commitsFromHead.add(permanentGraph.permanentCommitsInfo.getCommitId(it)) + true + } + return commitsFromHead + } + fun getFilesHistory(root: VirtualFile, files: Collection): Collection { filesHistoryCache.retainAll(files) - - filesHistoryCache.putAll(files.filter { it !in filesHistoryCache } - .associateWith { getCommitHashesWithFile(it) }) + val commitsFromHead = getCommitsFromHead(root) + filesHistoryCache.putAll(files + .filter { it !in filesHistoryCache } + .associateWith { file -> + getCommitHashesWithFile(file).filter { it in commitsFromHead } + }) val commits = files.mapNotNull { filesHistoryCache[it] }.flatten() return getCommitsData(root, commits)