@Override
  public <S> List<S> filterUniqueRoots(
      final List<S> in, final Convertor<S, VirtualFile> convertor) {
    Collections.sort(
        in, new ComparatorDelegate<S, VirtualFile>(convertor, FilePathComparator.getInstance()));

    for (int i = 1; i < in.size(); i++) {
      final S sChild = in.get(i);
      final VirtualFile child = convertor.convert(sChild);
      final VirtualFile childRoot = GitUtil.gitRootOrNull(child);
      if (childRoot == null) {
        // non-git file actually, skip it
        continue;
      }
      for (int j = i - 1; j >= 0; --j) {
        final S sParent = in.get(j);
        final VirtualFile parent = convertor.convert(sParent);
        // the method check both that parent is an ancestor of the child and that they share common
        // git root
        if (VfsUtilCore.isAncestor(parent, child, false)
            && VfsUtilCore.isAncestor(childRoot, parent, false)) {
          in.remove(i);
          //noinspection AssignmentToForLoopParameter
          --i;
          break;
        }
      }
    }
    return in;
  }
  @Before
  public void setUp() throws Throwable {
    IdeaTestApplication.getInstance();

    myTestName = createTestName();
    myProjectFixture =
        IdeaTestFixtureFactory.getFixtureFactory().createFixtureBuilder(myTestName).getFixture();

    edt(
        new ThrowableRunnable<Exception>() {
          @Override
          public void run() throws Exception {
            myProjectFixture.setUp();
          }
        });

    myProject = myProjectFixture.getProject();

    myProjectRoot = myProject.getBasePath();
    myProjectDir = myProject.getBaseDir();
    myTestRoot = myProjectRoot;

    myGit = ServiceManager.getService(myProject, Git.class);
    mySettings = GitVcsSettings.getInstance(myProject);
    mySettings.getAppSettings().setPathToGit(GitExecutor.PathHolder.GIT_EXECUTABLE);

    // dynamic overriding is used instead of making it in plugin.xml,
    // because MockVcsHelper is not ready to be a full featured implementation for all tests.
    myVcsHelper =
        GitTestUtil.overrideService(myProject, AbstractVcsHelper.class, MockVcsHelper.class);
    myChangeListManager = ChangeListManagerImpl.getInstanceImpl(myProject);
    myNotificator = (TestVcsNotifier) ServiceManager.getService(myProject, VcsNotifier.class);
    myVcs = GitVcs.getInstance(myProject);
    myRepositoryManager = GitUtil.getRepositoryManager(myProject);

    virtualCommits = new GitTestVirtualCommitsHolder();
    myAsyncTasks = new ArrayList<>();

    cd(myProjectRoot);
    myRepository = GitTestUtil.createRepository(myProject, myProjectRoot);

    ProjectLevelVcsManagerImpl vcsManager =
        (ProjectLevelVcsManagerImpl) ProjectLevelVcsManager.getInstance(myProject);
    AbstractVcs vcs = vcsManager.findVcsByName("Git");
    Assert.assertEquals(1, vcsManager.getRootsUnderVcs(vcs).length);

    GitTestUtil.assumeSupportedGitVersion(myVcs);
    LOG.info(getStartTestMarker());
  }
 @Override
 @Nullable
 public VcsRevisionNumber parseRevisionNumber(@Nullable String revision, @Nullable FilePath path)
     throws VcsException {
   if (revision == null || revision.length() == 0) return null;
   if (revision.length() > 40) { // date & revision-id encoded string
     String dateString = revision.substring(0, revision.indexOf("["));
     String rev = revision.substring(revision.indexOf("[") + 1, 40);
     Date d = new Date(Date.parse(dateString));
     return new GitRevisionNumber(rev, d);
   }
   if (path != null) {
     try {
       VirtualFile root = GitUtil.getGitRoot(path);
       return GitRevisionNumber.resolve(myProject, root, revision);
     } catch (VcsException e) {
       log.info("Unexpected problem with resolving the git revision number: ", e);
       throw e;
     }
   }
   return new GitRevisionNumber(revision);
 }
 @Override
 public boolean isVersionedDirectory(VirtualFile dir) {
   return dir.isDirectory() && GitUtil.gitRootOrNull(dir) != null;
 }