diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogPathsIndex.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogPathsIndex.java index 9347f8fa478b..9d766ac2cbd8 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogPathsIndex.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/index/VcsLogPathsIndex.java @@ -244,8 +244,9 @@ public class VcsLogPathsIndex extends VcsLogFullDetailsIndex> map(@NotNull VcsFullCommitDetails inputData) { Map> result = new THashMap<>(); - int size = inputData.getParents().isEmpty() ? 1 : inputData.getParents().size(); - for (int parent = 0; parent < size; parent++) { + // its not exactly parents count since it is very convenient to assume that initial commit has one parent + int parentsCount = inputData.getParents().isEmpty() ? 1 : inputData.getParents().size(); + for (int parent = 0; parent < parentsCount; parent++) { Collection> moves; Collection changedPaths; if (inputData instanceof VcsIndexableDetails) { @@ -273,7 +274,7 @@ public class VcsLogPathsIndex extends VcsLogFullDetailsIndex { try { - addChangeToResult(result, finalParent, changedPath, null); + addChangeToResult(result, finalParent, parentsCount, changedPath, null); } catch (IOException e) { myFatalErrorConsumer.consume(e); @@ -281,7 +282,7 @@ public class VcsLogPathsIndex extends VcsLogFullDetailsIndex { try { - addChangeToResult(result, finalParent, renamedPaths.second, renamedPaths.first); + addChangeToResult(result, finalParent, parentsCount, renamedPaths.second, renamedPaths.first); } catch (IOException e) { myFatalErrorConsumer.consume(e); @@ -289,48 +290,54 @@ public class VcsLogPathsIndex extends VcsLogFullDetailsIndex> result, int parent, - @NotNull String afterPath, @Nullable String beforePath) throws IOException { + private void addChangeToResult(@NotNull Map> commitChangesMap, int parent, + int parentsCount, @NotNull String afterPath, @Nullable String beforePath) throws IOException { int afterId = myPathsEnumerator.enumerate(afterPath); - List data = fillDataWithNulls(result, parent, afterId); + List changeDataList = getOrCreateChangeDataListForPath(commitChangesMap, afterId, parentsCount); if (beforePath == null) { - data.add(new ChangeData(ChangeKind.MODIFIED, -1)); + addChange(changeDataList, parent, new ChangeData(ChangeKind.MODIFIED, -1)); } else { int beforeId = myPathsEnumerator.enumerate(beforePath); if (beforeId == afterId && !SystemInfo.isFileSystemCaseSensitive) { // case only rename in case insensitive file system // since ids for before and after paths are the same we just treating this rename as a modification - data.add(new ChangeData(ChangeKind.MODIFIED, -1)); + addChange(changeDataList, parent, new ChangeData(ChangeKind.MODIFIED, -1)); } else { - data.add(new ChangeData(ChangeKind.RENAMED_TO, beforeId)); - List beforeData = fillDataWithNulls(result, parent, beforeId); - beforeData.add(new ChangeData(ChangeKind.RENAMED_FROM, afterId)); + addChange(changeDataList, parent, new ChangeData(ChangeKind.RENAMED_TO, beforeId)); + List beforeChangeDataList = getOrCreateChangeDataListForPath(commitChangesMap, beforeId, parentsCount); + addChange(beforeChangeDataList, parent, new ChangeData(ChangeKind.RENAMED_FROM, afterId)); } } } @NotNull - private static List fillDataWithNulls(@NotNull Map> result, - int parent, int pathId) { - List data = result.get(pathId); - if (data == null) { - data = ContainerUtil.newSmartList(); - result.put(pathId, data); + private static List getOrCreateChangeDataListForPath(@NotNull Map> pathIdToChangeDataListsMap, + int pathId, int parentsCount) { + List changeDataList = pathIdToChangeDataListsMap.get(pathId); + if (changeDataList == null) { + changeDataList = ContainerUtil.newSmartList(); + for (int i = 0; i < parentsCount; i++) { + changeDataList.add(null); + } + pathIdToChangeDataListsMap.put(pathId, changeDataList); } - for (int i = data.size(); i < parent; i++) { - data.add(null); + return changeDataList; + } + + private static void addChange(@NotNull List changeDataList, int parentIndex, @NotNull ChangeData change) { + ChangeData existingChange = changeDataList.get(parentIndex); + // most of the time, existing change is null + // but in case insensitive fs it is possible to have several changes for one file + // example two changes: R: abc -> AAA, D: aaa + // in this case we keep rename information + if (existingChange == null || (existingChange.kind != ChangeKind.RENAMED_FROM && existingChange.kind != ChangeKind.RENAMED_TO)) { + changeDataList.set(parentIndex, change); } - LOG.assertTrue(data.size() == parent); - return data; } @NotNull