diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp
index 2f5ba8ff58f92b5ae9f8335c9f4f32d508c2781a..2e15c6a8cd5dbd5f2aac0771eee440b0db1ca8a3 100644
--- a/src/plugins/mercurial/mercurialclient.cpp
+++ b/src/plugins/mercurial/mercurialclient.cpp
@@ -159,8 +159,116 @@ QString MercurialClient::branchQuerySync(const QString &repositoryRoot)
     return QLatin1String("Unknown Branch");
 }
 
-void MercurialClient::slotAnnotateRevisionRequested(const QString &source, const QString &change, int lineNumber)
+static inline QString msgParentRevisionFailed(const QString &workingDirectory,
+                                              const QString &revision,
+                                              const QString &why)
 {
+    return MercurialClient::tr("Unable to find parent revisions of %1 in %2: %3").arg(revision, workingDirectory, why);
+}
+
+static inline QString msgParseParentsOutputFailed(const QString &output)
+{
+    return MercurialClient::tr("Cannot parse output: %1").arg(output);
+}
+
+bool MercurialClient::parentRevisionsSync(const QString &workingDirectory,
+                                          const QString &file /* = QString() */,
+                                          const QString &revision,
+                                          QStringList *parents)
+{
+    parents->clear();
+    QStringList args;
+    args << QLatin1String("parents") <<  QLatin1String("-r") <<revision;
+    if (!file.isEmpty())
+        args << file;
+    QByteArray outputData;
+    if (!executeHgSynchronously(workingDirectory, args, &outputData))
+        return false;
+    QString output = QString::fromLocal8Bit(outputData);
+    output.remove(QLatin1Char('\r'));
+    /* Looks like: \code
+changeset:   0:031a48610fba
+user: ...
+\endcode   */
+    // Obtain first line and split by blank-delimited tokens
+    VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance();
+    const QStringList lines = output.split(QLatin1Char('\n'));
+    if (lines.size() < 1) {
+        outputWindow->appendSilently(msgParentRevisionFailed(workingDirectory, revision, msgParseParentsOutputFailed(output)));
+        return false;
+    }
+    QStringList changeSets = lines.front().simplified().split(QLatin1Char(' '));
+    if (changeSets.size() < 2) {
+        outputWindow->appendSilently(msgParentRevisionFailed(workingDirectory, revision, msgParseParentsOutputFailed(output)));
+        return false;
+    }
+    // Remove revision numbers
+    const QChar colon = QLatin1Char(':');
+    const QStringList::iterator end = changeSets.end();
+    QStringList::iterator it = changeSets.begin();
+    for (++it; it != end; ++it) {
+        const int colonIndex = it->indexOf(colon);
+        if (colonIndex != -1)
+            parents->push_back(it->mid(colonIndex + 1));
+    }
+    return true;
+}
+
+// Describe a change using an optional format
+bool MercurialClient::shortDescriptionSync(const QString &workingDirectory,
+                                           const QString &revision,
+                                           const QString &format,
+                                           QString *description)
+{
+    description->clear();
+    QStringList args;
+    args << QLatin1String("log") <<  QLatin1String("-r") <<revision;
+    if (!format.isEmpty())
+        args << QLatin1String("--template") << format;
+    QByteArray outputData;
+    if (!executeHgSynchronously(workingDirectory, args, &outputData))
+        return false;
+    *description = QString::fromLocal8Bit(outputData);
+    description->remove(QLatin1Char('\r'));
+    if (description->endsWith(QLatin1Char('\n')))
+        description->truncate(description->size() - 1);
+    return true;
+}
+
+// Default format: "SHA1 (author summmary)"
+static const char defaultFormatC[] = "{node} ({author|person} {desc|firstline})";
+
+bool MercurialClient::shortDescriptionSync(const QString &workingDirectory,
+                                           const QString &revision,
+                                           QString *description)
+{
+    if (!shortDescriptionSync(workingDirectory, revision, QLatin1String(defaultFormatC), description))
+        return false;
+    description->remove(QLatin1Char('\n'));
+    return true;
+}
+
+// Convenience to format a list of changes
+bool MercurialClient::shortDescriptionsSync(const QString &workingDirectory, const QStringList &revisions,
+                                            QStringList *descriptions)
+{
+    descriptions->clear();
+    foreach(const QString &revision, revisions) {
+        QString description;
+        if (!shortDescriptionSync(workingDirectory, revision, &description))
+            return false;
+        descriptions->push_back(description);
+    }
+    return true;
+}
+
+void MercurialClient::slotAnnotateRevisionRequested(const QString &source, QString change, int lineNumber)
+{
+    // This might be invoked with a verbose revision description
+    // "SHA1 author subject" from the annotation context menu. Strip the rest.
+    const int blankPos = change.indexOf(QLatin1Char(' '));
+    if (blankPos != -1)
+        change.truncate(blankPos);
     const QFileInfo fi(source);
     annotate(fi.absolutePath(), fi.fileName(), change, lineNumber);
 }
