diff --git a/src/plugins/coreplugin/iversioncontrol.h b/src/plugins/coreplugin/iversioncontrol.h
index 8fe0bc038e0c9cf290ce4865f2652bffad5aa608..0cd29f9438865aa00b2d8b63a4e7ec880af8f60d 100644
--- a/src/plugins/coreplugin/iversioncontrol.h
+++ b/src/plugins/coreplugin/iversioncontrol.h
@@ -56,21 +56,12 @@ public:
     /*!
      * Returns whether files in this directory should be managed with this
      * version control.
+     * If \a topLevel is non-null, it should return the topmost directory,
+     * for which this IVersionControl should be used. The VCSManager assumes
+     * that all files in the returned directory are managed by the same IVersionControl.
      */
-    virtual bool managesDirectory(const QString &filename) const = 0;
 
-    /*!
-     * This function should return the topmost directory, for which this
-     * IVersionControl should be used. The VCSManager assumes that all files in
-     * the returned directory are managed by the same IVersionControl.
-     *
-     * Note that this is used as an optimization, so that the VCSManager
-     * doesn't need to call managesDirectory(..) for each directory.
-     *
-     * This function is called after finding out that the directory is managed
-     * by a specific version control.
-     */
-    virtual QString findTopLevelForDirectory(const QString &directory) const = 0;
+    virtual bool managesDirectory(const QString &filename, QString *topLevel = 0) const = 0;
 
     /*!
      * Called to query whether a VCS supports the respective operations.
diff --git a/src/plugins/coreplugin/vcsmanager.cpp b/src/plugins/coreplugin/vcsmanager.cpp
index 35d5b2f0644560c79e40cfbf53044aea8b6d5fbd..0221e29c9fa2a4ecf401fe67045da5fd60bcfa1e 100644
--- a/src/plugins/coreplugin/vcsmanager.cpp
+++ b/src/plugins/coreplugin/vcsmanager.cpp
@@ -90,6 +90,18 @@ IVersionControl* VCSManager::findVersionControlForDirectory(const QString &direc
                                                             QString *topLevelDirectory)
 {
     typedef VersionControlCache::const_iterator VersionControlCacheConstIterator;
+
+    if (debug) {
+        qDebug(">findVersionControlForDirectory %s topLevelPtr %d",
+               qPrintable(directory), (topLevelDirectory != 0));
+        if (debug > 1) {
+            const VersionControlCacheConstIterator cend = m_d->m_cachedMatches.constEnd();
+            for (VersionControlCacheConstIterator it = m_d->m_cachedMatches.constBegin(); it != cend; ++it)
+                qDebug("Cache %s -> '%s'", qPrintable(it.key()), qPrintable(it.value()->displayName()));
+        }
+    }
+    QTC_ASSERT(!directory.isEmpty(), return 0);
+
     const VersionControlCacheConstIterator cacheEnd = m_d->m_cachedMatches.constEnd();
 
     if (topLevelDirectory)
@@ -100,37 +112,51 @@ IVersionControl* VCSManager::findVersionControlForDirectory(const QString &direc
     if (fullPathIt != cacheEnd) {
         if (topLevelDirectory)
             *topLevelDirectory = directory;
+        if (debug)
+            qDebug("<findVersionControlForDirectory: full cache match for VCS '%s'", qPrintable(fullPathIt.value()->displayName()));
         return fullPathIt.value();
     }
 
-    // Split the path, starting from top, try to find the matching repository
-    int pos = 0;
+    // Split the path, trying to find the matching repository. We start from the reverse
+    // in order to detected nested repositories correctly (say, a git checkout under SVN).
+    // Note that detection of a nested version control will still fail if the
+    // above-located version control is detected and entered into the cache first.
+    // The nested one can then no longer be found due to the splitting of the paths.
+    int pos = directory.size() - 1;
     const QChar slash = QLatin1Char('/');
     while (true) {
-        const int index = directory.indexOf(slash, pos);
-        if (index == -1)
+        const int index = directory.lastIndexOf(slash, pos);
+        if (index <= 0) // Stop at '/' or not found
             break;
         const QString directoryPart = directory.left(index);
         const VersionControlCacheConstIterator it = m_d->m_cachedMatches.constFind(directoryPart);
         if (it != cacheEnd) {
             if (topLevelDirectory)
                 *topLevelDirectory = it.key();
+            if (debug)
+                qDebug("<findVersionControlForDirectory: cache match for VCS '%s', topLevel: %s",
+                       qPrintable(it.value()->displayName()), qPrintable(it.key()));
             return it.value();
         }
-        pos = index + 1;
+        pos = index - 1;
     }
 
     // Nothing: ask the IVersionControls directly, insert the toplevel into the cache.
     const VersionControlList versionControls = allVersionControls();
     foreach (IVersionControl * versionControl, versionControls) {
-        if (versionControl->managesDirectory(directory)) {
-            const QString topLevel = versionControl->findTopLevelForDirectory(directory);
+        QString topLevel;
+        if (versionControl->managesDirectory(directory, &topLevel)) {
             m_d->m_cachedMatches.insert(topLevel, versionControl);
             if (topLevelDirectory)
                 *topLevelDirectory = topLevel;
+            if (debug)
+                qDebug("<findVersionControlForDirectory: invocation of '%s' matches: %s",
+                       qPrintable(versionControl->displayName()), qPrintable(topLevel));
             return versionControl;
         }
     }
+    if (debug)
+        qDebug("<findVersionControlForDirectory: No match for %s", qPrintable(directory));
     return 0;
 }
 
diff --git a/src/plugins/cvs/cvscontrol.cpp b/src/plugins/cvs/cvscontrol.cpp
index 42462006dfd3b62698822a1abbf06562c9bfd1f9..dbf8adf4b78c8dc8b25add6fe6b0600cd9a59deb 100644
--- a/src/plugins/cvs/cvscontrol.cpp
+++ b/src/plugins/cvs/cvscontrol.cpp
@@ -120,14 +120,9 @@ bool CVSControl::vcsAnnotate(const QString &file, int line)
     return true;
 }
 
-bool CVSControl::managesDirectory(const QString &directory) const
+bool CVSControl::managesDirectory(const QString &directory, QString *topLevel) const
 {
-    return m_plugin->managesDirectory(directory);
-}
-
-QString CVSControl::findTopLevelForDirectory(const QString &directory) const
-{
-    return m_plugin->findTopLevelForDirectory(directory);
+    return m_plugin->managesDirectory(directory, topLevel);
 }
 
 void CVSControl::emitRepositoryChanged(const QString &s)
diff --git a/src/plugins/cvs/cvscontrol.h b/src/plugins/cvs/cvscontrol.h
index 38a8ccfe8e73c669d8e7087a1fa9b7648dc4a3b4..4fd06c2de72d1be2df14d4c1474048d3a0aece31 100644
--- a/src/plugins/cvs/cvscontrol.h
+++ b/src/plugins/cvs/cvscontrol.h
@@ -45,8 +45,7 @@ public:
     explicit CVSControl(CVSPlugin *plugin);
     virtual QString displayName() const;
 
-    virtual bool managesDirectory(const QString &directory) const;
-    virtual QString findTopLevelForDirectory(const QString &directory) const;
+    virtual bool managesDirectory(const QString &directory, QString *topLevel = 0) const;
 
     virtual bool supportsOperation(Operation operation) const;
     virtual bool vcsOpen(const QString &fileName);
diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp
index 1f7e646fe1d91c8568898817b50dc6e3826fcbe4..1bdb606be6b1cc2071c2f379a57dd484be06d796 100644
--- a/src/plugins/cvs/cvsplugin.cpp
+++ b/src/plugins/cvs/cvsplugin.cpp
@@ -827,8 +827,10 @@ void CVSPlugin::slotDescribe(const QString &source, const QString &changeNr)
 
 bool CVSPlugin::describe(const QString &file, const QString &changeNr, QString *errorMessage)
 {
-    const QString toplevel = findTopLevelForDirectory(QFileInfo(file).absolutePath());
-    if (toplevel.isEmpty()) {
+
+    QString toplevel;
+    const bool manages = managesDirectory(QFileInfo(file).absolutePath(), &toplevel);
+    if (!manages || toplevel.isEmpty()) {
         *errorMessage = msgCannotFindTopLevel(file);
         return false;
     }
@@ -1122,45 +1124,44 @@ bool CVSPlugin::vcsDelete(const QString &workingDir, const QString &rawFileName)
 
 /* CVS has a "CVS" directory in each directory it manages. The top level
  * is the first directory under the directory that does not have it. */
