From c1b58b5d27319fa83e389f7fca4cc53713a428b3 Mon Sep 17 00:00:00 2001 From: Nicolas Meylan Date: Tue, 19 May 2026 10:45:00 +0200 Subject: [PATCH] Add support for unversionned and deleted files Both category are optionnal and can be disable from settings --- .../compare/ChangesService.java | 29 +++++++++++++---- src/main/java/model/MyModel.java | 9 +++--- src/main/java/settings/GitScopeSettings.java | 28 ++++++++++++++++ .../settings/GitScopeSettingsComponent.java | 32 +++++++++++++++++++ .../GitScopeSettingsConfigurable.java | 23 +++++++++---- 5 files changed, 103 insertions(+), 18 deletions(-) diff --git a/src/main/java/implementation/compare/ChangesService.java b/src/main/java/implementation/compare/ChangesService.java index 23901f8..fc851de 100644 --- a/src/main/java/implementation/compare/ChangesService.java +++ b/src/main/java/implementation/compare/ChangesService.java @@ -8,10 +8,12 @@ import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; import com.intellij.openapi.vcs.FilePath; +import com.intellij.openapi.vcs.FileStatus; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.changes.Change; import com.intellij.openapi.vcs.changes.ChangeListManager; import com.intellij.openapi.vcs.changes.ChangesUtil; +import com.intellij.openapi.vcs.changes.CurrentContentRevision; import com.intellij.openapi.vfs.VirtualFile; import git4idea.GitCommit; import git4idea.GitReference; @@ -22,6 +24,7 @@ import model.TargetBranchMap; import org.jetbrains.annotations.NotNull; import service.GitService; +import settings.GitScopeSettings; import system.Defs; import utils.PlatformApiReflection; import utils.GitUtil; @@ -249,17 +252,18 @@ public void clearCache(GitRepository repo) { */ private Collection filterLocalChanges(Collection localChanges, String repoPath, Collection existingChanges) { Collection filtered = new ArrayList<>(); + boolean showDeletedFiles = GitScopeSettings.getInstance().isShowDeletedFiles(); for (Change change : localChanges) { - VirtualFile changeFile = change.getVirtualFile(); - if (changeFile == null) { + FilePath changePath = ChangesUtil.getFilePath(change); + String changePathStr = changePath.getPath(); + + if (!showDeletedFiles && change.getType() == Change.Type.DELETED) { continue; } - String changePath = changeFile.getPath(); - // Check if change belongs to this repository - if (!changePath.startsWith(repoPath)) { + if (!changePathStr.startsWith(repoPath)) { continue; } @@ -267,8 +271,8 @@ private Collection filterLocalChanges(Collection localChanges, S if (existingChanges != null && !existingChanges.isEmpty()) { boolean isDuplicate = false; for (Change existing : existingChanges) { - VirtualFile existingFile = existing.getVirtualFile(); - if (existingFile != null && changePath.equals(existingFile.getPath())) { + String existingPath = ChangesUtil.getFilePath(existing).getPath(); + if (changePathStr.equals(existingPath)) { isDuplicate = true; break; } @@ -334,6 +338,17 @@ public RepoChangesResult doCollectChanges(Project project, GitRepository repo, S // Filter local changes for this repository repoLocalChanges = filterLocalChanges(localChanges, repoPath, null); + // Add unversioned (untracked) files if the setting is enabled + if (GitScopeSettings.getInstance().isShowUntrackedFiles()) { + for (FilePath unversionedPath : changeListManager.getUnversionedFilesPaths()) { + String filePathStr = unversionedPath.getPath(); + if (filePathStr.startsWith(repoPath)) { + Change untrackedChange = new Change(null, new CurrentContentRevision(unversionedPath), FileStatus.UNKNOWN); + repoLocalChanges.add(untrackedChange); + } + } + } + // Special handling for HEAD - return local changes only, no scope changes if (scopeRef.equals(GitService.BRANCH_HEAD)) { return new RepoChangesResult(new ArrayList<>(repoLocalChanges), new ArrayList<>(), repoLocalChanges); diff --git a/src/main/java/model/MyModel.java b/src/main/java/model/MyModel.java index ffce50b..5e0fdeb 100644 --- a/src/main/java/model/MyModel.java +++ b/src/main/java/model/MyModel.java @@ -1,7 +1,7 @@ package model; import com.intellij.openapi.vcs.changes.Change; -import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.openapi.vcs.changes.ChangesUtil; import git4idea.repo.GitRepository; import io.reactivex.rxjava3.core.Observable; import io.reactivex.rxjava3.subjects.PublishSubject; @@ -172,6 +172,7 @@ public Map getLocalChangesMap() { /** * Helper method to build a HashMap from a collection of changes indexed by file path. * This provides O(1) lookup performance for file status checks. + * Uses ChangesUtil.getFilePath() to properly handle deleted files (where getVirtualFile() is null). * * @param changes Collection of changes to convert to a map * @return Map of file path to Change, or null if changes is null @@ -183,10 +184,8 @@ public static Map buildChangesByPathMap(Collection chang Map changeMap = new HashMap<>(); for (Change change : changes) { - VirtualFile file = change.getVirtualFile(); - if (file != null) { - changeMap.put(file.getPath(), change); - } + String path = ChangesUtil.getFilePath(change).getPath(); + changeMap.put(path, change); } return changeMap; } diff --git a/src/main/java/settings/GitScopeSettings.java b/src/main/java/settings/GitScopeSettings.java index 0f07353..73cc173 100644 --- a/src/main/java/settings/GitScopeSettings.java +++ b/src/main/java/settings/GitScopeSettings.java @@ -32,6 +32,18 @@ public class GitScopeSettings implements PersistentStateComponent