diff --git a/src/plugins/mercurial/mercurialclient.h b/src/plugins/mercurial/mercurialclient.h
index 0a59b83a1d32c8c0f749c88612f708816608faa8..53fc0e58d0c135f10567746d4ceb99c451a510dc 100644
--- a/src/plugins/mercurial/mercurialclient.h
+++ b/src/plugins/mercurial/mercurialclient.h
@@ -64,6 +64,16 @@ public:
     bool remove(const QString &workingDir, const QString &fileName);
     bool manifestSync(const QString &repository, const QString &filename);
     QString branchQuerySync(const QString &repositoryRoot);
+    bool parentRevisionsSync(const QString &workingDirectory,
+                             const QString &file /* = QString() */,
+                             const QString &revision,
+                             QStringList *parents);
+    bool shortDescriptionSync(const QString &workingDirectory, const QString &revision,
+                              const QString &format /* = QString() */, QString *description);
+    bool shortDescriptionSync(const QString &workingDirectory, const QString &revision,
+                              QString *description);
+    bool shortDescriptionsSync(const QString &workingDirectory, const QStringList &revisions,
+                              QStringList *descriptions);
     void annotate(const QString &workingDir, const QString &files,
                   const QString revision = QString(), int lineNumber = -1);
     void diff(const QString &workingDir, const QStringList &files = QStringList());
@@ -95,7 +105,7 @@ public slots:
 
 private slots:
     void statusParser(const QByteArray &data);
