IDEA-80512 Watch for refs/remotes and refs/heads dirs recursively; update branches...
authorKirill Likhodedov <Kirill.Likhodedov@jetbrains.com>
Sat, 28 Jan 2012 14:33:53 +0000 (18:33 +0400)
committerKirill Likhodedov <Kirill.Likhodedov@jetbrains.com>
Sat, 28 Jan 2012 14:33:53 +0000 (18:33 +0400)
plugins/git4idea/src/git4idea/repo/GitRepositoryFiles.java
plugins/git4idea/src/git4idea/repo/GitRepositoryUpdater.java
plugins/git4idea/src/git4idea/update/GitFetcher.java

index f59d5409a73538e4530059957a7fcd1762992c25..3dea7f406c294cf8ad22e95f3cf6d6d6a62e812a 100644 (file)
@@ -77,6 +77,16 @@ public class GitRepositoryFiles {
   static Collection<String> getSubDirRelativePaths() {
     return Arrays.asList(REFS_HEADS, REFS_REMOTES, INFO);
   }
+  
+  @NotNull
+  String getRefsHeadsPath() {
+    return myRefsHeadsDirPath;
+  }
+  
+  @NotNull
+  String getRefsRemotesPath() {
+    return myRefsRemotesDirPath;
+  }
 
   /**
    * {@code .git/config}
index 464cc5c380dc60378ac304d2bd3976325ce0a3e7..0e9e5b26f028ecfd7b94b22af80dab4c7c28125f 100644 (file)
@@ -17,14 +17,19 @@ package git4idea.repo;
 
 import com.intellij.openapi.Disposable;
 import com.intellij.openapi.vfs.LocalFileSystem;
+import com.intellij.openapi.vfs.VfsUtil;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.openapi.vfs.VirtualFileManager;
 import com.intellij.openapi.vfs.newvfs.BulkFileListener;
 import com.intellij.openapi.vfs.newvfs.events.VFileEvent;
 import com.intellij.util.Consumer;
+import com.intellij.util.Processor;
 import com.intellij.util.concurrency.QueueProcessor;
 import com.intellij.util.messages.MessageBusConnection;
+import com.intellij.vcsUtil.VcsUtil;
 import git4idea.util.GitFileUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 import java.util.List;
 
@@ -38,6 +43,8 @@ final class GitRepositoryUpdater implements Disposable, BulkFileListener {
   private final GitRepositoryFiles myRepositoryFiles;
   private final MessageBusConnection myMessageBusConnection;
   private final QueueProcessor<GitRepository.TrackedTopic> myUpdateQueue;
+  private final VirtualFile myRemotesDir;
+  private final VirtualFile myHeadsDir;
 
   GitRepositoryUpdater(GitRepository repository) {
     myRepository = repository;
@@ -48,18 +55,34 @@ final class GitRepositoryUpdater implements Disposable, BulkFileListener {
     LocalFileSystem.getInstance().addRootToWatch(gitDir.getPath(), true);
     
     myRepositoryFiles = GitRepositoryFiles.getInstance(root);
+    visitGitDirVfs(gitDir);
+    myHeadsDir = VcsUtil.getVirtualFile(myRepositoryFiles.getRefsHeadsPath());
+    myRemotesDir = VcsUtil.getVirtualFile(myRepositoryFiles.getRefsRemotesPath());
+
+    myUpdateQueue = new QueueProcessor<GitRepository.TrackedTopic>(new Updater(myRepository), myRepository.getProject().getDisposed());
+    myMessageBusConnection = repository.getProject().getMessageBus().connect();
+    myMessageBusConnection.subscribe(VirtualFileManager.VFS_CHANGES, this);
+  }
+
+  private static void visitGitDirVfs(@NotNull VirtualFile gitDir) {
     gitDir.getChildren();
     for (String subdir : GitRepositoryFiles.getSubDirRelativePaths()) {
       VirtualFile dir = gitDir.findFileByRelativePath(subdir);
-      if (dir != null) {
-        dir.getChildren();
+      // process recursively, because we need to visit all branches under refs/heads and refs/remotes
+      visitAllChildrenRecursively(dir);
+    }
+  }
+
+  private static void visitAllChildrenRecursively(@Nullable VirtualFile dir) {
+    if (dir == null) {
+      return;
+    }
+    VfsUtil.processFilesRecursively(dir, new Processor<VirtualFile>() {
+      @Override
+      public boolean process(VirtualFile virtualFile) {
+        return true;
       }
-    }    
-    
-    myUpdateQueue = new QueueProcessor<GitRepository.TrackedTopic>(new Updater(myRepository), myRepository.getProject().getDisposed());
-    
-    myMessageBusConnection = repository.getProject().getMessageBus().connect();
-    myMessageBusConnection.subscribe(VirtualFileManager.VFS_CHANGES, this);
+    });
   }
 
   @Override
@@ -91,8 +114,14 @@ final class GitRepositoryUpdater implements Disposable, BulkFileListener {
         configChanged = true;
       } else if (myRepositoryFiles.isHeadFile(filePath)) {
         headChanged = true;
-      } else if (myRepositoryFiles.isBranchFile(filePath) || myRepositoryFiles.isRemoteBranchFile(filePath)) {
+      } else if (myRepositoryFiles.isBranchFile(filePath)) {
+        // it is also possible, that a local branch with complex name ("myfolder/mybranch") was created => the folder also to be watched.
+        branchFileChanged = true;   
+        visitAllChildrenRecursively(myHeadsDir);
+      } else if (myRepositoryFiles.isRemoteBranchFile(filePath)) {
+        // it is possible, that a branch from a new remote was fetch => we need to add new remote folder to the VFS
         branchFileChanged = true;
+        visitAllChildrenRecursively(myRemotesDir);
       } else if (myRepositoryFiles.isPackedRefs(filePath)) {
         packedRefsChanged = true;
       } else if (myRepositoryFiles.isRebaseFile(filePath)) {
index 18ed54b6ef5df7306c898b58c2cbdfa8354b52b4..7682e0736dfb1be1e16125abffadc4d6fee243f9 100644 (file)
@@ -83,6 +83,7 @@ public class GitFetcher {
       }
     }
     
+    repository.update(GitRepository.TrackedTopic.BRANCHES);
     return result;
   }