diff --git a/src/plugins/coreplugin/iversioncontrol.h b/src/plugins/coreplugin/iversioncontrol.h
index edaab39fbdbc4a07cb393792494e8f9c993f8c72..f30c348edc4afd6db1a0e0a888590f89cfb84c08 100644
--- a/src/plugins/coreplugin/iversioncontrol.h
+++ b/src/plugins/coreplugin/iversioncontrol.h
@@ -48,13 +48,6 @@ public:
 
     virtual QString name() const = 0;
 
-    virtual bool isEnabled() const = 0;
-
-    /*!
-     * Enable the VCS, that is, make its menu actions visible.
-     */
-    virtual void setEnabled(bool enabled) = 0;
-
     /*!
      * Returns whether files in this directory should be managed with this
      * version control.
diff --git a/src/plugins/coreplugin/vcsmanager.cpp b/src/plugins/coreplugin/vcsmanager.cpp
index e07ba2ff12e6608afb17099d8542b7bbbf96d60b..500454758798bad9ccdf4a0e1b64b8842c371439 100644
--- a/src/plugins/coreplugin/vcsmanager.cpp
+++ b/src/plugins/coreplugin/vcsmanager.cpp
@@ -46,15 +46,18 @@ enum { debug = 0 };
 namespace Core {
 
 typedef QList<IVersionControl *> VersionControlList;
+typedef QMap<QString, IVersionControl *> VersionControlCache;
 
 static inline VersionControlList allVersionControls()
 {
     return ExtensionSystem::PluginManager::instance()->getObjects<IVersionControl>();
 }
 
-// ---- VCSManagerPrivate
+// ---- VCSManagerPrivate:
+// Maintains a cache of top-level directory->version control.
+
 struct VCSManagerPrivate {
-    QMap<QString, IVersionControl *> m_cachedMatches;
+    VersionControlCache m_cachedMatches;
 };
 
 VCSManager::VCSManager(QObject *parent) :
@@ -79,57 +82,48 @@ void VCSManager::extensionsInitialized()
     }
 }
 
-void VCSManager::setVCSEnabled(const QString &directory)
-{
-    if (debug)
-        qDebug() << Q_FUNC_INFO << directory;
-    IVersionControl* managingVCS = findVersionControlForDirectory(directory);
-    const VersionControlList versionControls = allVersionControls();
-    foreach (IVersionControl *versionControl, versionControls) {
-        const bool newEnabled = versionControl == managingVCS;
-        if (newEnabled != versionControl->isEnabled())
-            versionControl->setEnabled(newEnabled);
-    }
-}
-
-void VCSManager::setAllVCSEnabled()
-{
-    if (debug)
-        qDebug() << Q_FUNC_INFO;
-    const VersionControlList versionControls = allVersionControls();
-    foreach (IVersionControl *versionControl, versionControls)
-        if (!versionControl->isEnabled())
-            versionControl->setEnabled(true);
-}
-
-IVersionControl* VCSManager::findVersionControlForDirectory(const QString &directory)
+IVersionControl* VCSManager::findVersionControlForDirectory(const QString &directory,
+                                                            QString *topLevelDirectory)
 {
-    // first look into the cache, check the whole name
-
-    {
-        const QMap<QString, IVersionControl *>::const_iterator it = m_d->m_cachedMatches.constFind(directory);
-        if (it != m_d->m_cachedMatches.constEnd())
-            return it.value();
+    typedef VersionControlCache::const_iterator VersionControlCacheConstIterator;
+    const VersionControlCacheConstIterator cacheEnd = m_d->m_cachedMatches.constEnd();
+
+    if (topLevelDirectory)
+        topLevelDirectory->clear();
+
+    // First check if the directory has an entry, meaning it is a top level
+    const VersionControlCacheConstIterator fullPathIt = m_d->m_cachedMatches.constFind(directory);
+    if (fullPathIt != cacheEnd) {
+        if (topLevelDirectory)
+            *topLevelDirectory = directory;
+        return fullPathIt.value();
     }
 
+    // Split the path, starting from top, try to find the matching repository
     int pos = 0;
     const QChar slash = QLatin1Char('/');
     while (true) {
-        int index = directory.indexOf(slash, pos);
+        const int index = directory.indexOf(slash, pos);
         if (index == -1)
             break;
         const QString directoryPart = directory.left(index);
-        QMap<QString, IVersionControl *>::const_iterator it = m_d->m_cachedMatches.constFind(directoryPart);
-        if (it != m_d->m_cachedMatches.constEnd())
+        const VersionControlCacheConstIterator it = m_d->m_cachedMatches.constFind(directoryPart);
+        if (it != cacheEnd) {
+            if (topLevelDirectory)
+                *topLevelDirectory = it.key();
             return it.value();
-        pos = index+1;
+        }
+        pos = index + 1;
     }
 
-    // ah nothing so ask the IVersionControls directly
+    // Nothing: ask the IVersionControls directly, insert the toplevel into the cache.
     const VersionControlList versionControls = allVersionControls();
     foreach (IVersionControl * versionControl, versionControls) {
         if (versionControl->managesDirectory(directory)) {
-            m_d->m_cachedMatches.insert(versionControl->findTopLevelForDirectory(directory), versionControl);
+            const QString topLevel = versionControl->findTopLevelForDirectory(directory);
+            m_d->m_cachedMatches.insert(topLevel, versionControl);
+            if (topLevelDirectory)
+                *topLevelDirectory = topLevel;
             return versionControl;
         }
     }
@@ -152,4 +146,14 @@ bool VCSManager::showDeleteDialog(const QString &fileName)
     return vc->vcsDelete(fileName);
 }
 
+CORE_EXPORT QDebug operator<<(QDebug in, const VCSManager &v)
+{
+    QDebug nospace = in.nospace();
+    const VersionControlCache::const_iterator cend = v.m_d->m_cachedMatches.constEnd();
+    for (VersionControlCache::const_iterator it = v.m_d->m_cachedMatches.constBegin(); it != cend; ++it)
+        nospace << "Directory: " << it.key() << ' ' << it.value()->name() << '\n';
+    nospace << '\n';
+    return in;
+}
+
 } // namespace Core
diff --git a/src/plugins/coreplugin/vcsmanager.h b/src/plugins/coreplugin/vcsmanager.h
index 772243dd95767278786b0cdc306bdb1a3cbbd600..eb5b67a1b2703c1c4d00483648e92f4eb43d1b56 100644
--- a/src/plugins/coreplugin/vcsmanager.h
+++ b/src/plugins/coreplugin/vcsmanager.h
@@ -35,20 +35,26 @@
 #include <QtCore/QString>
 #include <QtCore/QObject>
 
+QT_BEGIN_NAMESPACE
+class QDebug;
+QT_END_NAMESPACE
+
 namespace Core {
 
 struct VCSManagerPrivate;
 class IVersionControl;
 
-// The VCSManager has only one notable function:
-// findVersionControlFor(), which returns the IVersionControl * for a given
-// filename. Note that the VCSManager assumes that if a IVersionControl *
-// manages a directory, then it also manages all the files and all the
-// subdirectories.
-//
-// It works by asking all IVersionControl * if they manage the file, and ask
-// for the topmost directory it manages. This information is cached and
-// VCSManager thus knows pretty fast which IVersionControl * is responsible.
+/* VCSManager:
+ * 1) Provides functionality for finding the IVersionControl * for a given
+ *    filename (findVersionControlForDirectory). Note that the VCSManager assumes
+ *    that if a IVersionControl * manages a directory, then it also manages
+ *    all the files and all the subdirectories.
+ *    It works by asking all IVersionControl * if they manage the file, and ask
+ *    for the topmost directory it manages. This information is cached and
+ *    VCSManager thus knows pretty fast which IVersionControl * is responsible.
+ * 2) Passes on the changes from the version controls caused by updating or
+ *    branching repositories and routes them to its signals (repositoryChanged,
+ *    filesChanged). */
 
 class CORE_EXPORT VCSManager : public QObject
 {
@@ -60,19 +66,16 @@ public:
 
     void extensionsInitialized();
 
-    IVersionControl *findVersionControlForDirectory(const QString &directory);
-
-    // Enable the VCS managing a certain directory only. This should
-    // be used by project manager classes.
-    void setVCSEnabled(const QString &directory);
-    // Enable all VCS.
-    void setAllVCSEnabled();
+    IVersionControl *findVersionControlForDirectory(const QString &directory,
+                                                    QString *topLevelDirectory = 0);
 
     // Shows a confirmation dialog, whether the file should also be deleted
     // from revision control Calls sccDelete on the file. Returns false
     // if a failure occurs
     bool showDeleteDialog(const QString &fileName);
 
+    friend CORE_EXPORT QDebug operator<<(QDebug in, const VCSManager &);
+
 signals:
     void repositoryChanged(const QString &repository);
     void filesChanged(const QStringList &files);
@@ -81,6 +84,8 @@ private:
     VCSManagerPrivate *m_d;
 };
 
+CORE_EXPORT QDebug operator<<(QDebug in, const VCSManager &);
+
 } // namespace Core
 
 #endif // VCSMANAGER_H
diff --git a/src/plugins/cvs/cvscontrol.cpp b/src/plugins/cvs/cvscontrol.cpp
index 1689f22052798b8bfa1d3d9143bf23cc8baf2c50..01858d771ca6cf6c2e9fa0a02202be268b9b854b 100644
--- a/src/plugins/cvs/cvscontrol.cpp
+++ b/src/plugins/cvs/cvscontrol.cpp
@@ -44,19 +44,6 @@ QString CVSControl::name() const
     return QLatin1String("cvs");
 }
 
-bool CVSControl::isEnabled() const
-{
-     return m_enabled;
-}
-
-void CVSControl::setEnabled(bool enabled)
-{
-    if (m_enabled != enabled) {
-        m_enabled = enabled;
-        emit enabledChanged(m_enabled);
-    }
-}
-
 bool CVSControl::supportsOperation(Operation operation) const
 {
     bool rc = true;
diff --git a/src/plugins/cvs/cvscontrol.h b/src/plugins/cvs/cvscontrol.h
index c6adb7ffa9c019d617186446fd45123affee08aa..0234d16b9578972baaa212083860f4cc465c782b 100644
--- a/src/plugins/cvs/cvscontrol.h
+++ b/src/plugins/cvs/cvscontrol.h
@@ -45,9 +45,6 @@ public:
     explicit CVSControl(CVSPlugin *plugin);
     virtual QString name() const;
 
-    virtual bool isEnabled() const;
-    virtual void setEnabled(bool enabled);
-
     virtual bool managesDirectory(const QString &directory) const;
     virtual QString findTopLevelForDirectory(const QString &directory) const;
 
@@ -59,9 +56,6 @@ public:
     void emitRepositoryChanged(const QString &s);
     void emitFilesChanged(const QStringList &l);
 
-signals:
-    void enabledChanged(bool);
-
 private:
     bool m_enabled;
     CVSPlugin *m_plugin;
diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp
index 5f5849a17a95d5bf458278ceddcc7065d3ce894c..bfa406a39b0f368f75c6cb520eb7793d9d11f518 100644
--- a/src/plugins/cvs/cvsplugin.cpp
+++ b/src/plugins/cvs/cvsplugin.cpp
@@ -151,7 +151,7 @@ Core::IEditor* locateEditor(const char *property, const QString &entry)
 CVSPlugin *CVSPlugin::m_cvsPluginInstance = 0;
 
 CVSPlugin::CVSPlugin() :
-    m_versionControl(0),
+    VCSBase::VCSBasePlugin(QLatin1String(CVS::Constants::CVSCOMMITEDITOR_KIND)),
     m_projectExplorer(0),
     m_addAction(0),
     m_deleteAction(0),
@@ -168,6 +168,7 @@ CVSPlugin::CVSPlugin() :
     m_submitDiffAction(0),
     m_submitUndoAction(0),
     m_submitRedoAction(0),
+    m_menuAction(0),
     m_submitActionTriggered(false)
 {
 }
@@ -205,10 +206,8 @@ static inline Core::Command *createSeparator(QObject *parent,
     return ami->registerAction(tmpaction, id, globalcontext);
 }
 
-bool CVSPlugin::initialize(const QStringList &arguments, QString *errorMessage)
+bool CVSPlugin::initialize(const QStringList & /*arguments */, QString *errorMessage)
 {
-    Q_UNUSED(arguments);
-
     typedef VCSBase::VCSSubmitEditorFactory<CVSSubmitEditor> CVSSubmitEditorFactory;
     typedef VCSBase::VCSEditorFactory<CVSEditor> CVSEditorFactory;
     using namespace Constants;
@@ -216,21 +215,17 @@ bool CVSPlugin::initialize(const QStringList &arguments, QString *errorMessage)
     using namespace Core::Constants;
     using namespace ExtensionSystem;
 
+    VCSBase::VCSBasePlugin::initialize(new CVSControl(this));
+
     m_cvsPluginInstance = this;
     Core::ICore *core = Core::ICore::instance();
 
     if (!core->mimeDatabase()->addMimeTypes(QLatin1String(":/trolltech.cvs/CVS.mimetypes.xml"), errorMessage))
         return false;
 
-
-    m_versionControl = new CVSControl(this);
-    addAutoReleasedObject(m_versionControl);
-
     if (QSettings *settings = core->settings())
         m_settings.fromSettings(settings);
 
-    addAutoReleasedObject(new CoreListener(this));
-
     addAutoReleasedObject(new SettingsPage);
 
     addAutoReleasedObject(new CVSSubmitEditorFactory(&submitParameters));
@@ -250,10 +245,7 @@ bool CVSPlugin::initialize(const QStringList &arguments, QString *errorMessage)
         ami->createMenu(QLatin1String(CMD_ID_CVS_MENU));
     cvsMenu->menu()->setTitle(tr("&CVS"));
     toolsContainer->addMenu(cvsMenu);
-    if (QAction *ma = cvsMenu->menu()->menuAction()) {
-        ma->setEnabled(m_versionControl->isEnabled());
-        connect(m_versionControl, SIGNAL(enabledChanged(bool)), ma, SLOT(setVisible(bool)));
-    }
+    m_menuAction = cvsMenu->menu()->menuAction();
 
     QList<int> globalcontext;
     globalcontext << core->uniqueIDManager()->uniqueIdentifier(C_GLOBAL);
@@ -360,30 +352,21 @@ bool CVSPlugin::initialize(const QStringList &arguments, QString *errorMessage)
 
     m_submitRedoAction = new QAction(tr("&Redo"), this);
     command = ami->registerAction(m_submitRedoAction, Core::Constants::REDO, cvscommitcontext);
-
-    connect(Core::ICore::instance(), SIGNAL(contextChanged(Core::IContext *)), this, SLOT(updateActions()));
-
     return true;
 }
 
 void CVSPlugin::extensionsInitialized()
 {
     m_projectExplorer = ProjectExplorer::ProjectExplorerPlugin::instance();
-    if (m_projectExplorer) {
-        connect(m_projectExplorer,
-            SIGNAL(currentProjectChanged(ProjectExplorer::Project*)),
-            m_cvsPluginInstance, SLOT(updateActions()));
-    }
-    updateActions();
 }
 
-bool CVSPlugin::editorAboutToClose(Core::IEditor *iEditor)
+bool CVSPlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor)
 {
-    if (!iEditor || !isCommitEditorOpen() || qstrcmp(Constants::CVSCOMMITEDITOR, iEditor->kind()))
+    if (!isCommitEditorOpen())
         return true;
 
-    Core::IFile *fileIFace = iEditor->file();
-    const CVSSubmitEditor *editor = qobject_cast<CVSSubmitEditor *>(iEditor);
+    Core::IFile *fileIFace = submitEditor->file();
+    const CVSSubmitEditor *editor = qobject_cast<CVSSubmitEditor *>(submitEditor);
     if (!fileIFace || !editor)
         return true;
 
@@ -488,8 +471,11 @@ CVSSubmitEditor *CVSPlugin::openCVSSubmitEditor(const QString &fileName)
     return submitEditor;
 }
 