-    void slotAnnotateRevisionRequested(const QString &source, const QString &change, int lineNumber);
+    void slotAnnotateRevisionRequested(const QString &source, QString change, int lineNumber);
 
 private:
     bool executeHgSynchronously(const QString  &workingDir,
diff --git a/src/plugins/mercurial/mercurialeditor.cpp b/src/plugins/mercurial/mercurialeditor.cpp
index 9315c3dad237720fe8f663818b068b73302dd8b9..e38d30b886ebc777a625a4a85308e624d71b39f1 100644
--- a/src/plugins/mercurial/mercurialeditor.cpp
+++ b/src/plugins/mercurial/mercurialeditor.cpp
@@ -31,6 +31,7 @@
 #include "annotationhighlighter.h"
 #include "constants.h"
 #include "mercurialplugin.h"
+#include "mercurialclient.h"
 
 #include <coreplugin/editormanager/editormanager.h>
 #include <vcsbase/diffhighlighter.h>
@@ -53,6 +54,7 @@ MercurialEditor::MercurialEditor(const VCSBase::VCSBaseEditorParameters *type, Q
         changesetIdentifier40(QLatin1String(Constants::CHANGESETID40)),
         diffIdentifier(QLatin1String(Constants::DIFFIDENTIFIER))
 {
+    setAnnotateRevisionTextFormat(tr("Annotate %1"));
 }
 
 QSet<QString> MercurialEditor::annotationChanges() const
@@ -110,3 +112,21 @@ QString MercurialEditor::fileNameFromDiffSpecification(const QTextBlock &diffFil
     }
     return QString();
 }
+
+QStringList MercurialEditor::annotationPreviousVersions(const QString &revision) const
+{
+    MercurialClient *client = MercurialPlugin::instance()->client();
+    QStringList parents;
+    const QFileInfo fi(source());
+    const QString workingDirectory = fi.absolutePath();
+    // Retrieve parent revisions
+    QStringList revisions;
+    if (!client->parentRevisionsSync(workingDirectory, fi.fileName(), revision, &revisions))
+        return QStringList();
+    // Format with short summary
+    QStringList descriptions;
+    if (!client->shortDescriptionsSync(workingDirectory, revisions, &descriptions))
+        return QStringList();
+    return descriptions;
+}
+
diff --git a/src/plugins/mercurial/mercurialeditor.h b/src/plugins/mercurial/mercurialeditor.h
index ac5c3573387164b21c28280da5f6f5ec85229906..c74e6e48c865c710727998f2c179ef6d66da25e0 100644
--- a/src/plugins/mercurial/mercurialeditor.h
+++ b/src/plugins/mercurial/mercurialeditor.h
@@ -48,6 +48,7 @@ private:
     virtual VCSBase::DiffHighlighter *createDiffHighlighter() const;
     virtual VCSBase::BaseAnnotationHighlighter *createAnnotationHighlighter(const QSet<QString> &changes) const;
     virtual QString fileNameFromDiffSpecification(const QTextBlock &diffFileSpec) const;
+    virtual QStringList annotationPreviousVersions(const QString &revision) const;
 
     const QRegExp exactIdentifier12;
     const QRegExp exactIdentifier40;
diff --git a/src/plugins/mercurial/mercurialplugin.cpp b/src/plugins/mercurial/mercurialplugin.cpp
index c9eb4ba34454b7bb48ef55cddc64e846b25c850f..29c9f0f8d24795e58657a96da3fee36b8c57b803 100644
--- a/src/plugins/mercurial/mercurialplugin.cpp
+++ b/src/plugins/mercurial/mercurialplugin.cpp
@@ -117,7 +117,7 @@ MercurialPlugin *MercurialPlugin::m_instance = 0;
 MercurialPlugin::MercurialPlugin() :
         VCSBase::VCSBasePlugin(QLatin1String(Constants::COMMITKIND)),
         optionsPage(0),
-        client(0),
+        m_client(0),
         changeLog(0),
         m_menuAction(0)
 {
@@ -126,9 +126,9 @@ MercurialPlugin::MercurialPlugin() :
 
 MercurialPlugin::~MercurialPlugin()
 {
-    if (client) {
-        delete client;
-        client = 0;
+    if (m_client) {
+        delete m_client;
+        m_client = 0;
     }
 
     deleteCommitLog();
@@ -140,7 +140,7 @@ bool MercurialPlugin::initialize(const QStringList & /* arguments */, QString *
 {
     typedef VCSBase::VCSEditorFactory<MercurialEditor> MercurialEditorFactory;
 
-    VCSBase::VCSBasePlugin::initialize(new MercurialControl(client));
+    VCSBase::VCSBasePlugin::initialize(new MercurialControl(m_client));
 
     core = Core::ICore::instance();
     actionManager = core->actionManager();
@@ -149,15 +149,15 @@ bool MercurialPlugin::initialize(const QStringList & /* arguments */, QString *
     addAutoReleasedObject(optionsPage);
     mercurialSettings.readSettings(core->settings());
 
-    client = new MercurialClient();
-    connect(optionsPage, SIGNAL(settingsChanged()), client, SLOT(settingsChanged()));
+    m_client = new MercurialClient();
+    connect(optionsPage, SIGNAL(settingsChanged()), m_client, SLOT(settingsChanged()));
 
-    connect(client, SIGNAL(changed(QVariant)), versionControl(), SLOT(changed(QVariant)));
+    connect(m_client, SIGNAL(changed(QVariant)), versionControl(), SLOT(changed(QVariant)));
 
     static const char *describeSlot = SLOT(view(QString,QString));
     const int editorCount = sizeof(editorParameters)/sizeof(VCSBase::VCSBaseEditorParameters);
     for (int i = 0; i < editorCount; i++)
-        addAutoReleasedObject(new MercurialEditorFactory(editorParameters + i, client, describeSlot));
+        addAutoReleasedObject(new MercurialEditorFactory(editorParameters + i, m_client, describeSlot));
 
     addAutoReleasedObject(new VCSBase::VCSSubmitEditorFactory<CommitEditor>(&submitEditorParameters));
 
@@ -258,21 +258,21 @@ void MercurialPlugin::annotateCurrentFile()
 {
     const VCSBase::VCSBasePluginState state = currentState();
     QTC_ASSERT(state.hasFile(), return)
-    client->annotate(state.currentFileTopLevel(), state.relativeCurrentFile());
+    m_client->annotate(state.currentFileTopLevel(), state.relativeCurrentFile());
 }
 
 void MercurialPlugin::diffCurrentFile()
 {
     const VCSBase::VCSBasePluginState state = currentState();
     QTC_ASSERT(state.hasFile(), return)
-    client->diff(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()));
+    m_client->diff(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()));
 }
 
 void MercurialPlugin::logCurrentFile()
 {
     const VCSBase::VCSBasePluginState state = currentState();
     QTC_ASSERT(state.hasFile(), return)
-    client->log(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()), true);
+    m_client->log(state.currentFileTopLevel(), QStringList(state.relativeCurrentFile()), true);
 }
 
 void MercurialPlugin::revertCurrentFile()
@@ -283,14 +283,14 @@ void MercurialPlugin::revertCurrentFile()
     RevertDialog reverter;
     if (reverter.exec() != QDialog::Accepted)
         return;
-    client->revertFile(state.currentFileTopLevel(), state.relativeCurrentFile(), reverter.revision());
+    m_client->revertFile(state.currentFileTopLevel(), state.relativeCurrentFile(), reverter.revision());
 }
 
 void MercurialPlugin::statusCurrentFile()
 {
     const VCSBase::VCSBasePluginState state = currentState();
     QTC_ASSERT(state.hasFile(), return)
-    client->status(state.currentFileTopLevel(), state.relativeCurrentFile());
+    m_client->status(state.currentFileTopLevel(), state.relativeCurrentFile());
 }
 
 void MercurialPlugin::createDirectoryActions(const QList<int> &context)
@@ -327,14 +327,14 @@ void MercurialPlugin::diffRepository()
 {
     const VCSBase::VCSBasePluginState state = currentState();
     QTC_ASSERT(state.hasTopLevel(), return)
-    client->diff(state.topLevel());
+    m_client->diff(state.topLevel());
 }
 
 void MercurialPlugin::logRepository()
 {
     const VCSBase::VCSBasePluginState state = currentState();
     QTC_ASSERT(state.hasTopLevel(), return)
-    client->log(state.topLevel());
+    m_client->log(state.topLevel());
 }
 
 void MercurialPlugin::revertMulti()
@@ -345,7 +345,7 @@ void MercurialPlugin::revertMulti()
     RevertDialog reverter;
     if (reverter.exec() != QDialog::Accepted)
         return;
-    client->revertRepository(state.topLevel(), reverter.revision());
+    m_client->revertRepository(state.topLevel(), reverter.revision());
 }
 
 void MercurialPlugin::statusMulti()
@@ -353,7 +353,7 @@ void MercurialPlugin::statusMulti()
     const VCSBase::VCSBasePluginState state = currentState();
     QTC_ASSERT(state.hasTopLevel(), return)
 
-    client->status(state.topLevel());
+    m_client->status(state.topLevel());
 }
 
 void MercurialPlugin::createRepositoryActions(const QList<int> &context)
@@ -411,7 +411,7 @@ void MercurialPlugin::pull()
     dialog.setWindowTitle(tr("Pull Source"));
     if (dialog.exec() != QDialog::Accepted)
         return;
-    client->pull(state.topLevel(), dialog.getRepositoryString());
+    m_client->pull(state.topLevel(), dialog.getRepositoryString());
 }
 
 void MercurialPlugin::push()