-bool CVSPlugin::managesDirectory(const QString &directory) const
+bool CVSPlugin::managesDirectory(const QString &directory, QString *topLevel /* = 0 */) const
 {
+    if (topLevel)
+        topLevel->clear();
+    bool manages = false;
     const QDir dir(directory);
-    const bool rc = dir.exists() && managesDirectory(dir);
-    if (CVS::Constants::debug)
-        qDebug() << "CVSPlugin::managesDirectory" << directory << rc;
-    return rc;
+    do {
+        if (!dir.exists() || !checkCVSDirectory(dir))
+            break;
+        manages = true;
+        if (!topLevel)
+            break;
+        /* Recursing up, the top level is a child of the first directory that does
+         * not have a  "CVS" directory. The starting directory must be a managed
+         * one. Go up and try to find the first unmanaged parent dir. */
+        QDir lastDirectory = dir;
+        for (QDir parentDir = lastDirectory; parentDir.cdUp() ; lastDirectory = parentDir) {
+            if (!checkCVSDirectory(parentDir)) {
+                *topLevel = lastDirectory.absolutePath();
+                break;
+            }
+        }
+    } while (false);
+    if (CVS::Constants::debug) {
+        QDebug nsp = qDebug().nospace();
+        nsp << "CVSPlugin::managesDirectory" << directory << manages;
+        if (topLevel)
+            nsp << *topLevel;
+    }
+    return manages;
 }
 
