From 8cba57a6a118a92887e9e47e3f5bb99d102eb7cb Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 6 May 2016 20:20:22 +0300 Subject: [PATCH] IDEA-53175 use proper mv -f command for case-only rename from IDEA --- plugins/git4idea/src/git4idea/GitUtil.java | 14 +++++ .../src/git4idea/commands/GitCommand.java | 1 + .../src/git4idea/vfs/GitVFSListener.java | 60 +++++++++++++++---- 3 files changed, 64 insertions(+), 11 deletions(-) diff --git a/plugins/git4idea/src/git4idea/GitUtil.java b/plugins/git4idea/src/git4idea/GitUtil.java index a0ed9242e9f6..d2ec7bf34402 100644 --- a/plugins/git4idea/src/git4idea/GitUtil.java +++ b/plugins/git4idea/src/git4idea/GitUtil.java @@ -1054,4 +1054,18 @@ public class GitUtil { public static Collection getRepositories(@NotNull Project project) { return getRepositoryManager(project).getRepositories(); } + + /** + * Checks if the given paths are equal only by case. + * It is expected that the paths are different at least by the case. + */ + public static boolean isCaseOnlyChange(@NotNull String oldPath, @NotNull String newPath) { + if (oldPath.equalsIgnoreCase(newPath)) { + if (oldPath.equals(newPath)) { + LOG.error("Comparing perfectly equal paths: " + newPath); + } + return true; + } + return false; + } } diff --git a/plugins/git4idea/src/git4idea/commands/GitCommand.java b/plugins/git4idea/src/git4idea/commands/GitCommand.java index 156da155152e..5f79d0ca3f68 100644 --- a/plugins/git4idea/src/git4idea/commands/GitCommand.java +++ b/plugins/git4idea/src/git4idea/commands/GitCommand.java @@ -53,6 +53,7 @@ public class GitCommand { public static final GitCommand LS_REMOTE = read("ls-remote"); public static final GitCommand MERGE = write("merge"); public static final GitCommand MERGE_BASE = read("merge-base"); + public static final GitCommand MV = write("mv"); public static final GitCommand PULL = write("pull"); public static final GitCommand PUSH = write("push"); public static final GitCommand REBASE = write("rebase"); diff --git a/plugins/git4idea/src/git4idea/vfs/GitVFSListener.java b/plugins/git4idea/src/git4idea/vfs/GitVFSListener.java index 31946f7febf8..015cb5dabc0c 100644 --- a/plugins/git4idea/src/git4idea/vfs/GitVFSListener.java +++ b/plugins/git4idea/src/git4idea/vfs/GitVFSListener.java @@ -19,20 +19,26 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.progress.Task; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Pair; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.ObjectsConvertor; import com.intellij.openapi.vcs.VcsException; import com.intellij.openapi.vcs.VcsVFSListener; -import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vcs.update.RefreshVFsSynchronously; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileEvent; import com.intellij.ui.AppUIUtil; +import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.UIUtil; import com.intellij.vcsUtil.VcsFileUtil; import com.intellij.vcsUtil.VcsUtil; import git4idea.GitUtil; import git4idea.GitVcs; import git4idea.commands.Git; +import git4idea.commands.GitCommand; +import git4idea.commands.GitHandler; +import git4idea.commands.GitSimpleHandler; import git4idea.i18n.GitBundle; import git4idea.util.GitFileUtils; import org.jetbrains.annotations.NotNull; @@ -41,6 +47,9 @@ import java.io.File; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; +import static com.intellij.util.containers.ContainerUtil.map2Map; +import static com.intellij.util.containers.ContainerUtil.newHashSet; + public class GitVFSListener extends VcsVFSListener { /** * More than zero if events are suppressed @@ -198,17 +207,46 @@ public class GitVFSListener extends VcsVFSListener { } protected void performMoveRename(final List movedFiles) { - // because git does not tracks moves, the file are just added and deleted. - ArrayList added = new ArrayList(); - ArrayList removed = new ArrayList(); - for (MovedFileInfo info : movedFiles) { - if (!GitFileUtils.shouldIgnoreCaseChange(info.myNewPath, info.myOldPath)) { - added.add(VcsUtil.getFilePath(info.myNewPath)); - removed.add(VcsUtil.getFilePath(info.myOldPath)); + List toAdd = ContainerUtil.newArrayList(); + List toRemove = ContainerUtil.newArrayList(); + List toForceMove = ContainerUtil.newArrayList(); + for (MovedFileInfo movedInfo : movedFiles) { + String oldPath = movedInfo.myOldPath; + String newPath = movedInfo.myNewPath; + if (!SystemInfo.isFileSystemCaseSensitive && GitUtil.isCaseOnlyChange(oldPath, newPath)) { + toForceMove.add(movedInfo); + } + else { + toRemove.add(VcsUtil.getFilePath(oldPath)); + toAdd.add(VcsUtil.getFilePath(newPath)); } } - performAdding(added); - performDeletion(removed); + performAdding(toAdd); + performDeletion(toRemove); + performForceMove(toForceMove); + } + + private void performForceMove(@NotNull List files) { + Map filesToMove = map2Map(files, (info) -> Pair.create(VcsUtil.getFilePath(info.myNewPath), info)); + Set toRefresh = newHashSet(); + performBackgroundOperation(filesToMove.keySet(), "Moving Files...", new LongOperationPerRootExecutor() { + @Override + public void execute(@NotNull VirtualFile root, @NotNull List files) throws VcsException { + for (FilePath file : files) { + GitHandler h = new GitSimpleHandler(myProject, root, GitCommand.MV); + MovedFileInfo info = filesToMove.get(file); + h.addParameters("-f", info.myOldPath, info.myNewPath); + h.runInCurrentThread(null); + toRefresh.add(new File(info.myOldPath)); + toRefresh.add(new File(info.myNewPath)); + } + } + + @Override + public Collection getFilesToRefresh() { + return toRefresh; + } + }); } protected boolean isDirectoryVersioningSupported() { @@ -246,7 +284,7 @@ public class GitVFSListener extends VcsVFSListener { }); } } - LocalFileSystem.getInstance().refreshIoFiles(executor.getFilesToRefresh()); + RefreshVFsSynchronously.refreshFiles(executor.getFilesToRefresh()); } }); }