-void CVSPlugin::updateActions()
+void CVSPlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as)
 {
+    if (!VCSBase::VCSBasePlugin::enableMenuAction(as, m_menuAction))
+        return;
+
     m_diffProjectAction->setEnabled(true);
     m_commitAllAction->setEnabled(true);
     m_statusAction->setEnabled(true);
@@ -554,7 +540,7 @@ void CVSPlugin::revertCurrentFile()
     const CVSResponse revertResponse = runCVS(args, files, cvsShortTimeOut, true);
     if (revertResponse.result == CVSResponse::Ok) {
         fcb.setModifiedReload(true);
-        m_versionControl->emitFilesChanged(files);
+        cvsVersionControl()->emitFilesChanged(files);
     }
 }
 
@@ -738,7 +724,7 @@ void CVSPlugin::updateProject()
         const CVSResponse response = runCVS(args, topLevels, cvsLongTimeOut, true);
         if (response.result == CVSResponse::Ok)
             foreach(const QString &topLevel, topLevels)
-                m_versionControl->emitRepositoryChanged(topLevel);
+                cvsVersionControl()->emitRepositoryChanged(topLevel);
     }
 }
 
@@ -1193,6 +1179,11 @@ QString CVSPlugin::findTopLevelForDirectoryI(const QString &directory) const
     return QString();
 }
 
+CVSControl *CVSPlugin::cvsVersionControl() const
+{
+    return static_cast<CVSControl *>(versionControl());
+}
+
 }
 }
 Q_EXPORT_PLUGIN(CVS::Internal::CVSPlugin)
diff --git a/src/plugins/cvs/cvsplugin.h b/src/plugins/cvs/cvsplugin.h
index a1515cfc931431761ed10390c824135b8de00394..268c4848afc565adcd393efd382cb6d728d3ebd5 100644
--- a/src/plugins/cvs/cvsplugin.h
+++ b/src/plugins/cvs/cvsplugin.h
@@ -33,8 +33,7 @@
 #include "cvssettings.h"
 #include "cvsutils.h"
 
-#include <coreplugin/icorelistener.h>
-#include <extensionsystem/iplugin.h>
+#include <vcsbase/vcsbaseplugin.h>
 
 QT_BEGIN_NAMESPACE
 class QDir;
@@ -55,6 +54,10 @@ namespace ProjectExplorer {
     class ProjectExplorerPlugin;
 }
 
+namespace VCSBase {
+    class VCSBaseSubmitEditor;
+}
+
 namespace CVS {
 namespace Internal {
 
@@ -80,7 +83,7 @@ struct CVSResponse
  * the diff editor has an additional property specifying the
  * base directory for its interaction to work. */
 
-class CVSPlugin : public ExtensionSystem::IPlugin
+class CVSPlugin : public VCSBase::VCSBasePlugin
 {
     Q_OBJECT
 
@@ -90,7 +93,6 @@ public:
 
     virtual bool initialize(const QStringList &arguments, QString *error_message);
     virtual void extensionsInitialized();
-    virtual bool editorAboutToClose(Core::IEditor *editor);
 
     void cvsDiff(const QStringList &files, QString diffname = QString());
 
@@ -108,7 +110,6 @@ public:
     static CVSPlugin *cvsPluginInstance();
 
 private slots:
-    void updateActions();
     void addCurrentFile();
     void deleteCurrentFile();
     void revertCurrentFile();
@@ -124,6 +125,10 @@ private slots:
     void submitCurrentLog();
     void diffFiles(const QStringList &);
 
+protected:
+    virtual void updateActions(VCSBase::VCSBasePlugin::ActionState);
+    virtual bool submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor);
+
 private:
     bool isCommitEditorOpen() const;
     QString currentFileName() const;
@@ -152,9 +157,9 @@ private:
     void startCommit(const QString &file);
     bool commit(const QString &messageFile, const QStringList &subVersionFileList);
     void cleanCommitMessageFile();
+    inline CVSControl *cvsVersionControl() const;
 
     CVSSettings m_settings;
-    CVSControl *m_versionControl;
     QString m_commitMessageFileName;
 
     ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
@@ -175,32 +180,12 @@ private:
     QAction *m_submitDiffAction;
     QAction *m_submitUndoAction;
     QAction *m_submitRedoAction;
+    QAction *m_menuAction;
     bool    m_submitActionTriggered;
 
     static CVSPlugin *m_cvsPluginInstance;
 };
 
-// Just a proxy for CVSPlugin
-class CoreListener : public Core::ICoreListener
-{
-    Q_OBJECT
-public:
-    CoreListener(CVSPlugin *plugin) : m_plugin(plugin) { }
-
-    // Start commit when submit editor closes
-    bool editorAboutToClose(Core::IEditor *editor) {
-        return m_plugin->editorAboutToClose(editor);
-    }
-
-    // TODO: how to handle that ???
-    bool coreAboutToClose() {
-        return true;
-    }
-
-private:
-    CVSPlugin *m_plugin;
-};
-
 } // namespace CVS
 } // namespace Internal
 
diff --git a/src/plugins/git/changeselectiondialog.cpp b/src/plugins/git/changeselectiondialog.cpp
index 3274ec7ebc7e26f32ffe16378277394dde6adfa3..a99fab61aedf382251a1ee485845bbf11ae7f818 100644
--- a/src/plugins/git/changeselectiondialog.cpp
+++ b/src/plugins/git/changeselectiondialog.cpp
@@ -32,7 +32,8 @@
 #include <QtGui/QFileDialog>
 #include <QtGui/QMessageBox>
 
-using namespace Git::Internal;
+namespace Git {
+namespace Internal {
 
 ChangeSelectionDialog::ChangeSelectionDialog(QWidget *parent)
     : QDialog(parent)
@@ -42,6 +43,21 @@ ChangeSelectionDialog::ChangeSelectionDialog(QWidget *parent)
     setWindowTitle(tr("Select a Git commit"));
 }
 
+QString ChangeSelectionDialog::change() const
+{
+    return m_ui.changeNumberEdit->text();
+}
+
+QString ChangeSelectionDialog::repository() const
+{
+    return m_ui.repositoryEdit->text();
+}
+
+void ChangeSelectionDialog::setRepository(const QString &s)
+{
+    m_ui.repositoryEdit->setText(s);
+}
+
 void ChangeSelectionDialog::selectWorkingDirectory()
 {
     static QString location = QString();
@@ -67,3 +83,6 @@ void ChangeSelectionDialog::selectWorkingDirectory()
                           tr("Selected directory is not a Git repository"));
 
 }
+
+}
+}
diff --git a/src/plugins/git/changeselectiondialog.h b/src/plugins/git/changeselectiondialog.h
index 28330b0a1981995c53d45ce02d2e7f5b79426185..33f8cc6972faf2fc1388cb50640c133bb0efea76 100644
--- a/src/plugins/git/changeselectiondialog.h
+++ b/src/plugins/git/changeselectiondialog.h
@@ -37,21 +37,22 @@
 namespace Git {
 namespace Internal {
 
-class GitPlugin;
-
 class ChangeSelectionDialog : public QDialog
 {
     Q_OBJECT
 public:
     ChangeSelectionDialog(QWidget *parent = 0);
 
+    QString change() const;
+
+    QString repository() const;
+    void setRepository(const QString &s);
+
 public slots:
     void selectWorkingDirectory();
 
-private:
-    friend class GitPlugin;
+private:    
     Ui_ChangeSelectionDialog m_ui;
-
 };
 
 } // namespace Internal
diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
index 486196174af14489508f7d708bca781dfa2f8130..a7fda8a1abcf782ece5fb9eb5181ced0cfcf29a5 100644
--- a/src/plugins/git/gitclient.cpp
+++ b/src/plugins/git/gitclient.cpp
@@ -147,19 +147,6 @@ QString GitClient::findRepositoryForDirectory(const QString &dir)
     return QString();
 }
 