-bool CVSPlugin::managesDirectory(const QDir &directory) const
+bool CVSPlugin::checkCVSDirectory(const QDir &directory) const
 {
     const QString cvsDir = directory.absoluteFilePath(QLatin1String("CVS"));
     return QFileInfo(cvsDir).isDir();
 }
 
-QString CVSPlugin::findTopLevelForDirectory(const QString &directory) const
-{
-    // Debug wrapper
-    const QString rc = findTopLevelForDirectoryI(directory);
-    if (CVS::Constants::debug)
-        qDebug() << "CVSPlugin::findTopLevelForDirectory" << directory << rc;
-    return rc;
-}
-
-QString CVSPlugin::findTopLevelForDirectoryI(const QString &directory) const
-{
-    /* Recursing up, the top level is a child of the first directory that does
-     * not have a  "CVS" directory. The starting directory must be a managed
-     * one. Go up and try to find the first unmanaged parent dir. */
-    QDir lastDirectory = QDir(directory);
-    if (!lastDirectory.exists() || !managesDirectory(lastDirectory))
-        return QString();
-    for (QDir parentDir = lastDirectory; parentDir.cdUp() ; lastDirectory = parentDir) {
-        if (!managesDirectory(parentDir))
-            return lastDirectory.absolutePath();
-    }
-    return QString();
-}
-
 CVSControl *CVSPlugin::cvsVersionControl() const
 {
     return static_cast<CVSControl *>(versionControl());
diff --git a/src/plugins/cvs/cvsplugin.h b/src/plugins/cvs/cvsplugin.h
index 1548729dff11016524e3278650d2be5c54d81bad..c95cb8369f9dc453be65a68ed1c858ddc992fbff 100644
--- a/src/plugins/cvs/cvsplugin.h
+++ b/src/plugins/cvs/cvsplugin.h
@@ -95,8 +95,7 @@ public:
     // IVersionControl
     bool vcsAdd(const QString &workingDir, const QString &fileName);
     bool vcsDelete(const QString &workingDir, const QString &fileName);
-    bool managesDirectory(const QString &directory) const;
-    QString findTopLevelForDirectory(const QString &directory) const;
+    bool managesDirectory(const QString &directory, QString *topLevel = 0) const;
 
     static CVSPlugin *cvsPluginInstance();
 
@@ -145,7 +144,7 @@ private:
     void filelog(const QString &workingDir,
                  const QStringList &files = QStringList(),
                  bool enableAnnotationContextMenu = false);
-    bool managesDirectory(const QDir &directory) const;
+    bool checkCVSDirectory(const QDir &directory) const;
     QString findTopLevelForDirectoryI(const QString &directory) const;
     void startCommit(const QString &workingDir, const QStringList &files = QStringList());
     bool commit(const QString &messageFile, const QStringList &subVersionFileList);
diff --git a/src/plugins/git/gitversioncontrol.cpp b/src/plugins/git/gitversioncontrol.cpp
index 65a46e492e1f701d8fc23810c491114345e6e3ee..370e20bb2704a1ab835183519f4e09126f6a290c 100644
--- a/src/plugins/git/gitversioncontrol.cpp
+++ b/src/plugins/git/gitversioncontrol.cpp
@@ -206,14 +206,12 @@ bool GitVersionControl::vcsRemoveSnapshot(const QString &topLevel, const QString
             && gitClient()->synchronousStashRemove(topLevel, stashName);
 }
 
-bool GitVersionControl::managesDirectory(const QString &directory) const
+bool GitVersionControl::managesDirectory(const QString &directory, QString *topLevel) const
 {
-    return !GitClient::findRepositoryForDirectory(directory).isEmpty();
-}
-
-QString GitVersionControl::findTopLevelForDirectory(const QString &directory) const
-{
-    return GitClient::findRepositoryForDirectory(directory);
+    const QString topLevelFound = GitClient::findRepositoryForDirectory(directory);
+    if (topLevel)
+        *topLevel = topLevelFound;
+    return !topLevelFound.isEmpty();
 }
 
 bool GitVersionControl::vcsAnnotate(const QString &file, int line)
diff --git a/src/plugins/git/gitversioncontrol.h b/src/plugins/git/gitversioncontrol.h
index 098d8bef5282e2922f4c7891f41dc5317b0b618a..35504747a7ca3ecf284cca76ec081b85ee369ca8 100644
--- a/src/plugins/git/gitversioncontrol.h
+++ b/src/plugins/git/gitversioncontrol.h
@@ -46,8 +46,7 @@ public:
 
     virtual QString displayName() const;
 
-    bool managesDirectory(const QString &directory) const;
-    virtual QString findTopLevelForDirectory(const QString &directory) const;
+    virtual bool managesDirectory(const QString &directory, QString *topLevel) const;
 
     virtual bool supportsOperation(Operation operation) const;
     virtual bool vcsOpen(const QString &fileName);
diff --git a/src/plugins/mercurial/mercurialcontrol.cpp b/src/plugins/mercurial/mercurialcontrol.cpp
index e8cf97e1fbd25d241c96f360f18e2d980319f244..61342dc3507b8505d16ff887b6a8c9352c248842 100644
--- a/src/plugins/mercurial/mercurialcontrol.cpp
+++ b/src/plugins/mercurial/mercurialcontrol.cpp
@@ -47,16 +47,13 @@ QString MercurialControl::displayName() const
     return tr("Mercurial");
 }
 