@@ -423,7 +423,7 @@ void MercurialPlugin::push()
     dialog.setWindowTitle(tr("Push Destination"));
     if (dialog.exec() != QDialog::Accepted)
         return;
-    client->push(state.topLevel(), dialog.getRepositoryString());
+    m_client->push(state.topLevel(), dialog.getRepositoryString());
 }
 
 void MercurialPlugin::update()
@@ -435,7 +435,7 @@ void MercurialPlugin::update()
     updateDialog.setWindowTitle(tr("Update"));
     if (updateDialog.exec() != QDialog::Accepted)
         return;
-    client->update(state.topLevel(), updateDialog.revision());
+    m_client->update(state.topLevel(), updateDialog.revision());
 }
 
 void MercurialPlugin::import()
@@ -451,7 +451,7 @@ void MercurialPlugin::import()
         return;
 
     const QStringList fileNames = importDialog.selectedFiles();
-    client->import(state.topLevel(), fileNames);
+    m_client->import(state.topLevel(), fileNames);
 }
 
 void MercurialPlugin::incoming()
@@ -463,14 +463,14 @@ void MercurialPlugin::incoming()
     dialog.setWindowTitle(tr("Incoming Source"));
     if (dialog.exec() != QDialog::Accepted)
         return;
-    client->incoming(state.topLevel(), dialog.getRepositoryString());
+    m_client->incoming(state.topLevel(), dialog.getRepositoryString());
 }
 
 void MercurialPlugin::outgoing()
 {
     const VCSBase::VCSBasePluginState state = currentState();
     QTC_ASSERT(state.hasTopLevel(), return)
-    client->outgoing(state.topLevel());
+    m_client->outgoing(state.topLevel());
 }
 
 void MercurialPlugin::createSubmitEditorActions()
