diff --git a/plugins/git4idea/src/git4idea/repo/GitUntrackedFilesHolder.java b/plugins/git4idea/src/git4idea/repo/GitUntrackedFilesHolder.java
index cd91d5aa2c02..c748728f852e 100644
--- a/plugins/git4idea/src/git4idea/repo/GitUntrackedFilesHolder.java
+++ b/plugins/git4idea/src/git4idea/repo/GitUntrackedFilesHolder.java
@@ -68,10 +68,18 @@ import java.util.Set;
* In some cases (file creation/deletion) the file is not silently added/removed from the list - instead the file is marked as
* "possibly untracked" and Git is asked for the exact status of this file.
* It is needed, since the file may be created and added to the index independently, and events may race.
- *
+ *
+ *
* Also, if .git/index changes, then a full refresh is initiated. The reason is not only untracked files tracking, but also handling
* committing outside IDEA, etc.
*
+ *
+ * Synchronization policy used in this class:
+ * myDefinitelyUntrackedFiles is accessed under the myDefinitelyUntrackedFiles lock.
+ * myPossiblyUntrackedFiles and myReady is accessed under the LOCK lock.
+ * This is done so, because the latter two variables are accessed from the AWT in after() and we don't want to lock the AWT long,
+ * while myDefinitelyUntrackedFiles is modified along with native request to Git.
+ *
*
* @author Kirill Likhodedov
*/
@@ -84,8 +92,8 @@ public class GitUntrackedFilesHolder implements Disposable, BulkFileListener {
private final GitRepositoryFiles myRepositoryFiles;
private final Git myGit;
- private Set myDefinitelyUntrackedFiles = new HashSet();
- private Set myPossiblyUntrackedFiles = new HashSet();
+ private final Set myDefinitelyUntrackedFiles = new HashSet();
+ private final Set myPossiblyUntrackedFiles = new HashSet();
private boolean myReady; // if false, total refresh is needed
private final Object LOCK = new Object();
private final GitRepositoryManager myRepositoryManager;
@@ -111,8 +119,10 @@ public class GitUntrackedFilesHolder implements Disposable, BulkFileListener {
@Override
public void dispose() {
- synchronized (LOCK) {
+ synchronized (myDefinitelyUntrackedFiles) {
myDefinitelyUntrackedFiles.clear();
+ }
+ synchronized (LOCK) {
myPossiblyUntrackedFiles.clear();
}
}
@@ -121,10 +131,8 @@ public class GitUntrackedFilesHolder implements Disposable, BulkFileListener {
* Adds the file to the list of untracked.
*/
public void add(@NotNull VirtualFile file) {
- synchronized (LOCK) {
- if (myReady) {
- myDefinitelyUntrackedFiles.add(file);
- }
+ synchronized (myDefinitelyUntrackedFiles) {
+ myDefinitelyUntrackedFiles.add(file);
}
}
@@ -132,10 +140,8 @@ public class GitUntrackedFilesHolder implements Disposable, BulkFileListener {
* Removes several files from untracked.
*/
public void remove(@NotNull Collection files) {
- synchronized (LOCK) {
- if (myReady) {
- myDefinitelyUntrackedFiles.removeAll(files);
- }
+ synchronized (myDefinitelyUntrackedFiles) {
+ myDefinitelyUntrackedFiles.removeAll(files);
}
}
@@ -152,7 +158,7 @@ public class GitUntrackedFilesHolder implements Disposable, BulkFileListener {
} else {
rescanAll();
}
- synchronized (LOCK) {
+ synchronized (myDefinitelyUntrackedFiles) {
return myDefinitelyUntrackedFiles;
}
}
@@ -168,8 +174,11 @@ public class GitUntrackedFilesHolder implements Disposable, BulkFileListener {
*/
public void rescanAll() throws VcsException {
Set untrackedFiles = myGit.untrackedFiles(myProject, myRoot, null);
+ synchronized (myDefinitelyUntrackedFiles) {
+ myDefinitelyUntrackedFiles.clear();
+ myDefinitelyUntrackedFiles.addAll(untrackedFiles);
+ }
synchronized (LOCK) {
- myDefinitelyUntrackedFiles = untrackedFiles;
myPossiblyUntrackedFiles.clear();
myReady = true;
}
@@ -191,15 +200,15 @@ public class GitUntrackedFilesHolder implements Disposable, BulkFileListener {
Set suspiciousFiles = new HashSet();
synchronized (LOCK) {
suspiciousFiles.addAll(myPossiblyUntrackedFiles);
+ myPossiblyUntrackedFiles.clear();
}
- Set untrackedFiles = myGit.untrackedFiles(myProject, myRoot, suspiciousFiles);
- suspiciousFiles.removeAll(untrackedFiles);
- // files that were suspicious (and thus passed to 'git ls-files'), but are not untracked, are definitely tracked.
- Set trackedFiles = suspiciousFiles;
+ synchronized (myDefinitelyUntrackedFiles) {
+ Set untrackedFiles = myGit.untrackedFiles(myProject, myRoot, suspiciousFiles);
+ suspiciousFiles.removeAll(untrackedFiles);
+ // files that were suspicious (and thus passed to 'git ls-files'), but are not untracked, are definitely tracked.
+ Set trackedFiles = suspiciousFiles;
- synchronized (LOCK) {
- myPossiblyUntrackedFiles.clear();
myDefinitelyUntrackedFiles.addAll(untrackedFiles);
myDefinitelyUntrackedFiles.removeAll(trackedFiles);
}