-bool MercurialControl::managesDirectory(const QString &directory) const
+bool MercurialControl::managesDirectory(const QString &directory, QString *topLevel) const
 {
     QFileInfo dir(directory);
-    return !mercurialClient->findTopLevelForFile(dir).isEmpty();
-}
-
-QString MercurialControl::findTopLevelForDirectory(const QString &directory) const
-{
-    QFileInfo dir(directory);
-    return mercurialClient->findTopLevelForFile(dir);
+    const QString topLevelFound = mercurialClient->findTopLevelForFile(dir);
+    if (topLevel)
+        *topLevel = topLevelFound;
+    return !topLevelFound.isEmpty();
 }
 
 bool MercurialControl::supportsOperation(Operation operation) const
@@ -137,8 +134,9 @@ bool MercurialControl::vcsAnnotate(const QString &file, int line)
 bool MercurialControl::sccManaged(const QString &filename)
 {
     const QFileInfo fi(filename);
-    const QString topLevel = findTopLevelForDirectory(fi.absolutePath());
-    if (topLevel.isEmpty())
+    QString topLevel;
+    const bool managed = managesDirectory(fi.absolutePath(), &topLevel);
+    if (!managed || topLevel.isEmpty())
         return false;
     const QDir topLevelDir(topLevel);
     return mercurialClient->manifestSync(topLevel, topLevelDir.relativeFilePath(filename));
diff --git a/src/plugins/mercurial/mercurialcontrol.h b/src/plugins/mercurial/mercurialcontrol.h
index 02be0951bbc16cba7dfa51d66eea3b9c919bbe62..b74fce99ff8fa4a1e53a7c74d0178d8dd5dacfa9 100644
--- a/src/plugins/mercurial/mercurialcontrol.h
+++ b/src/plugins/mercurial/mercurialcontrol.h
@@ -50,8 +50,7 @@ public:
     explicit MercurialControl(MercurialClient *mercurialClient);
 
     QString displayName() const;
-    bool managesDirectory(const QString &filename) const;
-    QString findTopLevelForDirectory(const QString &directory) const;
+    bool managesDirectory(const QString &filename, QString *topLevel = 0) const;
     bool supportsOperation(Operation operation) const;
     bool vcsOpen(const QString &fileName);
     bool vcsAdd(const QString &filename);
diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp
index fefa63b675674f4ce7011bdba8b43d43afd1b471..4a44dc43a5021ac6b8fadddc0f50efdf8dc91bc9 100644
--- a/src/plugins/perforce/perforceplugin.cpp
+++ b/src/plugins/perforce/perforceplugin.cpp
@@ -848,7 +848,20 @@ void PerforcePlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as)
     m_updateAllAction->setEnabled(true);
 }
 