-// Return source file or directory string depending on parameters
-// ('git diff XX' -> 'XX' , 'git diff XX file' -> 'XX/file').
-static QString source(const QString &workingDirectory, const QString &fileName)
-{
-    if (fileName.isEmpty())
-        return workingDirectory;
-    QString rc = workingDirectory;
-    if (!rc.isEmpty() && !rc.endsWith(QDir::separator()))
-        rc += QDir::separator();
-    rc += fileName;
-    return rc;
-}
-
 /* Create an editor associated to VCS output of a source file/directory
  * (using the file's codec). Makes use of a dynamic property to find an
  * existing instance and to reuse it (in case, say, 'git diff foo' is
@@ -253,8 +240,7 @@ void GitClient::diff(const QString &workingDirectory,
 
     const QString kind = QLatin1String(Git::Constants::GIT_DIFF_EDITOR_KIND);
     const QString title = tr("Git Diff %1").arg(fileName);
-    const QString sourceFile = source(workingDirectory, fileName);
-
+    const QString sourceFile = VCSBase::VCSBaseEditor::getSource(workingDirectory, fileName);
     VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, sourceFile, true, "originalFileName", sourceFile);
     executeGit(workingDirectory, arguments, editor);
 }
@@ -267,10 +253,10 @@ void GitClient::status(const QString &workingDirectory)
     executeGit(workingDirectory, statusArgs, 0, true);
 }
 
-void GitClient::log(const QString &workingDirectory, const QString &fileName)
+void GitClient::log(const QString &workingDirectory, const QStringList &fileNames)
 {
     if (Git::Constants::debug)
-        qDebug() << "log" << workingDirectory << fileName;
+        qDebug() << "log" << workingDirectory << fileNames;
 
     QStringList arguments;
     arguments << QLatin1String("log") << QLatin1String(noColorOption);
@@ -278,12 +264,14 @@ void GitClient::log(const QString &workingDirectory, const QString &fileName)
     if (m_settings.logCount > 0)
          arguments << QLatin1String("-n") << QString::number(m_settings.logCount);
 
-    if (!fileName.isEmpty())
-        arguments << fileName;
+    if (!fileNames.isEmpty())
+        arguments.append(fileNames);
 
-    const QString title = tr("Git Log %1").arg(fileName);
+    const QString msgArg = fileNames.empty() ? workingDirectory :
+                           fileNames.join(QString(", "));
+    const QString title = tr("Git Log %1").arg(msgArg);
     const QString kind = QLatin1String(Git::Constants::GIT_LOG_EDITOR_KIND);
-    const QString sourceFile = source(workingDirectory, fileName);
+    const QString sourceFile = VCSBase::VCSBaseEditor::getSource(workingDirectory, fileNames);
     VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, sourceFile, false, "logFileName", sourceFile);
     executeGit(workingDirectory, arguments, editor);
 }
@@ -313,7 +301,7 @@ void GitClient::blame(const QString &workingDirectory, const QString &fileName,
 
     const QString kind = QLatin1String(Git::Constants::GIT_BLAME_EDITOR_KIND);
     const QString title = tr("Git Blame %1").arg(fileName);
-    const QString sourceFile = source(workingDirectory, fileName);
+    const QString sourceFile = VCSBase::VCSBaseEditor::getSource(workingDirectory, fileName);
 
     VCSBase::VCSBaseEditor *editor = createVCSEditor(kind, title, sourceFile, true, "blameFileName", sourceFile);
     executeGit(workingDirectory, arguments, editor, false, GitCommand::NoReport, lineNumber);
@@ -912,7 +900,7 @@ void GitClient::revert(const QStringList &files)
     QString errorMessage;
     switch (revertI(files, &isDirectory, &errorMessage)) {
     case RevertOk:
-        m_plugin->versionControl()->emitFilesChanged(files);
+        m_plugin->gitVersionControl()->emitFilesChanged(files);
         break;
     case RevertCanceled:
         break;
@@ -1020,7 +1008,7 @@ void GitClient::connectRepositoryChanged(const QString & repository, GitCommand
     if (!m_repositoryChangedSignalMapper) {
         m_repositoryChangedSignalMapper = new QSignalMapper(this);
         connect(m_repositoryChangedSignalMapper, SIGNAL(mapped(QString)),
-                m_plugin->versionControl(), SIGNAL(repositoryChanged(QString)));
+                m_plugin->gitVersionControl(), SIGNAL(repositoryChanged(QString)));
     }
     m_repositoryChangedSignalMapper->setMapping(cmd, repository);
     connect(cmd, SIGNAL(success()), m_repositoryChangedSignalMapper, SLOT(map()),
diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h
index 76da31203479171106ff7c997bc1e5a0a6bbea18..ef53fd3ff88f8df3407e71c1874196342b3dfaa2 100644
--- a/src/plugins/git/gitclient.h
+++ b/src/plugins/git/gitclient.h
@@ -79,7 +79,7 @@ public:
               const QStringList &unstagedFileNames, const QStringList &stagedFileNames= QStringList());
 
     void status(const QString &workingDirectory);
-    void log(const QString &workingDirectory, const QString &fileName);
+    void log(const QString &workingDirectory, const QStringList &fileNames);
     void blame(const QString &workingDirectory, const QString &fileName, int lineNumber = -1);
     void showCommit(const QString &workingDirectory, const QString &commit);
     void checkout(const QString &workingDirectory, const QString &file);
diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp
index 6e442bec7f240e3a0f8a5f062cb7421d3d61aa6f..5c0954b263168fd8066b54e29f5a89333c537f16 100644
--- a/src/plugins/git/gitplugin.cpp
+++ b/src/plugins/git/gitplugin.cpp
@@ -56,10 +56,6 @@
 #include <vcsbase/basevcssubmiteditorfactory.h>
 #include <vcsbase/vcsbaseoutputwindow.h>
 
-#include <projectexplorer/projectexplorer.h>
-#include <projectexplorer/project.h>
-#include <projectexplorer/projectnodes.h>
-
 #include <QtCore/QDebug>
 #include <QtCore/QDir>
 #include <QtCore/QFileInfo>
@@ -105,23 +101,16 @@ static inline const VCSBase::VCSBaseEditorParameters *findType(int ie)
 using namespace Git;
 using namespace Git::Internal;
 
-// CoreListener
-
-bool CoreListener::editorAboutToClose(Core::IEditor *editor)
-{
-    return m_plugin->editorAboutToClose(editor);
-}
-
 // GitPlugin
 
 GitPlugin *GitPlugin::m_instance = 0;
 
 GitPlugin::GitPlugin() :
+    VCSBase::VCSBasePlugin(QLatin1String(Git::Constants::GITSUBMITEDITOR_KIND)),
     m_core(0),
     m_diffAction(0),
     m_diffProjectAction(0),
-    m_statusAction(0),
-    m_statusProjectAction(0),
+    m_statusRepositoryAction(0),
     m_logAction(0),
     m_blameAction(0),
     m_logProjectAction(0),
@@ -141,8 +130,8 @@ GitPlugin::GitPlugin() :
     m_stashPopAction(0),
     m_stashListAction(0),
     m_branchListAction(0),
+    m_menuAction(0),
     m_gitClient(0),
-    m_versionControl(0),
     m_changeSelectionDialog(0),
     m_submitActionTriggered(false)
 {
@@ -192,15 +181,17 @@ static Core::Command *createSeparator(Core::ActionManager *am,
 
 bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
 {
+    Q_UNUSED(arguments)
+    Q_UNUSED(errorMessage)
+
     typedef VCSBase::VCSEditorFactory<GitEditor> GitEditorFactory;
     typedef VCSBase::VCSSubmitEditorFactory<GitSubmitEditor> GitSubmitEditorFactory;
 
-    Q_UNUSED(arguments)
-    Q_UNUSED(errorMessage)
+    VCSBase::VCSBasePlugin::initialize(new GitVersionControl(m_gitClient));
 
     m_core = Core::ICore::instance();
     m_gitClient = new GitClient(this);
-    // Create the globalco6664324b12a3339d18251df1cd69a1da06d1e2dcntext list to register actions accordingly
+    // Create the globalcontext list to register actions accordingly
     QList<int> globalcontext;
     globalcontext << m_core->uniqueIDManager()->uniqueIdentifier(Core::Constants::C_GLOBAL);
 
@@ -212,13 +203,7 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
     for (int i = 0; i < editorCount; i++)
         addAutoReleasedObject(new GitEditorFactory(editorParameters + i, m_gitClient, describeSlot));
 
-    addAutoReleasedObject(new CoreListener(this));
-
     addAutoReleasedObject(new GitSubmitEditorFactory(&submitParameters));
-
-    m_versionControl = new GitVersionControl(m_gitClient);
-    addAutoReleasedObject(m_versionControl);
-
     addAutoReleasedObject(new CloneWizard);
     addAutoReleasedObject(new Gitorious::Internal::GitoriousCloneWizard);
 
@@ -232,11 +217,7 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
         actionManager->createMenu(QLatin1String("Git"));
     gitContainer->menu()->setTitle(tr("&Git"));
     toolsContainer->addMenu(gitContainer);
-    if (QAction *ma = gitContainer->menu()->menuAction()) {
-        ma->setEnabled(m_versionControl->isEnabled());
-        connect(m_versionControl, SIGNAL(enabledChanged(bool)), ma, SLOT(setVisible(bool)));
-    }
-
+    m_menuAction = gitContainer->menu()->menuAction();
     Core::Command *command;
 
     m_diffAction = new Utils::ParameterAction(tr("Diff Current File"), tr("Diff \"%1\""), Utils::ParameterAction::AlwaysEnabled, this);
@@ -246,13 +227,6 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
     connect(m_diffAction, SIGNAL(triggered()), this, SLOT(diffCurrentFile()));
     gitContainer->addAction(command);
 
-    m_statusAction = new Utils::ParameterAction(tr("File Status"), tr("Status Related to \"%1\""), Utils::ParameterAction::AlwaysEnabled, this);
-    command = actionManager->registerAction(m_statusAction, "Git.Status", globalcontext);
-    command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+S")));
-    command->setAttribute(Core::Command::CA_UpdateText);
-    connect(m_statusAction, SIGNAL(triggered()), this, SLOT(statusFile()));
-    gitContainer->addAction(command);
-
     m_logAction = new Utils::ParameterAction(tr("Log File"), tr("Log of \"%1\""), Utils::ParameterAction::AlwaysEnabled, this);
     command = actionManager->registerAction(m_logAction, "Git.Log", globalcontext);
     command->setDefaultKeySequence(QKeySequence(tr("Alt+G,Alt+L")));
@@ -296,10 +270,9 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
     connect(m_diffProjectAction, SIGNAL(triggered()), this, SLOT(diffCurrentProject()));
     gitContainer->addAction(command);
 
-    m_statusProjectAction = new Utils::ParameterAction(tr("Project Status"), tr("Status Project \"%1\""), Utils::ParameterAction::AlwaysEnabled, this);
-    command = actionManager->registerAction(m_statusProjectAction, "Git.StatusProject", globalcontext);
-    command->setAttribute(Core::Command::CA_UpdateText);
-    connect(m_statusProjectAction, SIGNAL(triggered()), this, SLOT(statusProject()));
+    m_statusRepositoryAction = new QAction(tr("Repository Status"), this);
+    command = actionManager->registerAction(m_statusRepositoryAction, "Git.StatusRepository", globalcontext);
+    connect(m_statusRepositoryAction, SIGNAL(triggered()), this, SLOT(statusRepository()));
     gitContainer->addAction(command);
 
     m_logProjectAction = new Utils::ParameterAction(tr("Log Project"), tr("Log Project \"%1\""), Utils::ParameterAction::AlwaysEnabled, this);
@@ -386,12 +359,6 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
     m_redoAction = new QAction(tr("&Redo"), this);
     command = actionManager->registerAction(m_redoAction, Core::Constants::REDO, submitContext);
 
-    // Ask for updates of our actions, in case context switches
-    connect(m_core, SIGNAL(contextChanged(Core::IContext *)),
-        this, SLOT(updateActions()));
-    connect(m_core->fileManager(), SIGNAL(currentFileChanged(const QString &)),
-        this, SLOT(updateActions()));
-
     return true;
 }
 
@@ -399,9 +366,9 @@ void GitPlugin::extensionsInitialized()
 {
 }
 
-GitVersionControl *GitPlugin::versionControl() const
+GitVersionControl *GitPlugin::gitVersionControl() const
 {
-    return m_versionControl;
+    return static_cast<GitVersionControl *>(versionControl());
 }
 
 void GitPlugin::submitEditorDiff(const QStringList &unstaged, const QStringList &staged)
@@ -411,127 +378,83 @@ void GitPlugin::submitEditorDiff(const QStringList &unstaged, const QStringList
 
 void GitPlugin::diffCurrentFile()
 {
-    const QFileInfo fileInfo = currentFile();
-    const QString fileName = fileInfo.fileName();
-    const QString workingDirectory = fileInfo.absolutePath();
-    m_gitClient->diff(workingDirectory, QStringList(), fileName);
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasFile(), return)
+    m_gitClient->diff(state.currentFileTopLevel(), QStringList(), state.relativeCurrentFile());
 }
 
 void GitPlugin::diffCurrentProject()
 {
-    QString workingDirectory = getWorkingDirectory();
-    if (workingDirectory.isEmpty())
-        return;
-    m_gitClient->diff(workingDirectory, QStringList(), QString());
-}
-
-QFileInfo GitPlugin::currentFile() const
-{
-    QString fileName = m_core->fileManager()->currentFile();
-    QFileInfo fileInfo(fileName);
-    return fileInfo;
-}
-
-QString GitPlugin::getWorkingDirectory()
-{
-    QString workingDirectory;
-    if (const ProjectExplorer::ProjectExplorerPlugin *p = ProjectExplorer::ProjectExplorerPlugin::instance())
-        if (p && p->currentNode())
-            workingDirectory = QFileInfo(p->currentNode()->path()).absolutePath();
-
-    if (Git::Constants::debug > 1)
-        qDebug() << Q_FUNC_INFO << "Project" << workingDirectory;
-
-    if (workingDirectory.isEmpty())
-        workingDirectory = QFileInfo(m_core->fileManager()->currentFile()).absolutePath();
-    if (Git::Constants::debug > 1)
-        qDebug() << Q_FUNC_INFO << "file" << workingDirectory;
-
-    if (workingDirectory.isEmpty()) {
-        VCSBase::VCSBaseOutputWindow::instance()->appendError(tr("Could not find working directory"));
-        return QString();
-    }
-    return workingDirectory;
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasProject(), return)
+    m_gitClient->diff(state.currentProjectTopLevel(), QStringList(), state.relativeCurrentProject());
 }
 
-void GitPlugin::statusProject()
+void GitPlugin::statusRepository()
 {
-    QString workingDirectory = getWorkingDirectory();
-    if (workingDirectory.isEmpty())
-        return;
-    m_gitClient->status(workingDirectory);
-}
-
-void GitPlugin::statusFile()
-{
-    m_gitClient->status(currentFile().absolutePath());
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
+    m_gitClient->status(state.topLevel());
 }
 
 void GitPlugin::logFile()
 {
-    const QFileInfo fileInfo = currentFile();    
-    const QString fileName = fileInfo.fileName();
-    const QString workingDirectory = fileInfo.absolutePath();
-    m_gitClient->log(workingDirectory, fileName);
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasFile(), return)
+    m_gitClient->log(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()));
 }
 
 void GitPlugin::blameFile()
 {
-    const QFileInfo fileInfo = currentFile();
-    const QString fileName = fileInfo.fileName();
-    const QString workingDirectory = fileInfo.absolutePath();
-
-    m_gitClient->blame(workingDirectory, fileName,
-                       VCSBase::VCSBaseEditor::lineNumberOfCurrentEditor(fileInfo.absoluteFilePath()));
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasFile(), return)
+    const int lineNumber = VCSBase::VCSBaseEditor::lineNumberOfCurrentEditor(state.currentFile());
+    m_gitClient->blame(state.currentFileTopLevel(), state.relativeCurrentFile(), lineNumber);
 }
 
 void GitPlugin::logProject()
 {
-    QString workingDirectory = getWorkingDirectory();
-    if (workingDirectory.isEmpty())
-        return;
-    m_gitClient->log(workingDirectory, QString());
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasProject(), return)
+    m_gitClient->log(state.currentProjectTopLevel(), state.relativeCurrentProject());
 }
 
 void GitPlugin::undoFileChanges()
 {
-    const QFileInfo fileInfo = currentFile();
-    Core::FileChangeBlocker fcb(fileInfo.filePath());
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasFile(), return)
+    Core::FileChangeBlocker fcb(state.currentFile());
     fcb.setModifiedReload(true);
-
-    m_gitClient->revert(QStringList(fileInfo.absoluteFilePath()));
+    m_gitClient->revert(QStringList(state.currentFile()));
 }
 
 void GitPlugin::undoProjectChanges()
 {
-    const QString workingDirectory = getWorkingDirectory();
-    if (workingDirectory.isEmpty())
-        return;
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
+    const QString msg = tr("Would you like to revert all pending changes to the repository\n%1?").arg(state.topLevel());
     const QMessageBox::StandardButton answer
             = QMessageBox::question(m_core->mainWindow(),
-                                    tr("Revert"),
-                                    tr("Would you like to revert all pending changes to the project?"),
+                                    tr("Revert"), msg,
                                     QMessageBox::Yes|QMessageBox::No,
                                     QMessageBox::No);
     if (answer == QMessageBox::No)
         return;
-    m_gitClient->hardReset(workingDirectory, QString());
+    m_gitClient->hardReset(state.topLevel(), QString());
 }
 
 void GitPlugin::stageFile()
 {
-    const QFileInfo fileInfo = currentFile();
-    const QString fileName = fileInfo.fileName();
-    const QString workingDirectory = fileInfo.absolutePath();
-    m_gitClient->addFile(workingDirectory, fileName);
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasFile(), return)
+    m_gitClient->addFile(state.currentFileTopLevel(), state.relativeCurrentFile());
 }
 
 void GitPlugin::unstageFile()
 {
-    const QFileInfo fileInfo = currentFile();
-    const QString fileName = fileInfo.fileName();
-    const QString workingDirectory = fileInfo.absolutePath();
-    m_gitClient->synchronousReset(workingDirectory, QStringList(fileName));
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasFile(), return)
+    m_gitClient->synchronousReset(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()));
 }
 
 void GitPlugin::startCommit()
@@ -543,15 +466,12 @@ void GitPlugin::startCommit()
         return;
     }
 
-    // Find repository and get commit data
-    const QFileInfo currentFileInfo = currentFile();
-    if (!currentFileInfo.exists())
-        return;
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
 
-    const QString workingDirectory = currentFileInfo.absolutePath();
     QString errorMessage, commitTemplate;
     CommitData data;
-    if (!m_gitClient->getCommitData(workingDirectory, &commitTemplate, &data, &errorMessage)) {
+    if (!m_gitClient->getCommitData(state.topLevel(), &commitTemplate, &data, &errorMessage)) {
         VCSBase::VCSBaseOutputWindow::instance()->append(errorMessage);
         return;
     }
@@ -606,13 +526,12 @@ void GitPlugin::submitCurrentLog()
     m_core->editorManager()->closeEditors(editors);
 }
 
-bool GitPlugin::editorAboutToClose(Core::IEditor *iEditor)
+bool GitPlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor)
 {
-    // Closing a submit editor?
-    if (!iEditor || !isCommitEditorOpen() || qstrcmp(iEditor->kind(), Constants::GITSUBMITEDITOR_KIND))
-        return true;
-    Core::IFile *fileIFace = iEditor->file();
-    const GitSubmitEditor *editor = qobject_cast<GitSubmitEditor *>(iEditor);
+    if (!isCommitEditorOpen())
+        return false;
+    Core::IFile *fileIFace = submitEditor->file();
+    const GitSubmitEditor *editor = qobject_cast<GitSubmitEditor *>(submitEditor);
     if (!fileIFace || !editor)
         return true;
     // Submit editor closing. Make it write out the commit message
@@ -668,15 +587,14 @@ bool GitPlugin::editorAboutToClose(Core::IEditor *iEditor)
 
 void GitPlugin::pull()
 {
-    const QString workingDirectory = getWorkingDirectory();
-    if (workingDirectory.isEmpty())
-        return;
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
 
-    switch (m_gitClient->ensureStash(workingDirectory)) {
+    switch (m_gitClient->ensureStash(state.topLevel())) {
         case GitClient::StashUnchanged:
         case GitClient::Stashed:
         case GitClient::NotStashed:
-            m_gitClient->pull(workingDirectory);
+            m_gitClient->pull(state.topLevel());
         default:
         break;
     }
@@ -684,34 +602,33 @@ void GitPlugin::pull()
 
 void GitPlugin::push()
 {
-    const QString workingDirectory = getWorkingDirectory();
-    if (!workingDirectory.isEmpty())
-        m_gitClient->push(workingDirectory);
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
+    m_gitClient->push(state.topLevel());
 }
 
 void GitPlugin::stash()
 {
-    const QString workingDirectory = getWorkingDirectory();
-    if (!workingDirectory.isEmpty())
-        m_gitClient->stash(workingDirectory);
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
+    m_gitClient->stash(state.topLevel());
 }
 
 void GitPlugin::stashPop()
 {
-    const QString workingDirectory = getWorkingDirectory();
-    if (!workingDirectory.isEmpty())
-        m_gitClient->stashPop(workingDirectory);
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
+    m_gitClient->stashPop(state.topLevel());
 }
 
 void GitPlugin::branchList()
 {
-    const QString workingDirectory = getWorkingDirectory();
-    if (workingDirectory.isEmpty())
-        return;
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
     QString errorMessage;
     BranchDialog dialog(m_core->mainWindow());
 
-    if (!dialog.init(m_gitClient, workingDirectory, &errorMessage)) {
+    if (!dialog.init(m_gitClient, state.topLevel(), &errorMessage)) {
         VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
         return;
     }
@@ -720,85 +637,67 @@ void GitPlugin::branchList()
 
 void GitPlugin::stashList()
 {
-    const QString workingDirectory = getWorkingDirectory();
-    if (!workingDirectory.isEmpty())
-        m_gitClient->stashList(workingDirectory);
+    const VCSBase::VCSBasePluginState state = currentState();
+    QTC_ASSERT(state.hasTopLevel(), return)
+    m_gitClient->stashList(state.topLevel());
 }
 
-void GitPlugin::updateActions()
+void GitPlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as)
 {
-    const QFileInfo current = currentFile();
-    const QString fileName = current.fileName();
-    const QString currentDirectory = getWorkingDirectory();
-    const QString repository = m_gitClient->findRepositoryForFile(current.absoluteFilePath());
-    // First check for file commands and if the current file is inside
-    // a Git-repository
+    if (!VCSBase::VCSBasePlugin::enableMenuAction(as, m_menuAction))
+        return;
+
+    const QString fileName = currentState().currentFileName();
     m_diffAction->setParameter(fileName);
-    m_statusAction->setParameter(fileName);
     m_logAction->setParameter(fileName);
     m_blameAction->setParameter(fileName);
     m_undoFileAction->setParameter(fileName);
     m_stageAction->setParameter(fileName);
     m_unstageAction->setParameter(fileName);
 
-    bool enabled = !fileName.isEmpty() && !repository.isEmpty();
-    m_diffAction->setEnabled(enabled);
-    m_statusAction->setEnabled(enabled);
-    m_logAction->setEnabled(enabled);
-    m_blameAction->setEnabled(enabled);
-    m_undoFileAction->setEnabled(enabled);
-    m_stageAction->setEnabled(enabled);
-    m_unstageAction->setEnabled(enabled);
-
-    if (repository.isEmpty()) {
-        // If the file is not in a repository, the corresponding project will
-        // be neither and we can disable everything and return
-        m_diffProjectAction->setEnabled(false);
-        m_diffProjectAction->setParameter(repository);
-        m_statusProjectAction->setParameter(repository);
-        m_statusProjectAction->setEnabled(false);
-        m_logProjectAction->setParameter(repository);
-        m_logProjectAction->setEnabled(false);
-        m_undoProjectAction->setEnabled(false);
-        return;
-    }
+    bool fileEnabled = !fileName.isEmpty();
+    m_diffAction->setEnabled(fileEnabled);
+    m_logAction->setEnabled(fileEnabled);
+    m_blameAction->setEnabled(fileEnabled);
+    m_undoFileAction->setEnabled(fileEnabled);
+    m_stageAction->setEnabled(fileEnabled);
+    m_unstageAction->setEnabled(fileEnabled);
 
-    // We only know the file is in some repository, we do not know
-    // anything about any project so far.
-    QString project;
-    if (const ProjectExplorer::ProjectExplorerPlugin *p = ProjectExplorer::ProjectExplorerPlugin::instance()) {
-        if (const ProjectExplorer::Node *node = p->currentNode())
-            if (const ProjectExplorer::Node *projectNode = node->projectNode())
-                project = QFileInfo(projectNode->path()).completeBaseName();
-    }
+    const QString projectName = currentState().currentProjectName();
+    const bool projectEnabled = !projectName.isEmpty();
+    m_diffProjectAction->setEnabled(projectEnabled);
+    m_diffProjectAction->setParameter(projectName);
+    m_logProjectAction->setEnabled(projectEnabled);
+    m_logProjectAction->setParameter(projectName);
+    m_undoProjectAction->setEnabled(projectEnabled);
+
+    const bool repositoryEnabled = currentState().hasTopLevel();
+    m_statusRepositoryAction->setEnabled(repositoryEnabled);
+    m_branchListAction->setEnabled(repositoryEnabled);
+    m_stashListAction->setEnabled(repositoryEnabled);
+    m_stashPopAction->setEnabled(repositoryEnabled);
 
-    enabled = !project.isEmpty();
-    m_diffProjectAction->setEnabled(enabled);
-    m_diffProjectAction->setParameter(project);
-    m_statusProjectAction->setEnabled(enabled);
-    m_statusProjectAction->setParameter(project);
-    m_logProjectAction->setEnabled(enabled);
-    m_logProjectAction->setParameter(project);
-    m_undoProjectAction->setEnabled(enabled);
+    // Prompts for repo.
+    m_showAction->setEnabled(true);
 }
 
 void GitPlugin::showCommit()
 {
+    const VCSBase::VCSBasePluginState state = currentState();
+
     if (!m_changeSelectionDialog)
         m_changeSelectionDialog = new ChangeSelectionDialog();
 
-    const QFileInfo currentInfo = currentFile();
-    QString repositoryLocation = m_gitClient->findRepositoryForFile(currentInfo.absoluteFilePath());
-    if (!repositoryLocation.isEmpty())
-        m_changeSelectionDialog->m_ui.repositoryEdit->setText(repositoryLocation);
+    if (state.hasTopLevel())
+        m_changeSelectionDialog->setRepository(state.topLevel());
 
     if (m_changeSelectionDialog->exec() != QDialog::Accepted)
         return;
-    const QString change = m_changeSelectionDialog->m_ui.changeNumberEdit->text();
+    const QString change = m_changeSelectionDialog->change();
     if (change.isEmpty())
         return;
 
-    m_gitClient->show(m_changeSelectionDialog->m_ui.repositoryEdit->text(), change);
+    m_gitClient->show(m_changeSelectionDialog->repository(), change);
 }
 
 GitSettings GitPlugin::settings() const
diff --git a/src/plugins/git/gitplugin.h b/src/plugins/git/gitplugin.h
index 0d6ad7fbdd5f412efedb67daf7b1d47c412a4ed6..bd2f6d1af40f344b47a236e8ffa6faf226e4177b 100644
--- a/src/plugins/git/gitplugin.h
+++ b/src/plugins/git/gitplugin.h
@@ -31,9 +31,9 @@
 #define GITPLUGIN_H
 
 #include "settingspage.h"
+#include "vcsbase/vcsbaseplugin.h"
 
 #include <coreplugin/editormanager/ieditorfactory.h>
-#include <coreplugin/icorelistener.h>
 #include <extensionsystem/iplugin.h>
 
 #include <QtCore/QObject>
@@ -49,7 +49,6 @@ QT_END_NAMESPACE
 namespace Core {
 class IEditorFactory;
 class ICore;
-class IVersionControl;
 }
 namespace Utils {
 class ParameterAction;
@@ -66,19 +65,7 @@ class GitSubmitEditor;
 struct CommitData;
 struct GitSettings;
 
-// Just a proxy for GitPlugin
-class CoreListener : public Core::ICoreListener
-{
-    Q_OBJECT
-public:
-    CoreListener(GitPlugin *plugin) : m_plugin(plugin) { }
-    bool editorAboutToClose(Core::IEditor *editor);
-    bool coreAboutToClose() { return true; }
-private:
-    GitPlugin *m_plugin;
-};
-
-class GitPlugin : public ExtensionSystem::IPlugin
+class GitPlugin : public VCSBase::VCSBasePlugin
 {
     Q_OBJECT
 
@@ -91,25 +78,19 @@ public:
     virtual bool initialize(const QStringList &arguments, QString *error_message);
     virtual void extensionsInitialized();
 
-    QString getWorkingDirectory();
+    GitVersionControl *gitVersionControl() const;
 
     GitSettings settings() const;
     void setSettings(const GitSettings &s);
 
-    GitClient *gitClient() const;
-    GitVersionControl *versionControl() const;
-
-public slots:
-    void updateActions();
-    bool editorAboutToClose(Core::IEditor *editor);
+    GitClient *gitClient() const;  
 
 private slots:
     void diffCurrentFile();
     void diffCurrentProject();
     void submitEditorDiff(const QStringList &unstaged, const QStringList &staged);
     void submitCurrentLog();
-    void statusFile();
-    void statusProject();
+    void statusRepository();
     void logFile();
     void blameFile();
     void logProject();
@@ -127,9 +108,12 @@ private slots:
     void pull();
     void push();
 
+protected:
+    virtual void updateActions(VCSBase::VCSBasePlugin::ActionState);
+    virtual bool submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor);
+
 private:
     bool isCommitEditorOpen() const;
-    QFileInfo currentFile() const;
     Core::IEditor *openSubmitEditor(const QString &fileName, const CommitData &cd);
     void cleanCommitMessageFile();
 
@@ -137,8 +121,7 @@ private:
     Core::ICore *m_core;
     Utils::ParameterAction *m_diffAction;
     Utils::ParameterAction *m_diffProjectAction;
-    Utils::ParameterAction *m_statusAction;
-    Utils::ParameterAction *m_statusProjectAction;
+    QAction *m_statusRepositoryAction;
     Utils::ParameterAction *m_logAction;
     Utils::ParameterAction *m_blameAction;
     Utils::ParameterAction *m_logProjectAction;
@@ -159,9 +142,9 @@ private:
     QAction *m_stashPopAction;
     QAction *m_stashListAction;
     QAction *m_branchListAction;
+    QAction *m_menuAction;
 
     GitClient                   *m_gitClient;
-    GitVersionControl           *m_versionControl;
     ChangeSelectionDialog       *m_changeSelectionDialog;
     QString                     m_submitRepository;
     QStringList                 m_submitOrigCommitFiles;
diff --git a/src/plugins/git/gitversioncontrol.cpp b/src/plugins/git/gitversioncontrol.cpp
index c64a683bea0622f92a9ed46e3c3358e3159556f1..e9e8ec96026d466c2d077ea1d943c8fe81d3fc91 100644
--- a/src/plugins/git/gitversioncontrol.cpp
+++ b/src/plugins/git/gitversioncontrol.cpp
@@ -44,19 +44,6 @@ QString GitVersionControl::name() const
     return QLatin1String("git");
 }
 
-bool GitVersionControl::isEnabled() const
-{
-    return m_enabled;
-}
-
-void GitVersionControl::setEnabled(bool enabled)
-{
-    if (m_enabled != enabled) {
-        m_enabled = enabled;
-        emit enabledChanged(m_enabled);
-    }
-}
-
 bool GitVersionControl::supportsOperation(Operation operation) const
 {
     bool rc = false;
diff --git a/src/plugins/git/gitversioncontrol.h b/src/plugins/git/gitversioncontrol.h
index 44598000638800f3ad57de9da892ffff926221e6..fc4c1f7a2fdbd8fb8992b970d1dbcfb5e4e7dd60 100644
--- a/src/plugins/git/gitversioncontrol.h
+++ b/src/plugins/git/gitversioncontrol.h
@@ -46,9 +46,6 @@ public:
 
     virtual QString name() const;
 
-    virtual bool isEnabled() const;
-    virtual void setEnabled(bool enabled);
-
     bool managesDirectory(const QString &directory) const;
     virtual QString findTopLevelForDirectory(const QString &directory) const;
 
diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp
index a80d8f559734d6bb7d8a00230e398ac0974a5cde..8e1e55ea73d4f44b8b492fec03ee738e9b6994b2 100644
--- a/src/plugins/perforce/perforceplugin.cpp
+++ b/src/plugins/perforce/perforceplugin.cpp
@@ -152,15 +152,6 @@ static const char * const CMD_ID_SEPARATOR1 = "Perforce.Separator1";
 static const char * const CMD_ID_SEPARATOR2 = "Perforce.Separator2";
 static const char * const CMD_ID_SEPARATOR3 = "Perforce.Separator3";
 
-////
-// CoreListener
-////
-
-bool CoreListener::editorAboutToClose(Core::IEditor *editor)
-{
-    return m_plugin->editorAboutToClose(editor);
-}
-
 ////
 // PerforcePlugin
 ////
@@ -168,6 +159,7 @@ bool CoreListener::editorAboutToClose(Core::IEditor *editor)
 PerforcePlugin *PerforcePlugin::m_perforcePluginInstance = NULL;
 
 PerforcePlugin::PerforcePlugin() :
+    VCSBase::VCSBasePlugin(QLatin1String(Constants::PERFORCESUBMITEDITOR_KIND)),
     m_editAction(0),
     m_addAction(0),
     m_deleteAction(0),
@@ -190,8 +182,7 @@ PerforcePlugin::PerforcePlugin() :
     m_submitActionTriggered(false),
     m_diffSelectedFiles(0),
     m_undoAction(0),
-    m_redoAction(0),
-    m_versionControl(0)
+    m_redoAction(0)
 {
 }
 
@@ -201,14 +192,13 @@ static const VCSBase::VCSBaseSubmitEditorParameters submitParameters = {
     Perforce::Constants::C_PERFORCESUBMITEDITOR
 };
 
-bool PerforcePlugin::initialize(const QStringList &arguments, QString *errorMessage)
+bool PerforcePlugin::initialize(const QStringList & /* arguments */, QString * errorMessage)
 {
-    Q_UNUSED(arguments)
-    Q_UNUSED(errorMessage)
-
     typedef VCSBase::VCSEditorFactory<PerforceEditor> PerforceEditorFactory;
     typedef VCSBase::VCSSubmitEditorFactory<PerforceSubmitEditor> PerforceSubmitEditorFactory;
 
+    VCSBase::VCSBasePlugin::initialize(new PerforceVersionControl(this));
+
     Core::ICore *core = Core::ICore::instance();
     if (!core->mimeDatabase()->addMimeTypes(QLatin1String(":/trolltech.perforce/Perforce.mimetypes.xml"), errorMessage))
         return false;
@@ -227,11 +217,6 @@ bool PerforcePlugin::initialize(const QStringList &arguments, QString *errorMess
     for (int i = 0; i < editorCount; i++)
         addAutoReleasedObject(new PerforceEditorFactory(editorParameters + i, this, describeSlot));
 
-    m_versionControl = new PerforceVersionControl(this);
-    addAutoReleasedObject(m_versionControl);
-
-    addAutoReleasedObject(new CoreListener(this));
-
     //register actions
     Core::ActionManager *am = Core::ICore::instance()->actionManager();
 
@@ -242,10 +227,7 @@ bool PerforcePlugin::initialize(const QStringList &arguments, QString *errorMess
         am->createMenu(QLatin1String(CMD_ID_PERFORCE_MENU));
     mperforce->menu()->setTitle(tr("&Perforce"));
     mtools->addMenu(mperforce);
-    if (QAction *ma = mperforce->menu()->menuAction()) {
-        ma->setEnabled(m_versionControl->isEnabled());
-        connect(m_versionControl, SIGNAL(enabledChanged(bool)), ma, SLOT(setVisible(bool)));
-    }
+    m_menuAction = mperforce->menu()->menuAction();
 
     QList<int> globalcontext;
     globalcontext << Core::Constants::C_GLOBAL_ID;
@@ -397,24 +379,12 @@ bool PerforcePlugin::initialize(const QStringList &arguments, QString *errorMess
     m_redoAction = new QAction(tr("&Redo"), this);
     command = am->registerAction(m_redoAction, Core::Constants::REDO, perforcesubmitcontext);
 
-    connect(core, SIGNAL(contextChanged(Core::IContext *)),
-        this, SLOT(updateActions()));
-
-    connect(core->fileManager(), SIGNAL(currentFileChanged(const QString &)),
-        this, SLOT(updateActions()));
-
     return true;
 }
 
 void PerforcePlugin::extensionsInitialized()
 {
     m_projectExplorer = ProjectExplorer::ProjectExplorerPlugin::instance();
-    if (m_projectExplorer) {
-        connect(m_projectExplorer,
-            SIGNAL(currentProjectChanged(ProjectExplorer::Project*)),
-            this, SLOT(updateActions()));
-    }
-    updateActions();
 }
 
 void PerforcePlugin::openCurrentFile()
@@ -455,7 +425,7 @@ void PerforcePlugin::revertCurrentFile()
     fcb.setModifiedReload(true);
     PerforceResponse result2 = runP4Cmd(QStringList() << QLatin1String("revert") << fileName, QStringList(), CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
     if (!result2.error)
-        m_versionControl->emitFilesChanged(QStringList(fileName));
+        perforceVersionControl()->emitFilesChanged(QStringList(fileName));
 }
 
 void PerforcePlugin::diffCurrentFile()
@@ -519,7 +489,7 @@ void PerforcePlugin::updateCheckout(const QStringList &dirs)
     const PerforceResponse resp = runP4Cmd(args, QStringList(), CommandToWindow|StdOutToWindow|StdErrToWindow|ErrorToWindow);
     if (!dirs.empty())
         foreach(const QString &dir, dirs)
-            m_versionControl->emitRepositoryChanged(dir);
+            perforceVersionControl()->emitRepositoryChanged(dir);
 }
 
 void PerforcePlugin::printOpenedFileList()
@@ -680,8 +650,11 @@ void PerforcePlugin::filelog(const QString &fileName)
     }
 }
 
