From dcac40250745ce990013a39f41d6066409a3d281 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Tue, 21 Feb 2017 22:05:19 +0000 Subject: [PATCH] Don't autodelete directory after deleting the last file in it Executing `git rm` on the last file in a directory makes Git remove not only this file, but its parent directory as well. Although it is Git's behavior, it is not convenient, and it is also unexpected since `git rm` is not explicitly triggered by user who deletes a file from the Project View. GitVFSListener is triggered _after_ actual deletion of the file, so the only thing Git should do is to delete the file from the index: git rm --cached. This does the same as `git rm`, but prevents Git from removing the directory (since files are not touched on disk, only in the index). Fixes IDEA-75590 --- .../src/git4idea/vfs/GitVFSListener.java | 2 +- .../tests/git4idea/checkin/GitRmTest.kt | 60 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 plugins/git4idea/tests/git4idea/checkin/GitRmTest.kt diff --git a/plugins/git4idea/src/git4idea/vfs/GitVFSListener.java b/plugins/git4idea/src/git4idea/vfs/GitVFSListener.java index 779d40be7f83..b6b796345d72 100644 --- a/plugins/git4idea/src/git4idea/vfs/GitVFSListener.java +++ b/plugins/git4idea/src/git4idea/vfs/GitVFSListener.java @@ -180,7 +180,7 @@ public class GitVFSListener extends VcsVFSListener { HashSet filesToRefresh = new HashSet<>(); public void execute(@NotNull VirtualFile root, @NotNull List files) throws VcsException { - GitFileUtils.delete(myProject, root, files, "--ignore-unmatch"); + GitFileUtils.delete(myProject, root, files, "--ignore-unmatch", "--cached"); if (!myProject.isDisposed()) { VcsFileUtil.markFilesDirty(myProject, files); } diff --git a/plugins/git4idea/tests/git4idea/checkin/GitRmTest.kt b/plugins/git4idea/tests/git4idea/checkin/GitRmTest.kt new file mode 100644 index 000000000000..8ccda0347b32 --- /dev/null +++ b/plugins/git4idea/tests/git4idea/checkin/GitRmTest.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package git4idea.checkin + +import com.intellij.openapi.application.runWriteAction +import com.intellij.openapi.command.CommandProcessor +import com.intellij.openapi.vcs.FileStatus +import com.intellij.openapi.vcs.VcsVFSListener +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.testFramework.runInEdtAndWait +import com.intellij.vcsUtil.VcsUtil.getFilePath +import git4idea.test.GitSingleRepoTest +import git4idea.test.git +import java.io.File + +class GitRmTest : GitSingleRepoTest() { + + override fun getDebugLogCategories() = super.getDebugLogCategories().plus("#" + VcsVFSListener::class.java.name) + + // IDEA-75590 + fun `test empty directories are not removed on git rm`() { + val nestedDir = File(myProjectPath, "lib/subdir") + assertTrue("Directory $nestedDir wasn't created", nestedDir.mkdirs()) + val file = File(nestedDir, "f.txt") + assertTrue("File $file wasn't created", file.createNewFile()) + git("add .") + git("commit -m 'added file'") + val vf = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(file) + assertNotNull("VirtualFile not found for file $file", vf) + vf!! + + runInEdtAndWait { + CommandProcessor.getInstance().executeCommand(myProject, { + runWriteAction { + vf.delete(this) + } + }, null, null) + } + updateChangeListManager() + + assertFalse("File wasn't deleted", file.exists()) + assertTrue("Directory shouldn't have been deleted", nestedDir.exists()) + val change = changeListManager.getChange(getFilePath(vf)) + assertNotNull(change) + assertEquals(FileStatus.DELETED, change!!.fileStatus) + } +} \ No newline at end of file