-bool PerforcePlugin::managesDirectory(const QString &directory)
+bool PerforcePlugin::managesDirectory(const QString &directory, QString *topLevel /* = 0 */)
+{
+    const bool rc = managesDirectoryFstat(directory);
+    if (topLevel) {
+        if (rc) {
+            *topLevel = m_settings.topLevelSymLinkTarget();
+        } else {
+            topLevel->clear();
+        }
+    }
+    return rc;
+}
+
+bool PerforcePlugin::managesDirectoryFstat(const QString &directory)
 {
     if (!m_settings.isValid())
         return false;
@@ -875,13 +888,6 @@ bool PerforcePlugin::managesDirectory(const QString &directory)
     return managed;
 }
 
-QString PerforcePlugin::findTopLevelForDirectory(const QString &dir)
-{
-    if (!m_settings.isValid())
-        return QString();
-    return managesDirectory(dir) ? m_settings.topLevelSymLinkTarget() : QString();
-}
-
 bool PerforcePlugin::vcsOpen(const QString &workingDir, const QString &fileName)
 {
     if (Perforce::Constants::debug)
diff --git a/src/plugins/perforce/perforceplugin.h b/src/plugins/perforce/perforceplugin.h
index feddd2bcf6ae883673fc78a700a3a7eda429945b..1e9cceb3ab50d99320cdb0d992b95099f89417b5 100644
--- a/src/plugins/perforce/perforceplugin.h
+++ b/src/plugins/perforce/perforceplugin.h
@@ -84,8 +84,7 @@ public:
     bool initialize(const QStringList &arguments, QString *error_message);
     void extensionsInitialized();
 
-    bool managesDirectory(const QString &directory);
-    QString findTopLevelForDirectory(const QString &directory);
+    bool managesDirectory(const QString &directory, QString *topLevel = 0);
     bool vcsOpen(const QString &workingDir, const QString &fileName);
     bool vcsAdd(const QString &workingDir, const QString &fileName);
     bool vcsDelete(const QString &workingDir, const QString &filename);
@@ -194,6 +193,7 @@ private:
     void updateCheckout(const QString &workingDir = QString(),
                         const QStringList &dirs = QStringList());
     bool revertProject(const QString &workingDir, const QStringList &args, bool unchangedOnly);
+    bool managesDirectoryFstat(const QString &directory);
 
     inline PerforceVersionControl *perforceVersionControl() const;
 
diff --git a/src/plugins/perforce/perforceversioncontrol.cpp b/src/plugins/perforce/perforceversioncontrol.cpp
index e715fa7ec8ace316c10b545ccdae4e366a7f1489..2dc414f59cdb2eca4dbfa74a55436e0c224766de 100644
--- a/src/plugins/perforce/perforceversioncontrol.cpp
+++ b/src/plugins/perforce/perforceversioncontrol.cpp
@@ -120,19 +120,15 @@ bool PerforceVersionControl::vcsAnnotate(const QString &file, int line)
     return true;
 }
 
