Source:
<code>private void createResourceChangeListener() { resourceChangeListener = new IResourceChangeListener() { private final Map<IProject, IPath> deletedProjects = new HashMap<>(); @Override public void resourceChanged(IResourceChangeEvent event) { if (event.getDelta() != null) { SkipNotInterestingDeltaVisitor skipNotInterestingVisitor = new SkipNotInterestingDeltaVisitor(); try { event.getDelta().accept(skipNotInterestingVisitor); if (!skipNotInterestingVisitor .hasAtLeastOneInterestingDelta()) { return; } } catch (CoreException e) { Activator.logError(e.getMessage(), e); } } <START> <END> Repository repository = getRepository(); if (repository == null) { ResourcesPlugin.getWorkspace() .removeResourceChangeListener(this); resourceChangeListener = null; return; } if (event.getType() == IResourceChangeEvent.PRE_DELETE) { IResource resource = event.getResource(); if (resource.getType() == IResource.PROJECT) { IPath projectPath = resource.getLocation(); if (projectPath != null) { IPath repoPath = ResourceUtil .getRepositoryRelativePath(projectPath, repository); if (repoPath != null) { deletedProjects.put((IProject) resource, projectPath); } } } return; } GitResourceDeltaVisitor visitor = new GitResourceDeltaVisitor( repository, deletedProjects); try { event.getDelta().accept(visitor); } catch (CoreException e) { Activator.logError(e.getMessage(), e); return; } if (visitor.getGitIgnoreChanged()) { scheduleReloadJob("A .gitignore changed"); } else if (visitor.isProjectDeleted()) { scheduleReloadJob("A project was deleted"); } else if (indexDiffData == null) { scheduleReloadJob("Resource changed, no diff available"); } else { Collection<String> filesToUpdate = visitor .getFilesToUpdate(); Collection<IResource> resourcesToUpdate = visitor .getResourcesToUpdate(); if (!filesToUpdate.isEmpty()) { scheduleUpdateJob(filesToUpdate, resourcesToUpdate); } } } }; ResourcesPlugin.getWorkspace().addResourceChangeListener( resourceChangeListener, IResourceChangeEvent.POST_CHANGE | IResourceChangeEvent.PRE_DELETE); }</code><technical_language>This approach need careful performance tests large workspaces. (On a machine a hard disk in good working order :-)) especially worried post-build events "uninteresting changes" (marker changes)</technical_language>

Target:
private void createResourceChangeListener() { resourceChangeListener = new IResourceChangeListener() { private final Map<IProject, IPath> deletedProjects = new HashMap<>(); @Override public void resourceChanged(IResourceChangeEvent event) { if (event.getType() == IResourceChangeEvent.PRE_DELETE) { IResource resource = event.getResource(); if (resource.getType() == IResource.PROJECT) { IPath projectPath = resource.getLocation(); if (projectPath != null) { Repository repository = getRepository(); if (repository == null) { ResourcesPlugin.getWorkspace() .removeResourceChangeListener(this); resourceChangeListener = null; return; } IPath repoPath = ResourceUtil .getRepositoryRelativePath(projectPath, repository); if (repoPath != null) { deletedProjects.put((IProject) resource, projectPath); } } } return; } RepositorySupplier repositorySupplier = new RepositorySupplier( IndexDiffCacheEntry.this); GitResourceDeltaVisitor visitor = new GitResourceDeltaVisitor( repositorySupplier, null, deletedProjects); try { event.getDelta().accept(visitor); } catch (CoreException e) { Activator.logError(e.getMessage(), e); return; } if (repositorySupplier.get() == null) { ResourcesPlugin.getWorkspace() .removeResourceChangeListener(this); resourceChangeListener = null; return; } if (visitor.getGitIgnoreChanged()) { scheduleReloadJob("A .gitignore changed"); } else if (visitor.isProjectDeleted()) { scheduleReloadJob("A project was deleted"); } else if (indexDiffData == null) { scheduleReloadJob("Resource changed, no diff available"); } else { Collection<String> filesToUpdate = visitor .getFilesToUpdate(); Collection<IResource> resourcesToUpdate = visitor .getResourcesToUpdate(); if (!filesToUpdate.isEmpty()) { scheduleUpdateJob(filesToUpdate, resourcesToUpdate); } } } }; ResourcesPlugin.getWorkspace().addResourceChangeListener( resourceChangeListener, IResourceChangeEvent.POST_CHANGE | IResourceChangeEvent.PRE_DELETE); }