-void PerforcePlugin::updateActions()
+void PerforcePlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as)
 {
+    if (!VCSBase::VCSBasePlugin::enableMenuAction(as, m_menuAction))
+        return;
+
     const QString fileName = currentFileName();
     const QString baseName = fileName.isEmpty() ? fileName : QFileInfo(fileName).fileName();
 
@@ -993,19 +966,16 @@ bool PerforcePlugin::isCommitEditorOpen() const
     return !m_commitMessageFileName.isEmpty();
 }
 
-bool PerforcePlugin::editorAboutToClose(Core::IEditor *editor)
+bool PerforcePlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor)
 {
-    if (!editor || !isCommitEditorOpen())
+    if (!isCommitEditorOpen())
         return true;
-    Core::ICore *core = Core::ICore::instance();
-    Core::IFile *fileIFace = editor->file();
-    if (!fileIFace)
-        return true;
-    const PerforceSubmitEditor *perforceEditor = qobject_cast<PerforceSubmitEditor *>(editor);
-    if (!perforceEditor)
+    Core::IFile *fileIFace = submitEditor->file();
+    const PerforceSubmitEditor *perforceEditor = qobject_cast<PerforceSubmitEditor *>(submitEditor);
+    if (!fileIFace || !perforceEditor)
         return true;
-    QFileInfo editorFile(fileIFace->fileName());
-    QFileInfo changeFile(m_commitMessageFileName);
+    const QFileInfo editorFile(fileIFace->fileName());
+    const QFileInfo changeFile(m_commitMessageFileName);
     if (editorFile.absoluteFilePath() == changeFile.absoluteFilePath()) {
         // Prompt the user. Force a prompt unless submit was actually invoked (that
         // is, the editor was closed or shutdown).
@@ -1025,9 +995,10 @@ bool PerforcePlugin::editorAboutToClose(Core::IEditor *editor)
             m_settings.setPromptToSubmit(wantsPrompt);
             m_settings.toSettings(Core::ICore::instance()->settings());
         }
-        core->fileManager()->blockFileChange(fileIFace);
+        Core::FileManager *fileManager = Core::ICore::instance()->fileManager();
+        fileManager->blockFileChange(fileIFace);
         fileIFace->save();
-        core->fileManager()->unblockFileChange(fileIFace);
+        fileManager->unblockFileChange(fileIFace);
         if (answer == VCSBase::VCSBaseSubmitEditor::SubmitConfirmed) {
             QFile commitMessageFile(m_commitMessageFileName);
             if (!commitMessageFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
@@ -1071,7 +1042,7 @@ bool PerforcePlugin::editorAboutToClose(Core::IEditor *editor)
             const QString output = QString::fromLocal8Bit(proc.readAll());
             VCSBase::VCSBaseOutputWindow::instance()->append(output);
             if (output.contains(QLatin1String("Out of date files must be resolved or reverted)"))) {
-                QMessageBox::warning(editor->widget(), tr("Pending change"), tr("Could not submit the change, because your workspace was out of date. Created a pending submit instead."));
+                QMessageBox::warning(submitEditor->widget(), tr("Pending change"), tr("Could not submit the change, because your workspace was out of date. Created a pending submit instead."));
             }
             QApplication::restoreOverrideCursor();
         }
@@ -1219,5 +1190,10 @@ PerforcePlugin *PerforcePlugin::perforcePluginInstance()
     return m_perforcePluginInstance;
 }
 
+PerforceVersionControl *PerforcePlugin::perforceVersionControl() const
+{
+    return static_cast<PerforceVersionControl *>(versionControl());
+}
+
 Q_EXPORT_PLUGIN(PerforcePlugin)
 
diff --git a/src/plugins/perforce/perforceplugin.h b/src/plugins/perforce/perforceplugin.h
index 275903a9c595c60bd56c77465412c1799673c069..2aba09194c0c03df54e4a2bf7733698f468f786b 100644
--- a/src/plugins/perforce/perforceplugin.h
+++ b/src/plugins/perforce/perforceplugin.h
@@ -34,8 +34,7 @@
 
 #include <coreplugin/editormanager/ieditorfactory.h>
 #include <coreplugin/iversioncontrol.h>
-#include <coreplugin/icorelistener.h>
-#include <extensionsystem/iplugin.h>
+#include <vcsbase/vcsbaseplugin.h>
 #include <projectexplorer/projectexplorer.h>
 
 #include <QtCore/QObject>
@@ -56,19 +55,6 @@ namespace Perforce {
 namespace Internal {
 
 class PerforceVersionControl;
-class PerforcePlugin;
-
-// Just a proxy for PerforcePlugin
-class CoreListener : public Core::ICoreListener
-{
-    Q_OBJECT
-public:
-    CoreListener(PerforcePlugin *plugin) : m_plugin(plugin) { }
-    bool editorAboutToClose(Core::IEditor *editor);
-    bool coreAboutToClose() { return true; }
-private:
-    PerforcePlugin *m_plugin;
-};
 
 struct PerforceResponse
 {
@@ -78,7 +64,7 @@ struct PerforceResponse
     QString message;
 };
 
-class PerforcePlugin : public ExtensionSystem::IPlugin
+class PerforcePlugin : public VCSBase::VCSBasePlugin
 {
     Q_OBJECT
 
@@ -94,8 +80,6 @@ public:
     bool vcsOpen(const QString &fileName);
     bool vcsAdd(const QString &fileName);
     bool vcsDelete(const QString &filename);
-    // Displays the message for the submit mesage
-    bool editorAboutToClose(Core::IEditor *editor);
 
     void p4Diff(const QStringList &files, QString diffname = QString());
 
@@ -130,11 +114,14 @@ private slots:
     void filelogCurrentFile();
     void filelog();
 
-    void updateActions();
     void submitCurrentLog();
     void printPendingChanges();
     void slotDiff(const QStringList &files);
 
+protected:
+    virtual void updateActions(VCSBase::VCSBasePlugin::ActionState);
+    virtual bool submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor);
+
 private:
     QStringList environment() const;
 
@@ -163,6 +150,7 @@ private:
     bool isCommitEditorOpen() const;
 
     void updateCheckout(const QStringList &dirs = QStringList());
+    inline PerforceVersionControl *perforceVersionControl() const;
 
     ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
 
@@ -191,12 +179,11 @@ private:
 
     QAction *m_undoAction;
     QAction *m_redoAction;
-
+    QAction *m_menuAction;
 
     static PerforcePlugin *m_perforcePluginInstance;
     QString pendingChangesData();
 
-    PerforceVersionControl *m_versionControl;
     PerforceSettings m_settings;
 };
 
diff --git a/src/plugins/perforce/perforceversioncontrol.cpp b/src/plugins/perforce/perforceversioncontrol.cpp
index ad915b2a2085f42ff63aec3e0da6fd8fc7d1d073..f5424082810328d52e7abcc168b5fb4ce4df4d78 100644
--- a/src/plugins/perforce/perforceversioncontrol.cpp
+++ b/src/plugins/perforce/perforceversioncontrol.cpp
@@ -38,25 +38,12 @@ PerforceVersionControl::PerforceVersionControl(PerforcePlugin *plugin) :
     m_plugin(plugin)
 {
 }
-
+    
 QString PerforceVersionControl::name() const
 {
     return QLatin1String("perforce");
 }
 
-bool PerforceVersionControl::isEnabled() const
-{
-     return m_enabled;
-}
-
-void PerforceVersionControl::setEnabled(bool enabled)
-{
-    if (m_enabled != enabled) {
-        m_enabled = enabled;
-        emit enabledChanged(m_enabled);
-    }
-}
-
 bool PerforceVersionControl::supportsOperation(Operation operation) const
 {
     bool rc = true;
diff --git a/src/plugins/perforce/perforceversioncontrol.h b/src/plugins/perforce/perforceversioncontrol.h
index dd385061cbca5e80267a4ec43f54712381ca94bc..c6f5e1a4d6892b6c2f148697d1195578fc916e10 100644
--- a/src/plugins/perforce/perforceversioncontrol.h
+++ b/src/plugins/perforce/perforceversioncontrol.h
@@ -45,9 +45,6 @@ public:
 
     virtual QString name() const;
 
-    virtual bool isEnabled() const;
-    virtual void setEnabled(bool enabled);
-
     bool managesDirectory(const QString &directory) const;
     virtual QString findTopLevelForDirectory(const QString &directory) const;
 
@@ -59,9 +56,6 @@ public:
     void emitRepositoryChanged(const QString &s);
     void emitFilesChanged(const QStringList &l);
 
-signals:
-    void enabledChanged(bool);
-
 private:
     bool m_enabled;
     PerforcePlugin *m_plugin;
diff --git a/src/plugins/projectexplorer/projectexplorer.cpp b/src/plugins/projectexplorer/projectexplorer.cpp
index c15c303e3aea1fb6e7f621034ee95a4552cd31cd..dd4020baaa16b1ca8e9b077f91ee732f1fd8f2ca 100644
--- a/src/plugins/projectexplorer/projectexplorer.cpp
+++ b/src/plugins/projectexplorer/projectexplorer.cpp
@@ -1323,13 +1323,6 @@ void ProjectExplorerPlugin::setCurrent(Project *project, QString filePath, Node
     if (projectChanged) {
         if (debug)
             qDebug() << "ProjectExplorer - currentProjectChanged(" << (project ? project->name() : "0") << ")";
-        // Enable the right VCS
-        if (const Core::IFile *projectFile = project ? project->file() : static_cast<const Core::IFile *>(0)) {
-            core->vcsManager()->setVCSEnabled(QFileInfo(projectFile->fileName()).absolutePath());
-        } else {
-            core->vcsManager()->setAllVCSEnabled();
-        }
-
         emit currentProjectChanged(project);
         updateActions();
     }
diff --git a/src/plugins/subversion/subversioncontrol.cpp b/src/plugins/subversion/subversioncontrol.cpp
index ff0e0f1c81e872b85872d5990ded86f5089870ac..901b3f115cec7c13f9c5e9cf6cc63b4628948436 100644
--- a/src/plugins/subversion/subversioncontrol.cpp
+++ b/src/plugins/subversion/subversioncontrol.cpp
@@ -44,19 +44,6 @@ QString SubversionControl::name() const
     return QLatin1String("subversion");
 }
 
-bool SubversionControl::isEnabled() const
-{
-     return m_enabled;
-}
-
-void SubversionControl::setEnabled(bool enabled)
-{
-    if (m_enabled != enabled) {
-        m_enabled = enabled;
-        emit enabledChanged(m_enabled);
-    }
-}
-
 bool SubversionControl::supportsOperation(Operation operation) const
 {
     bool rc = true;
diff --git a/src/plugins/subversion/subversioncontrol.h b/src/plugins/subversion/subversioncontrol.h
index 325cfd10989bb9a4cb435d633c2d911125695852..6e1f0d3866116f147a5dacd8107bbe622f588990 100644
--- a/src/plugins/subversion/subversioncontrol.h
+++ b/src/plugins/subversion/subversioncontrol.h
@@ -45,9 +45,6 @@ public:
     explicit SubversionControl(SubversionPlugin *plugin);
     virtual QString name() const;
 
-    virtual bool isEnabled() const;
-    virtual void setEnabled(bool enabled);
-
     virtual bool managesDirectory(const QString &directory) const;
     virtual QString findTopLevelForDirectory(const QString &directory) const;
 
@@ -59,9 +56,6 @@ public:
     void emitRepositoryChanged(const QString &);
     void emitFilesChanged(const QStringList &);
 
-signals:
-    void enabledChanged(bool);
-
 private:
     bool m_enabled;
     SubversionPlugin *m_plugin;
diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp
index 0060e0239535c3ca1edee3e7e6a6675fa2ac1b90..7c479121f2f4d08ca37f353708c30258eefd69fb 100644
--- a/src/plugins/subversion/subversionplugin.cpp
+++ b/src/plugins/subversion/subversionplugin.cpp
@@ -180,8 +180,8 @@ static inline QStringList svnDirectories()
 SubversionPlugin *SubversionPlugin::m_subversionPluginInstance = 0;
 
 SubversionPlugin::SubversionPlugin() :
+    VCSBase::VCSBasePlugin(QLatin1String(Subversion::Constants::SUBVERSIONCOMMITEDITOR_KIND)),
     m_svnDirectories(svnDirectories()),
-    m_versionControl(0),
     m_projectExplorer(0),
     m_addAction(0),
     m_deleteAction(0),
@@ -199,6 +199,7 @@ SubversionPlugin::SubversionPlugin() :
     m_submitDiffAction(0),
     m_submitUndoAction(0),
     m_submitRedoAction(0),
+    m_menuAction(0),
     m_submitActionTriggered(false)
 {
 }
@@ -237,10 +238,8 @@ static inline Core::Command *createSeparator(QObject *parent,
     return ami->registerAction(tmpaction, id, globalcontext);
 }
 
-bool SubversionPlugin::initialize(const QStringList &arguments, QString *errorMessage)
+bool SubversionPlugin::initialize(const QStringList & /*arguments */, QString *errorMessage)
 {
-    Q_UNUSED(arguments)
-
     typedef VCSBase::VCSSubmitEditorFactory<SubversionSubmitEditor> SubversionSubmitEditorFactory;
     typedef VCSBase::VCSEditorFactory<SubversionEditor> SubversionEditorFactory;
     using namespace Constants;
@@ -248,19 +247,17 @@ bool SubversionPlugin::initialize(const QStringList &arguments, QString *errorMe
     using namespace Core::Constants;
     using namespace ExtensionSystem;
 
+    VCSBase::VCSBasePlugin::initialize(new SubversionControl(this));
+
     m_subversionPluginInstance = this;
     Core::ICore *core = Core::ICore::instance();
 
     if (!core->mimeDatabase()->addMimeTypes(QLatin1String(":/trolltech.subversion/Subversion.mimetypes.xml"), errorMessage))
         return false;
 
-    m_versionControl = new SubversionControl(this);
-    addAutoReleasedObject(m_versionControl);
-
     if (QSettings *settings = core->settings())
         m_settings.fromSettings(settings);
 
-    addAutoReleasedObject(new CoreListener(this));
     addAutoReleasedObject(new SettingsPage);
 
     addAutoReleasedObject(new SubversionSubmitEditorFactory(&submitParameters));
@@ -280,11 +277,7 @@ bool SubversionPlugin::initialize(const QStringList &arguments, QString *errorMe
         ami->createMenu(QLatin1String(CMD_ID_SUBVERSION_MENU));
     subversionMenu->menu()->setTitle(tr("&Subversion"));
     toolsContainer->addMenu(subversionMenu);
-    if (QAction *ma = subversionMenu->menu()->menuAction()) {
-        ma->setEnabled(m_versionControl->isEnabled());
-        connect(m_versionControl, SIGNAL(enabledChanged(bool)), ma, SLOT(setVisible(bool)));
-    }
-
+    m_menuAction = subversionMenu->menu()->menuAction();
     QList<int> globalcontext;
     globalcontext << core->uniqueIDManager()->uniqueIdentifier(C_GLOBAL);
 
@@ -396,29 +389,21 @@ bool SubversionPlugin::initialize(const QStringList &arguments, QString *errorMe
     m_submitRedoAction = new QAction(tr("&Redo"), this);
     command = ami->registerAction(m_submitRedoAction, Core::Constants::REDO, svncommitcontext);
 
-    connect(Core::ICore::instance(), SIGNAL(contextChanged(Core::IContext *)), this, SLOT(updateActions()));
-
     return true;
 }
 
 void SubversionPlugin::extensionsInitialized()
 {
     m_projectExplorer = ProjectExplorer::ProjectExplorerPlugin::instance();
-    if (m_projectExplorer) {
-        connect(m_projectExplorer,
-            SIGNAL(currentProjectChanged(ProjectExplorer::Project*)),
-            m_subversionPluginInstance, SLOT(updateActions()));
-    }
-    updateActions();
 }
 
-bool SubversionPlugin::editorAboutToClose(Core::IEditor *iEditor)
+bool SubversionPlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor)
 {
-    if ( !iEditor || !isCommitEditorOpen() || qstrcmp(Constants::SUBVERSIONCOMMITEDITOR, iEditor->kind()))
+    if (!isCommitEditorOpen())
         return true;
 
-    Core::IFile *fileIFace = iEditor->file();
-    const SubversionSubmitEditor *editor = qobject_cast<SubversionSubmitEditor *>(iEditor);
+    Core::IFile *fileIFace = submitEditor->file();
+    const SubversionSubmitEditor *editor = qobject_cast<SubversionSubmitEditor *>(submitEditor);
     if (!fileIFace || !editor)
         return true;
 
@@ -511,8 +496,11 @@ SubversionSubmitEditor *SubversionPlugin::openSubversionSubmitEditor(const QStri
     return submitEditor;
 }
 
-void SubversionPlugin::updateActions()
+void SubversionPlugin::updateActions(VCSBase::VCSBasePlugin::ActionState as)
 {
+    if (!VCSBase::VCSBasePlugin::enableMenuAction(as, m_menuAction))
+        return;
+
     m_diffProjectAction->setEnabled(true);
     m_commitAllAction->setEnabled(true);
     m_statusAction->setEnabled(true);
@@ -574,7 +562,7 @@ void SubversionPlugin::revertCurrentFile()
     const SubversionResponse revertResponse = runSvn(args, subversionShortTimeOut, true);
     if (!revertResponse.error) {
         fcb.setModifiedReload(true);
-        m_versionControl->emitFilesChanged(QStringList(file));
+        subVersionControl()->emitFilesChanged(QStringList(file));
     }
 }
 
@@ -752,9 +740,10 @@ void SubversionPlugin::updateProject()
     args.push_back(QLatin1String(nonInteractiveOptionC));
     args.append(topLevels);
     const SubversionResponse response = runSvn(args, subversionLongTimeOut, true);
-    if (!response.error)
+    if (!response.error) {
         foreach(const QString &repo, topLevels)
-            m_versionControl->emitRepositoryChanged(repo);
+            subVersionControl()->emitRepositoryChanged(repo);
+    }
 }
 
 void SubversionPlugin::annotateCurrentFile()
@@ -1086,4 +1075,9 @@ QString SubversionPlugin::findTopLevelForDirectoryI(const QString &directory) co
     return QString();
 }
 
+SubversionControl *SubversionPlugin::subVersionControl() const
+{
+    return static_cast<SubversionControl *>(versionControl());
+}
+
 Q_EXPORT_PLUGIN(SubversionPlugin)
diff --git a/src/plugins/subversion/subversionplugin.h b/src/plugins/subversion/subversionplugin.h
index 6e3dab7e5d35235893bd2638fc755dfb01077589..0e6450b3ef3f9ccd8449dc1b66ba5563a64baed9 100644
--- a/src/plugins/subversion/subversionplugin.h
+++ b/src/plugins/subversion/subversionplugin.h
@@ -32,8 +32,7 @@
 
 #include "subversionsettings.h"
 
-#include <coreplugin/icorelistener.h>
-#include <extensionsystem/iplugin.h>
+#include <vcsbase/vcsbaseplugin.h>
 
 QT_BEGIN_NAMESPACE
 class QDir;
@@ -43,6 +42,7 @@ QT_END_NAMESPACE
 
 namespace Core {
     class IVersionControl;
+    class IEditor;
 }
 namespace Utils {
     class ParameterAction;
@@ -52,6 +52,10 @@ namespace ProjectExplorer {
     class ProjectExplorerPlugin;
 }
 
+namespace VCSBase {
+    class VCSBaseSubmitEditor;
+}
+
 namespace Subversion {
 namespace Internal {
 
@@ -67,7 +71,7 @@ struct SubversionResponse
     QString message;
 };
 
-class SubversionPlugin : public ExtensionSystem::IPlugin
+class SubversionPlugin : public VCSBase::VCSBasePlugin
 {
     Q_OBJECT
 
@@ -77,7 +81,6 @@ public:
 
     bool initialize(const QStringList &arguments, QString *error_message);
     void extensionsInitialized();
-    bool editorAboutToClose(Core::IEditor *editor);
 
     void svnDiff(const QStringList &files, QString diffname = QString());
 
@@ -95,7 +98,6 @@ public:
     static SubversionPlugin *subversionPluginInstance();
 
 private slots:
-    void updateActions();
     void addCurrentFile();
     void deleteCurrentFile();
     void revertCurrentFile();
@@ -112,6 +114,10 @@ private slots:
     void submitCurrentLog();
     void diffFiles(const QStringList &);
 
+protected:
+    virtual void updateActions(VCSBase::VCSBasePlugin::ActionState);
+    virtual bool submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *submitEditor);
+
 private:
     inline bool isCommitEditorOpen() const;
     QString currentFileName() const;
@@ -128,11 +134,11 @@ private:
     void startCommit(const QStringList &files);
     bool commit(const QString &messageFile, const QStringList &subVersionFileList);
     void cleanCommitMessageFile();
+    inline SubversionControl *subVersionControl() const;
 
     const QStringList m_svnDirectories;
 
     SubversionSettings m_settings;
-    SubversionControl *m_versionControl;
     QString m_commitMessageFileName;
 
     ProjectExplorer::ProjectExplorerPlugin *m_projectExplorer;
@@ -154,32 +160,12 @@ private:
     QAction *m_submitDiffAction;
     QAction *m_submitUndoAction;
     QAction *m_submitRedoAction;
+    QAction *m_menuAction;
     bool    m_submitActionTriggered;
 
     static SubversionPlugin *m_subversionPluginInstance;
 };
 
-// Just a proxy for SubversionPlugin
-class CoreListener : public Core::ICoreListener
-{
-    Q_OBJECT
-public:
-    CoreListener(SubversionPlugin *plugin) : m_plugin(plugin) { }
-
-    // Start commit when submit editor closes
-    bool editorAboutToClose(Core::IEditor *editor) {
-        return m_plugin->editorAboutToClose(editor);
-    }
-
-    // TODO: how to handle that ???
-    bool coreAboutToClose() {
-        return true;
-    }
-
-private:
-    SubversionPlugin *m_plugin;
-};
-
 } // namespace Subversion
 } // namespace Internal
 
diff --git a/src/plugins/vcsbase/basevcseditorfactory.cpp b/src/plugins/vcsbase/basevcseditorfactory.cpp
index 775777e6e0f1b864d7dc7528df202fa418692f18..633d2e172278dc3eb1276feba22f5f2a3ea954dd 100644
--- a/src/plugins/vcsbase/basevcseditorfactory.cpp
+++ b/src/plugins/vcsbase/basevcseditorfactory.cpp
@@ -28,7 +28,6 @@
 **************************************************************************/
 
 #include "basevcseditorfactory.h"
-#include "vcsbaseplugin.h"
 #include "vcsbaseeditor.h"
 
 #include <coreplugin/editormanager/editormanager.h>
diff --git a/src/plugins/vcsbase/vcsbase.pro b/src/plugins/vcsbase/vcsbase.pro
index 45461211b95ec5489af859641f0c200aa3d0c66e..6dec3b25850bf7d8c6a263e6a8d558b15302cdda 100644
--- a/src/plugins/vcsbase/vcsbase.pro
+++ b/src/plugins/vcsbase/vcsbase.pro
@@ -5,6 +5,8 @@ include(../../qtcreatorplugin.pri)
 include(vcsbase_dependencies.pri)
 HEADERS += vcsbase_global.h \
     vcsbaseconstants.h \
+    vcsplugin.h \
+    corelistener.h \
     vcsbaseplugin.h \
     baseannotationhighlighter.h \
     diffhighlighter.h \
@@ -25,7 +27,9 @@ HEADERS += vcsbase_global.h \
     basecheckoutwizardpage.h \
     vcsbaseoutputwindow.h
 
-SOURCES += vcsbaseplugin.cpp \
+SOURCES += vcsplugin.cpp \
+    vcsbaseplugin.cpp \
+    corelistener.cpp \
     baseannotationhighlighter.cpp \
     diffhighlighter.cpp \
     vcsbasetextdocument.cpp \
diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp
index 4536445054bfd337fd0fb0c53d8e099e8dad65a6..abd4287966a1dffa1504a8d872f1d1a2b90b9f12 100644
--- a/src/plugins/vcsbase/vcsbaseeditor.cpp
+++ b/src/plugins/vcsbase/vcsbaseeditor.cpp
@@ -630,5 +630,41 @@ bool VCSBaseEditor::gotoLineOfEditor(Core::IEditor *e, int lineNumber)
     return false;
 }
 
+// Return source file or directory string depending on parameters
+// ('git diff XX' -> 'XX' , 'git diff XX file' -> 'XX/file').
+QString VCSBaseEditor::getSource(const QString &workingDirectory,
+                                 const QString &fileName)
+{
+    if (fileName.isEmpty())
+        return workingDirectory;
+
+    QString rc = workingDirectory;
+    const QChar slash = QLatin1Char('/');
+    if (!rc.isEmpty() && !(rc.endsWith(slash) || rc.endsWith(QLatin1Char('\\'))))
+        rc += slash;
+    rc += fileName;
+    return rc;
+}
+
+QString VCSBaseEditor::getSource(const QString &workingDirectory,
+                                 const QStringList &fileNames)
+{
+    return fileNames.size() == 1 ?
+            getSource(workingDirectory, fileNames.front()) :
+            workingDirectory;
+}
+
+QString VCSBaseEditor::getTitleId(const QString &workingDirectory, const QStringList &fileNames)
+{
+    switch (fileNames.size()) {
+    case 0:
+        return workingDirectory;
+    case 1:
+        return fileNames.front();
+    default:
+        break;
+    }
+    return fileNames.join(QLatin1String(", "));
+}
 
 } // namespace VCSBase
diff --git a/src/plugins/vcsbase/vcsbaseeditor.h b/src/plugins/vcsbase/vcsbaseeditor.h
index 286f950cd62bac88e3b9fc6b80789bd68ff544fd..d272a4cba0c94b46fe720beca778dd880fb57c75 100644
--- a/src/plugins/vcsbase/vcsbaseeditor.h
+++ b/src/plugins/vcsbase/vcsbaseeditor.h
@@ -128,6 +128,15 @@ public:
     //Helper to go to line of editor if it is a text editor
     static bool gotoLineOfEditor(Core::IEditor *e, int lineNumber);
 
+    // Convenience functions to determine the source to pass on to a diff
+    // editor if one has a call consisting of working directory and file arguments.
+    // ('git diff XX' -> 'XX' , 'git diff XX file' -> 'XX/file').
+    static QString getSource(const QString &workingDirectory, const QString &fileName);
+    static QString getSource(const QString &workingDirectory, const QStringList &fileNames);   
+    // Convenience functions to determine an title/id to identify the editor
+    // from the arguments (','-joined arguments or directory).
+    static QString getTitleId(const QString &workingDirectory, const QStringList &fileNames);
+
 signals:
     void describeRequested(const QString &source, const QString &change);
 
diff --git a/src/plugins/vcsbase/vcsbaseplugin.cpp b/src/plugins/vcsbase/vcsbaseplugin.cpp
index 911fc2580c70c2d55335588260ac97b78b1aad95..78c72de5657a20e0c8fc574fd1fd18e6460113ce 100644
--- a/src/plugins/vcsbase/vcsbaseplugin.cpp
+++ b/src/plugins/vcsbase/vcsbaseplugin.cpp
@@ -28,97 +28,420 @@
 **************************************************************************/
 
 #include "vcsbaseplugin.h"
-#include "diffhighlighter.h"
-#include "vcsbasesettingspage.h"
-#include "nicknamedialog.h"
-#include "vcsbaseoutputwindow.h"
+#include "vcsbasesubmiteditor.h"
+#include "vcsplugin.h"
+#include "corelistener.h"
 
 #include <coreplugin/icore.h>
-#include <coreplugin/coreconstants.h>
-#include <coreplugin/uniqueidmanager.h>
-#include <coreplugin/mimedatabase.h>
+#include <coreplugin/ifile.h>
+#include <coreplugin/iversioncontrol.h>
+#include <coreplugin/filemanager.h>
+#include <coreplugin/vcsmanager.h>
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/project.h>
+#include <utils/qtcassert.h>
 
-#include <QtCore/QtPlugin>
 #include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QSharedData>
+
+#include <QtGui/QAction>
+
+enum { debug = 0 };
 
 namespace VCSBase {
+
 namespace Internal {
 
-VCSBasePlugin *VCSBasePlugin::m_instance = 0;
+// Internal state created by the state listener and
+// VCSBasePluginState.
+
+struct State {
+    void clearFile();
+    void clearProject();
+    inline void clear();
+
+    bool equals(const State &rhs) const;
 
-VCSBasePlugin::VCSBasePlugin() :
-    m_settingsPage(0),
-    m_nickNameModel(0)
+    inline bool hasFile() const     { return !currentFile.isEmpty(); }
+    inline bool hasProject() const  { return !currentProjectPath.isEmpty(); }
+    inline bool isEmpty() const     { return !hasFile() && !hasProject(); }
+
+    QString currentFile;
+    QString currentFileName;
+    QString currentFileDirectory;
+    QString currentFileTopLevel;
+
+    QString currentProjectPath;
+    QString currentProjectName;
+    QString currentProjectTopLevel;
+};
+
+void State::clearFile()
 {
-    m_instance = this;
+    currentFile.clear();
+    currentFileName.clear();
+    currentFileDirectory.clear();
+    currentFileTopLevel.clear();
 }
 
-VCSBasePlugin::~VCSBasePlugin()
+void State::clearProject()
 {
-    m_instance = 0;
+    currentProjectPath.clear();
+    currentProjectName.clear();
+    currentProjectTopLevel.clear();
 }
 
-bool VCSBasePlugin::initialize(const QStringList &arguments, QString *errorMessage)
+void State::clear()
 {
-    Q_UNUSED(arguments)
-    Q_UNUSED(errorMessage)
+    clearFile();
+    clearProject();
+}
+
+bool State::equals(const State &rhs) const
+{
+    return currentFile == rhs.currentFile
+            && currentFileName == rhs.currentFileName
+            && currentFileTopLevel == rhs.currentFileTopLevel
+            && currentProjectPath == rhs.currentProjectPath
+            && currentProjectName == rhs.currentProjectName
+            && currentProjectTopLevel == rhs.currentProjectTopLevel;
+}
 
+QDebug operator<<(QDebug in, const State &state)
+{
+    QDebug nospace = in.nospace();
+    nospace << "State: ";
+    if (state.isEmpty()) {
+        nospace << "<empty>";
+    } else {
+        if (state.hasFile()) {
+            nospace << "File=" << state.currentFile
+                    << ',' << state.currentFileTopLevel;
+        } else {
+            nospace << "<no file>";
+        }
+        nospace << '\n';
+        if (state.hasProject()) {
+            nospace << "       Project=" << state.currentProjectName
+            << ',' << state.currentProjectPath
+            << ',' << state.currentProjectTopLevel;
+
+        } else {
+            nospace << "<no project>";
+        }
+        nospace << '\n';
+    }
+    return in;
+}
+
+// StateListener: Connects to the relevant signals, tries to find version
+// controls and emits signals to the plugin instances.
+
+class StateListener : public QObject {
+    Q_OBJECT
+public:
+    explicit StateListener(QObject *parent);
+
+signals:
+    void stateChanged(const VCSBase::Internal::State &s, Core::IVersionControl *vc);
+
+private slots:
+    void slotStateChanged();
+};
+
+StateListener::StateListener(QObject *parent) :
+        QObject(parent)
+{
     Core::ICore *core = Core::ICore::instance();
-    if (!core->mimeDatabase()->addMimeTypes(QLatin1String(":/vcsbase/VCSBase.mimetypes.xml"), errorMessage))
-        return false;
+    connect(core, SIGNAL(contextChanged(Core::IContext *)),
+            this, SLOT(slotStateChanged()));
+    connect(core->fileManager(), SIGNAL(currentFileChanged(QString)),
+            this, SLOT(slotStateChanged()));
 
-    m_settingsPage = new VCSBaseSettingsPage;
-    addAutoReleasedObject(m_settingsPage);
-    addAutoReleasedObject(VCSBaseOutputWindow::instance());
-    connect(m_settingsPage, SIGNAL(settingsChanged(VCSBase::Internal::VCSBaseSettings)),
-            this, SIGNAL(settingsChanged(VCSBase::Internal::VCSBaseSettings)));
-    connect(m_settingsPage, SIGNAL(settingsChanged(VCSBase::Internal::VCSBaseSettings)),
-            this, SLOT(slotSettingsChanged()));
-    slotSettingsChanged();
-    return true;
+    if (ProjectExplorer::ProjectExplorerPlugin *pe = ProjectExplorer::ProjectExplorerPlugin::instance())
+        connect(pe, SIGNAL(currentProjectChanged(ProjectExplorer::Project*)),
+                this, SLOT(slotStateChanged()));
 }
 
-void VCSBasePlugin::extensionsInitialized()
+void StateListener::slotStateChanged()
 {
+    const ProjectExplorer::ProjectExplorerPlugin *pe = ProjectExplorer::ProjectExplorerPlugin::instance();
+    const Core::ICore *core = Core::ICore::instance();
+    Core::VCSManager *vcsManager = core->vcsManager();
+
+    // Get the current file. Are we on a temporary submit editor or something? Ignore.
+    State state;
+    state.currentFile = core->fileManager()->currentFile();
+    if (!state.currentFile.isEmpty() && state.currentFile.startsWith(QDir::tempPath()))
+        state.currentFile.clear();
+    // Get the file and its control. Do not use the file unless we find one
+    Core::IVersionControl *fileControl = 0;
+    if (!state.currentFile.isEmpty()) {
+        const QFileInfo fi(state.currentFile);
+        state.currentFileDirectory = fi.absolutePath();
+        state.currentFileName = fi.fileName();
+        fileControl = vcsManager->findVersionControlForDirectory(state.currentFileDirectory,
+                                                                 &state.currentFileTopLevel);
+        if (!fileControl)
+            state.clearFile();
+    }
+    // Check for project, find the control
+    Core::IVersionControl *projectControl = 0;
+    if (const ProjectExplorer::Project *currentProject = pe->currentProject()) {
+        state.currentProjectPath = QFileInfo(currentProject->file()->fileName()).absolutePath();
+        state.currentProjectName = currentProject->name();
+        projectControl = vcsManager->findVersionControlForDirectory(state.currentProjectPath,
+                                                                    &state.currentProjectTopLevel);
+        if (projectControl) {
+            // If we have both, let the file's one take preference
+            if (fileControl && projectControl != fileControl) {
+                state.clearProject();
+            }
+        } else {
+            state.clearProject(); // No control found
+        }
+    }
+    // Assemble state and emit signal.
+    Core::IVersionControl *vc = state.currentFile.isEmpty() ? projectControl : fileControl;
+    if (debug)
+        qDebug() << state << (vc ? vc->name() : QString(QLatin1String("No version control")));
+    emit stateChanged(state, vc);
 }
 
-VCSBasePlugin *VCSBasePlugin::instance()
+} // namespace Internal
+
+class VCSBasePluginStateData : public QSharedData {
+public:
+    Internal::State m_state;
+};
+
+VCSBasePluginState::VCSBasePluginState() : data(new VCSBasePluginStateData)
 {
-    return m_instance;
 }
 
-VCSBaseSettings VCSBasePlugin::settings() const
+VCSBasePluginState::VCSBasePluginState(const VCSBasePluginState &rhs) : data(rhs.data)
 {
-    return m_settingsPage->settings();
 }
 
-/* Delayed creation/update of the nick name model. */
-QStandardItemModel *VCSBasePlugin::nickNameModel()
+VCSBasePluginState &VCSBasePluginState::operator=(const VCSBasePluginState &rhs)
 {
-    if (!m_nickNameModel) {
-        m_nickNameModel = NickNameDialog::createModel(this);
-        populateNickNameModel();
-    }
-    return m_nickNameModel;
+    if (this != &rhs)
+        data.operator=(rhs.data);
+    return *this;
+}
+
+VCSBasePluginState::~VCSBasePluginState()
+{
+}
+
+QString VCSBasePluginState::currentFile() const
+{
+    return data->m_state.currentFile;
+}
+
+QString VCSBasePluginState::currentFileName() const
+{
+    return data->m_state.currentFileName;
+}
+
+QString VCSBasePluginState::currentFileTopLevel() const
+{
+    return data->m_state.currentFileTopLevel;
+}
+
+QString VCSBasePluginState::currentFileDirectory() const
+{
+    return data->m_state.currentFileDirectory;
+}
+
+QString VCSBasePluginState::relativeCurrentFile() const
+{
+    QTC_ASSERT(hasFile(), return QString())
+    return QDir(data->m_state.currentFileTopLevel).relativeFilePath(data->m_state.currentFile);
+}
+
+QString VCSBasePluginState::currentProjectPath() const
+{
+    return data->m_state.currentProjectPath;
+}
+
+QString VCSBasePluginState::currentProjectName() const
+{
+    return data->m_state.currentProjectName;
+}
+
+QString VCSBasePluginState::currentProjectTopLevel() const
+{
+    return data->m_state.currentProjectTopLevel;
+}
+
+QStringList VCSBasePluginState::relativeCurrentProject() const
+{
+    QStringList rc;
+    QTC_ASSERT(hasProject(), return rc)
+    if (data->m_state.currentProjectTopLevel != data->m_state.currentProjectPath)
+        rc.append(QDir(data->m_state.currentProjectTopLevel).relativeFilePath(data->m_state.currentProjectPath));
+    return rc;
 }
 
-void VCSBasePlugin::populateNickNameModel()
+bool VCSBasePluginState::hasTopLevel() const
 {
-    QString errorMessage;
-    if (!NickNameDialog::populateModelFromMailCapFile(settings().nickNameMailMap,
-                                                      m_nickNameModel,
-                                                      &errorMessage)) {
-            qWarning("%s", qPrintable(errorMessage));
+    return data->m_state.hasFile() || data->m_state.hasProject();
+}
+
+QString VCSBasePluginState::topLevel() const
+{
+    return hasFile() ? data->m_state.currentFileTopLevel : data->m_state.currentProjectTopLevel;
+}
+
+bool VCSBasePluginState::equals(const Internal::State &rhs) const
+{
+    return data->m_state.equals(rhs);
+}
+
+bool VCSBasePluginState::equals(const VCSBasePluginState &rhs) const
+{
+    return equals(rhs.data->m_state);
+}
+
+void VCSBasePluginState::clear()
+{
+    data->m_state.clear();
+}
+
+void VCSBasePluginState::setState(const Internal::State &s)
+{
+    data->m_state = s;
+}
+
+bool VCSBasePluginState::isEmpty() const
+{
+    return data->m_state.isEmpty();
+}
+
+bool VCSBasePluginState::hasFile() const
+{
+    return data->m_state.hasFile();
+}
+
+bool VCSBasePluginState::hasProject() const
+{
+    return data->m_state.hasProject();
+}
+
+VCSBASE_EXPORT QDebug operator<<(QDebug in, const VCSBasePluginState &state)
+{
+    in << state.data->m_state;
+    return in;
+}
+
+//  VCSBasePlugin
+struct VCSBasePluginPrivate {
+    explicit VCSBasePluginPrivate(const QString &submitEditorKind);
+
+    const QString m_submitEditorKind;
+    Core::IVersionControl *m_versionControl;
+    VCSBasePluginState m_state;
+    int m_actionState;
+
+    static Internal::StateListener *m_listener;
+};
+
+VCSBasePluginPrivate::VCSBasePluginPrivate(const QString &submitEditorKind) :
+    m_submitEditorKind(submitEditorKind),
+    m_versionControl(0),
+    m_actionState(-1)
+{
+}
+
+Internal::StateListener *VCSBasePluginPrivate::m_listener = 0;
+
+VCSBasePlugin::VCSBasePlugin(const QString &submitEditorKind) :
+    d(new VCSBasePluginPrivate(submitEditorKind))
+{
+}
+
+VCSBasePlugin::~VCSBasePlugin()
+{
+    delete d;
+}
+
+void VCSBasePlugin::initialize(Core::IVersionControl *vc)
+{
+    d->m_versionControl = vc;
+    addAutoReleasedObject(vc);
+
+    Internal::VCSPlugin *plugin = Internal::VCSPlugin::instance();
+    connect(plugin->coreListener(), SIGNAL(submitEditorAboutToClose(VCSBaseSubmitEditor*,bool*)),
+            this, SLOT(slotSubmitEditorAboutToClose(VCSBaseSubmitEditor*,bool*)));
+    // First time: create new listener
+    if (!VCSBasePluginPrivate::m_listener)
+        VCSBasePluginPrivate::m_listener = new Internal::StateListener(plugin);
+    connect(VCSBasePluginPrivate::m_listener,
+            SIGNAL(stateChanged(VCSBase::Internal::State, Core::IVersionControl*)),
+            this,
+            SLOT(slotStateChanged(VCSBase::Internal::State,Core::IVersionControl*)));
+}
+
+void VCSBasePlugin::slotSubmitEditorAboutToClose(VCSBaseSubmitEditor *submitEditor, bool *result)
+{
+    if (debug)
+        qDebug() << this << d->m_submitEditorKind << "Closing submit editor" << submitEditor << submitEditor->kind();
+    if (submitEditor->kind() == d->m_submitEditorKind)
+        *result = submitEditorAboutToClose(submitEditor);
+}
+
+Core::IVersionControl *VCSBasePlugin::versionControl() const
+{
+    return d->m_versionControl;
+}
+
+void VCSBasePlugin::slotStateChanged(const VCSBase::Internal::State &newInternalState, Core::IVersionControl *vc)
+{
+    if (vc == d->m_versionControl) {
+        // We are directly affected: Change state
+        if (!d->m_state.equals(newInternalState)) {
+            d->m_state.setState(newInternalState);
+            updateActions(VCSEnabled);
         }
+    } else {
+        // Some other VCS plugin or state changed: Reset us to empty state.
+        const ActionState newActionState = vc ? OtherVCSEnabled : NoVCSEnabled;
+        if (d->m_actionState != newActionState || !d->m_state.isEmpty()) {
+            d->m_actionState = newActionState;
+            const VCSBasePluginState emptyState;
+            d->m_state = emptyState;
+            updateActions(newActionState);
+        }
+    }
 }
 
-void VCSBasePlugin::slotSettingsChanged()
+const VCSBasePluginState &VCSBasePlugin::currentState() const
 {
-    if (m_nickNameModel)
-        populateNickNameModel();
+    return d->m_state;
+}
+
+bool VCSBasePlugin::enableMenuAction(ActionState as, QAction *menuAction)
+{
+    if (debug)
+        qDebug() << "enableMenuAction" << menuAction->text() << as;
+    switch (as) {
+    case VCSBase::VCSBasePlugin::NoVCSEnabled:
+        menuAction->setVisible(true);
+        menuAction->setEnabled(false);
+        return false;
+    case VCSBase::VCSBasePlugin::OtherVCSEnabled:
+        menuAction->setVisible(false);
+        return false;
+    case VCSBase::VCSBasePlugin::VCSEnabled:
+        menuAction->setVisible(true);
+        menuAction->setEnabled(true);
+        break;
+    }
+    return true;
 }
 
-} // namespace Internal
 } // namespace VCSBase
 
-Q_EXPORT_PLUGIN(VCSBase::Internal::VCSBasePlugin)
+#include "vcsbaseplugin.moc"
diff --git a/src/plugins/vcsbase/vcsbaseplugin.h b/src/plugins/vcsbase/vcsbaseplugin.h
index 136755955992eedb4b5523e443418943eb6ee1a9..e1d1d9bb618c0e70ba025efb2fe54d763ae22995 100644
--- a/src/plugins/vcsbase/vcsbaseplugin.h
+++ b/src/plugins/vcsbase/vcsbaseplugin.h
@@ -30,56 +30,146 @@
 #ifndef VCSBASEPLUGIN_H
 #define VCSBASEPLUGIN_H
 
+#include "vcsbase_global.h"
+
 #include <extensionsystem/iplugin.h>
 
-#include <QtCore/QObject>
+#include <QSharedDataPointer>
 
 QT_BEGIN_NAMESPACE
-class QStandardItemModel;
+class QAction;
 QT_END_NAMESPACE
 
-namespace VCSBase {
+namespace Core {
+    class IVersionControl;
+}
+
+namespace VCSBase {  
 namespace Internal {
+    struct State;
+}
+
+class VCSBaseSubmitEditor;
+struct VCSBasePluginPrivate;
+class VCSBasePluginStateData;
+class VCSBasePlugin;
+
+/* VCSBasePlugin and VCSBasePluginState: Provide a base class for
+ * VCS plugins. It mainly takes care of maintaining the
+ * VCS-relevant state of Qt Creator which is a tuple of
+ *
+ * 1) Current file    and it's version system control/top level
+ * 2) Current project and it's version system control/top level
+ *
+ * (reflected in VCSBasePluginState). The plugin connects to the
+ * relevant change signals in Qt Creator and calls the virtual
+ * updateActions() for the plugins to update their menu actions
+ * according to the new state. This is done centrally to avoid
+ * single plugins repeatedly invoking searches/QFileInfo on files,
+ * etc.
+ *
+ * If current file/project are managed
+ * by different version controls, the project is discarded and only
+ * the current file is taken into account, allowing to do a diff
+ * also when the project of a file is not opened.
+ *
+ * When triggering an action, a copy of the state should be made to
+ * keep it, as it may rapidly change due to context changes, etc.
+ *
+ * The class also detects the VCS plugin submit editor closing and calls
+ * the virtual submitEditorAboutToClose() to trigger the submit process. */
+
+class VCSBASE_EXPORT VCSBasePluginState
+{
+public:
+    VCSBasePluginState();
+    VCSBasePluginState(const VCSBasePluginState &);
+    VCSBasePluginState &operator=(const VCSBasePluginState &);
+    ~VCSBasePluginState();
+
+    void clear();
+
+    bool isEmpty() const;
+    bool hasFile() const;
+    bool hasProject() const;
+    bool hasTopLevel() const;
+
+    // Current file.
+    QString currentFile() const;
+    QString currentFileName() const;
+    QString currentFileDirectory() const;
+    QString currentFileTopLevel() const;
+    // Convenience: Returns file relative to top level.
+    QString relativeCurrentFile() const;
+
+    // Current project.
+    QString currentProjectPath() const;
+    QString currentProjectName() const;
+    QString currentProjectTopLevel() const;
+    /* Convenience: Returns project path relative to top level if it
+     * differs from top level (else empty()) as an argument list to do
+     * eg a 'vcs diff <args>' */
+    QStringList relativeCurrentProject() const;
+
+    // Top level directory for actions on the top level. Preferably
+    // the file one.
+    QString topLevel() const;
+
+    bool equals(const VCSBasePluginState &rhs) const;
+
+    friend VCSBASE_EXPORT QDebug operator<<(QDebug in, const VCSBasePluginState &state);
 
-struct VCSBaseSettings;
-class VCSBaseSettingsPage;
+private:
+    friend class VCSBasePlugin;
+    bool equals(const Internal::State &s) const;
+    void setState(const Internal::State &s);
 
-class VCSBasePlugin : public ExtensionSystem::IPlugin
+    QSharedDataPointer<VCSBasePluginStateData> data;
+};
+
+VCSBASE_EXPORT QDebug operator<<(QDebug in, const VCSBasePluginState &state);
+
+inline bool operator==(const VCSBasePluginState &s1, const VCSBasePluginState &s2)
+{ return s1.equals(s2); }
+inline bool operator!=(const VCSBasePluginState &s1, const VCSBasePluginState &s2)
+{ return !s1.equals(s2); }
+
+class VCSBASE_EXPORT VCSBasePlugin : public ExtensionSystem::IPlugin
 {
     Q_OBJECT
 
-public:
-    VCSBasePlugin();
-    ~VCSBasePlugin();
+protected:
+    explicit VCSBasePlugin(const QString &submitEditorKind);
 
-    bool initialize(const QStringList &arguments, QString *error_message);
+    void initialize(Core::IVersionControl *vc);
+    Core::IVersionControl *versionControl() const;
 
-    void extensionsInitialized();
+public:   
+    virtual ~VCSBasePlugin();
 
-    static VCSBasePlugin *instance();
+    const VCSBasePluginState &currentState() const;
 
-    VCSBaseSettings settings() const;
+protected:
+    enum ActionState { NoVCSEnabled, OtherVCSEnabled, VCSEnabled };
 
-    // Model of user nick names used for the submit
-    // editor. Stored centrally here to achieve delayed
-    // initialization and updating on settings change.
-    QStandardItemModel *nickNameModel();
+    // Implement to enable the plugin menu actions according to state.
+    virtual void updateActions(ActionState as) = 0;
+    // Implement to start the submit process.   
+    virtual bool submitEditorAboutToClose(VCSBaseSubmitEditor *submitEditor) = 0;
 
-signals:
-    void settingsChanged(const VCSBase::Internal::VCSBaseSettings& s);
+    // A helper to enable the VCS menu action according to state:
+    // NoVCSEnabled->(visible,disabled), OtherVCSEnabled->(invisible), else
+    // enabled. Returns whether actions should be set up further.
+    static bool enableMenuAction(ActionState as, QAction *in);
 
 private slots:
-    void slotSettingsChanged();
+    void slotSubmitEditorAboutToClose(VCSBaseSubmitEditor *submitEditor, bool *result);
+    void slotStateChanged(const VCSBase::Internal::State &s, Core::IVersionControl *vc);
 
 private:
-    void populateNickNameModel();
-
-    static VCSBasePlugin *m_instance;
-    VCSBaseSettingsPage *m_settingsPage;
-    QStandardItemModel *m_nickNameModel;
+    VCSBasePluginPrivate *d;
 };
 
-} // namespace Internal
 } // namespace VCSBase
 
 #endif // VCSBASEPLUGIN_H
diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp
index 82efcb537b528c898924c014756a3d3e36753a3b..dba5cc254180574bbb6c784a1ffe0ae52528a471 100644
--- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp
+++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp
@@ -29,7 +29,7 @@
 
 #include "vcsbasesubmiteditor.h"
 #include "vcsbasesettings.h"
-#include "vcsbaseplugin.h"
+#include "vcsplugin.h"
 #include "nicknamedialog.h"
 #include "submiteditorfile.h"
 
@@ -75,7 +75,7 @@ namespace VCSBase {
 
 static inline QString submitMessageCheckScript()
 {
-    return Internal::VCSBasePlugin::instance()->settings().submitMessageCheckScript;
+    return Internal::VCSPlugin::instance()->settings().submitMessageCheckScript;
 }
 
 struct VCSBaseSubmitEditorPrivate
@@ -127,7 +127,7 @@ VCSBaseSubmitEditor::VCSBaseSubmitEditor(const VCSBaseSubmitEditorParameters *pa
     connect(m_d->m_widget, SIGNAL(diffSelected(QStringList)), this, SLOT(slotDiffSelectedVCSFiles(QStringList)));
     connect(m_d->m_widget->descriptionEdit(), SIGNAL(textChanged()), this, SLOT(slotDescriptionChanged()));
 
-    const Internal::VCSBaseSettings settings = Internal::VCSBasePlugin::instance()->settings();
+    const Internal::VCSBaseSettings settings = Internal::VCSPlugin::instance()->settings();
     // Add additional context menu settings
     if (!settings.submitMessageCheckScript.isEmpty() || !settings.nickNameMailMap.isEmpty()) {
         QAction *sep = new QAction(this);
@@ -152,7 +152,7 @@ VCSBaseSubmitEditor::VCSBaseSubmitEditor(const VCSBaseSubmitEditorParameters *pa
 
     // wrapping. etc
     slotUpdateEditorSettings(settings);
-    connect(Internal::VCSBasePlugin::instance(),
+    connect(Internal::VCSPlugin::instance(),
             SIGNAL(settingsChanged(VCSBase::Internal::VCSBaseSettings)),
             this, SLOT(slotUpdateEditorSettings(VCSBase::Internal::VCSBaseSettings)));
 
@@ -199,7 +199,7 @@ void VCSBaseSubmitEditor::createUserFields(const QString &fieldConfigFile)
     if (fields.empty())
         return;
     // Create a completer on user names
-    const QStandardItemModel *nickNameModel = Internal::VCSBasePlugin::instance()->nickNameModel();
+    const QStandardItemModel *nickNameModel = Internal::VCSPlugin::instance()->nickNameModel();
     QCompleter *completer = new QCompleter(Internal::NickNameDialog::nickNameList(nickNameModel), this);
 
     Utils::SubmitFieldWidget *fieldWidget = new Utils::SubmitFieldWidget;
@@ -487,7 +487,7 @@ VCSBaseSubmitEditor::PromptSubmitResult
 QString VCSBaseSubmitEditor::promptForNickName()
 {
     if (!m_d->m_nickNameDialog)
-        m_d->m_nickNameDialog = new Internal::NickNameDialog(Internal::VCSBasePlugin::instance()->nickNameModel(), m_d->m_widget);
+        m_d->m_nickNameDialog = new Internal::NickNameDialog(Internal::VCSPlugin::instance()->nickNameModel(), m_d->m_widget);
     if (m_d->m_nickNameDialog->exec() == QDialog::Accepted)
        return m_d->m_nickNameDialog->nickName();
     return QString();