-bool PerforceVersionControl::managesDirectory(const QString &directory) const
-{
-    const bool rc = m_plugin->managesDirectory(directory);
-    if (Perforce::Constants::debug)
-        qDebug() << "managesDirectory" << directory << rc;
-    return rc;
-}
-
-QString PerforceVersionControl::findTopLevelForDirectory(const QString &directory) const
-{
-    const QString rc = m_plugin->findTopLevelForDirectory(directory);
-    if (Perforce::Constants::debug)
-        qDebug() << "findTopLevelForDirectory" << directory << rc;
+bool PerforceVersionControl::managesDirectory(const QString &directory, QString *topLevel) const
+{
+    const bool rc = m_plugin->managesDirectory(directory, topLevel);
+    if (Perforce::Constants::debug) {
+        QDebug nsp = qDebug().nospace();
+        nsp << "managesDirectory" << directory << rc;
+        if (topLevel)
+            nsp << topLevel;
+    }
     return rc;
 }
 
diff --git a/src/plugins/perforce/perforceversioncontrol.h b/src/plugins/perforce/perforceversioncontrol.h
index 9fe43af676c1b573e58c4c23953bfede19882098..1e14cd2810f2820b1a54ae91ca685afe22b5334a 100644
--- a/src/plugins/perforce/perforceversioncontrol.h
+++ b/src/plugins/perforce/perforceversioncontrol.h
@@ -45,8 +45,8 @@ public:
 
     virtual QString displayName() const;
 
-    bool managesDirectory(const QString &directory) const;
-    virtual QString findTopLevelForDirectory(const QString &directory) const;
+    virtual bool managesDirectory(const QString &directory, QString *topLevel = 0) const;
+
 
     virtual bool supportsOperation(Operation operation) const;
     virtual bool vcsOpen(const QString &fileName);
diff --git a/src/plugins/subversion/subversioncontrol.cpp b/src/plugins/subversion/subversioncontrol.cpp
index f7b4648dcb8f797899687f66f758a0a4d47473d2..f25fc3ab6a2b70ab19357c812024ea7d006523c4 100644
--- a/src/plugins/subversion/subversioncontrol.cpp
+++ b/src/plugins/subversion/subversioncontrol.cpp
@@ -114,14 +114,9 @@ bool SubversionControl::vcsRemoveSnapshot(const QString &, const QString &)
     return false;
 }
 
-bool SubversionControl::managesDirectory(const QString &directory) const
+bool SubversionControl::managesDirectory(const QString &directory, QString *topLevel) const
 {
-    return m_plugin->managesDirectory(directory);
-}
-
-QString SubversionControl::findTopLevelForDirectory(const QString &directory) const
-{
-    return m_plugin->findTopLevelForDirectory(directory);
+    return m_plugin->managesDirectory(directory, topLevel);
 }
 
 bool SubversionControl::vcsAnnotate(const QString &file, int line)