@@ -502,9 +502,9 @@ void MercurialPlugin::commit()
 
     m_submitRepository = state.topLevel();
 
-    connect(client, SIGNAL(parsedStatus(QList<QPair<QString,QString> >)),
+    connect(m_client, SIGNAL(parsedStatus(QList<QPair<QString,QString> >)),
             this, SLOT(showCommitWidget(QList<QPair<QString,QString> >)));
-    client->statusWithSignal(m_submitRepository);
+    m_client->statusWithSignal(m_submitRepository);
 }
 
 void MercurialPlugin::showCommitWidget(const QList<QPair<QString, QString> > &status)
@@ -512,7 +512,7 @@ void MercurialPlugin::showCommitWidget(const QList<QPair<QString, QString> > &st
 
     VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance();
     //Once we receive our data release the connection so it can be reused elsewhere
-    disconnect(client, SIGNAL(parsedStatus(QList<QPair<QString,QString> >)),
+    disconnect(m_client, SIGNAL(parsedStatus(QList<QPair<QString,QString> >)),
                this, SLOT(showCommitWidget(QList<QPair<QString,QString> >)));
 
     if (status.isEmpty()) {
@@ -547,7 +547,7 @@ void MercurialPlugin::showCommitWidget(const QList<QPair<QString, QString> > &st
     const QString msg = tr("Commit changes for \"%1\".").arg(m_submitRepository);
     commitEditor->setDisplayName(msg);
 
-    QString branch = client->branchQuerySync(m_submitRepository);
+    QString branch = m_client->branchQuerySync(m_submitRepository);
 
     commitEditor->setFields(m_submitRepository, branch, mercurialSettings.userName(),
                             mercurialSettings.email(), status);
@@ -560,7 +560,7 @@ void MercurialPlugin::showCommitWidget(const QList<QPair<QString, QString> > &st
 
 void MercurialPlugin::diffFromEditorSelected(const QStringList &files)
 {
-    client->diff(m_submitRepository, files);
+    m_client->diff(m_submitRepository, files);
 }
 
 void MercurialPlugin::commitFromEditor()
@@ -604,7 +604,7 @@ bool MercurialPlugin::submitEditorAboutToClose(VCSBase::VCSBaseSubmitEditor *sub
         editorFile->save();
         core->fileManager()->unblockFileChange(editorFile);
 
-        client->commit(commitEditor->repoRoot(), files, commitEditor->committerInfo(),
+        m_client->commit(commitEditor->repoRoot(), files, commitEditor->committerInfo(),
                        editorFile->fileName());
     }
     return true;
diff --git a/src/plugins/mercurial/mercurialplugin.h b/src/plugins/mercurial/mercurialplugin.h
index c11d5590a0796bc75a94a36df35ddd821a1d44e7..6b6e9f50717a1b61525afff367d0c58343cf1dad 100644
--- a/src/plugins/mercurial/mercurialplugin.h
+++ b/src/plugins/mercurial/mercurialplugin.h
@@ -79,6 +79,7 @@ public:
     bool initialize(const QStringList &arguments, QString *error_message);
     void extensionsInitialized();
     static MercurialPlugin *instance() { return m_instance; }
+    MercurialClient *client() const { return m_client; }
 
     QStringList standardArguments() const;
 
@@ -145,7 +146,7 @@ private:
     static MercurialPlugin *m_instance;
     MercurialSettings mercurialSettings;
     OptionsPage *optionsPage;
-    MercurialClient *client;
+    MercurialClient *m_client;
 
     Core::ICore *core;
     Core::ActionManager *actionManager;