diff --git a/src/plugins/subversion/subversioncontrol.h b/src/plugins/subversion/subversioncontrol.h
index 8389f822495ca6d2ee79a40d26ed537ca52ad96b..5610059d66168f974686d10817e0a18b8cab03c1 100644
--- a/src/plugins/subversion/subversioncontrol.h
+++ b/src/plugins/subversion/subversioncontrol.h
@@ -45,8 +45,7 @@ public:
     explicit SubversionControl(SubversionPlugin *plugin);
     virtual QString displayName() const;
 
-    virtual bool managesDirectory(const QString &directory) const;
-    virtual QString findTopLevelForDirectory(const QString &directory) const;
+    virtual bool managesDirectory(const QString &directory, QString *topLevel = 0) const;
 
     virtual bool supportsOperation(Operation operation) const;
     virtual bool vcsOpen(const QString &fileName);
diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp
index 857bad4731368132e3dd07341e5fb8f7bb2571b9..ff299b1912903f0c62e29bee9f7db3cad34d8dc7 100644
--- a/src/plugins/subversion/subversionplugin.cpp
+++ b/src/plugins/subversion/subversionplugin.cpp
@@ -940,8 +940,9 @@ void SubversionPlugin::describe(const QString &source, const QString &changeNr)
     // To describe a complete change, find the top level and then do
     //svn diff -r 472958:472959 <top level>
     const QFileInfo fi(source);
-    const QString topLevel = findTopLevelForDirectory(fi.isDir() ? source : fi.absolutePath());
-    if (topLevel.isEmpty())
+    QString topLevel;
+    const bool manages = managesDirectory(fi.isDir() ? source : fi.absolutePath(), &topLevel);
+    if (!manages || topLevel.isEmpty())
         return;
     if (Subversion::Constants::debug)
         qDebug() << Q_FUNC_INFO << source << topLevel << changeNr;
@@ -1184,7 +1185,7 @@ bool SubversionPlugin::vcsAdd14(const QString &workingDir, const QString &rawFil
             if (!path.isEmpty())
                 path += slash;
             path += relativePath.at(p);
-            if (!managesDirectory(QDir(path))) {
+            if (!checkSVNSubDir(QDir(path))) {
                 QStringList addDirArgs;
                 addDirArgs << QLatin1String("add") << QLatin1String("--non-recursive") << QDir::toNativeSeparators(path);
                 const SubversionResponse addDirResponse = runSvn(workingDir, addDirArgs, m_settings.timeOutMS(), true);
@@ -1224,16 +1225,40 @@ bool SubversionPlugin::vcsMove(const QString &workingDir, const QString &from, c
 /* Subversion has ".svn" directory in each directory
  * it manages. The top level is the first directory
  * under the directory that does not have a  ".svn". */
-bool SubversionPlugin::managesDirectory(const QString &directory) const
+bool SubversionPlugin::managesDirectory(const QString &directory, QString *topLevel /* = 0 */) const
 {
     const QDir dir(directory);
-    const bool rc = dir.exists() && managesDirectory(dir);
-    if (Subversion::Constants::debug)
-        qDebug() << "SubversionPlugin::managesDirectory" << directory << rc;
-    return rc;
+    if (topLevel)
+        topLevel->clear();
+    bool manages = false;
+    do {
+        if (!dir.exists() || !checkSVNSubDir(dir))
+            break;
+        manages = true;
+        if (!topLevel)
+            break;
+        /* Recursing up, the top level is a child of the first directory that does
+         * not have a  ".svn" directory. The starting directory must be a managed
+         * one. Go up and try to find the first unmanaged parent dir. */
+        QDir lastDirectory = dir;
+        for (QDir parentDir = lastDirectory; parentDir.cdUp() ; lastDirectory = parentDir) {
+            if (!checkSVNSubDir(parentDir)) {
+                *topLevel = lastDirectory.absolutePath();
+                break;
+            }
+        }
+    } while (false);
+    if (Subversion::Constants::debug) {
+        QDebug nsp = qDebug().nospace();
+        nsp << "SubversionPlugin::managesDirectory" << directory << manages;
+        if (topLevel)
+            nsp << *topLevel;
+    }
+    return manages;
 }
 
-bool SubversionPlugin::managesDirectory(const QDir &directory) const
+// Check whether SVN management subdirs exist.
+bool SubversionPlugin::checkSVNSubDir(const QDir &directory) const
 {
     const int dirCount = m_svnDirectories.size();
     for (int i = 0; i < dirCount; i++) {
@@ -1244,30 +1269,6 @@ bool SubversionPlugin::managesDirectory(const QDir &directory) const
     return false;
 }
 
-QString SubversionPlugin::findTopLevelForDirectory(const QString &directory) const
-{
-    // Debug wrapper
-    const QString rc = findTopLevelForDirectoryI(directory);
-    if (Subversion::Constants::debug)
-        qDebug() << "SubversionPlugin::findTopLevelForDirectory" << directory << rc;
-    return rc;
-}
-
-QString SubversionPlugin::findTopLevelForDirectoryI(const QString &directory) const
-{
-    /* Recursing up, the top level is a child of the first directory that does
-     * not have a  ".svn" directory. The starting directory must be a managed
-     * one. Go up and try to find the first unmanaged parent dir. */
-    QDir lastDirectory = QDir(directory);
-    if (!lastDirectory.exists() || !managesDirectory(lastDirectory))
-        return QString();
-    for (QDir parentDir = lastDirectory; parentDir.cdUp() ; lastDirectory = parentDir) {
-        if (!managesDirectory(parentDir))
-            return lastDirectory.absolutePath();
-    }
-    return QString();
-}
-
 SubversionControl *SubversionPlugin::subVersionControl() const
 {
     return static_cast<SubversionControl *>(versionControl());
diff --git a/src/plugins/subversion/subversionplugin.h b/src/plugins/subversion/subversionplugin.h
index a7bb187c56d44f2b95546d1414a246ab6d3671e3..278cb2d30336041a64d82d34a60fcb337594c430 100644
--- a/src/plugins/subversion/subversionplugin.h
+++ b/src/plugins/subversion/subversionplugin.h
@@ -95,8 +95,7 @@ public:
     bool vcsAdd15(const QString &workingDir, const QString &fileName);
     bool vcsDelete(const QString &workingDir, const QString &fileName);
     bool vcsMove(const QString &workingDir, const QString &from, const QString &to);
-    bool managesDirectory(const QString &directory) const;
-    QString findTopLevelForDirectory(const QString &directory) const;
+    bool managesDirectory(const QString &directory, QString *topLevel = 0) const;
 
     static SubversionPlugin *subversionPluginInstance();
 
@@ -145,8 +144,7 @@ private:
                  bool enableAnnotationContextMenu = false);
     void svnStatus(const QString &workingDir, const QStringList &relativePath = QStringList());
     void svnUpdate(const QString &workingDir, const QStringList &relativePaths = QStringList());
-    bool managesDirectory(const QDir &directory) const;
-    QString findTopLevelForDirectoryI(const QString &directory) const;
+    bool checkSVNSubDir(const QDir &directory) const;
     void startCommit(const QString &workingDir, const QStringList &files = QStringList());
     bool commit(const QString &messageFile, const QStringList &subVersionFileList);
     void cleanCommitMessageFile();
diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp
index 67b3e80901bc4ff33952fdba91284d45d929e3bd..815a062247577e3b54652e266ee1d4ad800c99b4 100644
--- a/src/plugins/vcsbase/vcsbaseeditor.cpp
+++ b/src/plugins/vcsbase/vcsbaseeditor.cpp
@@ -821,8 +821,8 @@ QString VCSBaseEditor::findDiffFile(const QString &f, Core::IVersionControl *con
     // Try to locate via repository.
     if (!control)
         return QString();
-    const QString topLevel = control->findTopLevelForDirectory(sourceDir);
-    if (topLevel.isEmpty())
+    QString topLevel;
+    if (!control->managesDirectory(sourceDir, &topLevel))
         return QString();
     const QFileInfo topLevelFileInfo(topLevel + slash + f);
     if (topLevelFileInfo.isFile())