diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
index eb9d562005354922bd2f4d7cd927ec9460ebf948..c9ce5894ea4cc46d10c8959025f9b2de86509716 100644
--- a/src/plugins/git/gitclient.cpp
+++ b/src/plugins/git/gitclient.cpp
@@ -829,6 +829,26 @@ private:
     QStringList m_files;
 };
 
+class ProgressParser : public VcsBase::ProgressParser
+{
+public:
+    ProgressParser() :
+        m_progressExp(QLatin1String("\\((\\d+)/(\\d+)\\)")) // e.g. Rebasing (7/42)
+    {
+    }
+
+protected:
+    void parseProgress(const QString &text)
+    {
+        if (m_progressExp.lastIndexIn(text) != -1)
+            setProgressAndMaximum(m_progressExp.cap(1).toInt(), m_progressExp.cap(2).toInt());
+    }
+
+private:
+    QRegExp m_progressExp;
+};
+
+
 
 Core::IEditor *locateEditor(const char *property, const QString &entry)
 {
@@ -3487,6 +3507,7 @@ void GitClient::rebase(const QString &workingDirectory, const QString &baseBranc
                                   arguments);
     VcsBase::Command *command = createCommand(workingDirectory, 0, true);
     new ConflictHandler(command, workingDirectory, gitCommand);
+    command->setProgressParser(new ProgressParser);
     command->addJob(arguments, -1);
     command->execute();
 }
@@ -3532,6 +3553,7 @@ void GitClient::interactiveRebase(const QString &workingDirectory, const QString
         m_disableEditor = true;
     VcsBase::Command *command = createCommand(workingDirectory, 0, true);
     new ConflictHandler(command, workingDirectory, QLatin1String("rebase"));
+    command->setProgressParser(new ProgressParser);
     command->addJob(arguments, -1);
     command->execute();
     command->setCookie(workingDirectory);
diff --git a/src/plugins/vcsbase/command.cpp b/src/plugins/vcsbase/command.cpp
index 21701174483fbd760a77c23b47a73336a4d710be..57d36c3575c614c4761e8ec374b94fe1d6add2d0 100644
--- a/src/plugins/vcsbase/command.cpp
+++ b/src/plugins/vcsbase/command.cpp
@@ -37,6 +37,7 @@
 #include <vcsbase/vcsbaseoutputwindow.h>
 #include <utils/synchronousprocess.h>
 #include <utils/runextensions.h>
+#include <utils/qtcassert.h>
 
 #include <QDebug>
 #include <QProcess>
@@ -48,11 +49,29 @@
 #include <QVariant>
 #include <QStringList>
 #include <QTextCodec>
+#include <QMutex>
 
 Q_DECLARE_METATYPE(QVariant)
 
 enum { debugExecution = 0 };
 
+/*!
+    \fn void VcsBase::ProgressParser::parseProgress(const QString &text)
+
+    Reimplement to parse progress as it appears in the standard output.
+    If a progress string is detected, call \c setProgressAndMaximum() to update
+    the progress bar accordingly.
+
+    \sa VcsBase::ProgressParser::setProgressAndMaximum()
+*/
+
+/*!
+    \fn void VcsBase::ProgressParser::setProgressAndMaximum(int value, int maximum)
+
+    Sets progress \a value and \a maximum for current command. Called by \c parseProgress()
+    when a progress string is detected.
+*/
+
 namespace VcsBase {
 namespace Internal {
 
@@ -69,6 +88,7 @@ public:
     CommandPrivate(const QString &binary,
                    const QString &workingDirectory,
                    const QProcessEnvironment &environment);
+    ~CommandPrivate();
 
     const QString m_binaryPath;
     const QString m_workingDirectory;
@@ -78,6 +98,7 @@ public:
     unsigned m_flags;
     QTextCodec *m_codec;
     const QString m_sshPasswordPrompt;
+    ProgressParser *m_progressParser;
 
     QList<Job> m_jobs;
 
@@ -95,11 +116,17 @@ CommandPrivate::CommandPrivate(const QString &binary,
     m_flags(0),
     m_codec(0),
     m_sshPasswordPrompt(VcsBasePlugin::sshPrompt()),
+    m_progressParser(0),
     m_lastExecSuccess(false),
     m_lastExecExitCode(-1)
 {
 }
 
+CommandPrivate::~CommandPrivate()
+{
+    delete m_progressParser;
+}
+
 CommandPrivate::Job::Job(const QStringList &a, int t) :
     arguments(a),
     timeout(t)
@@ -207,6 +234,8 @@ void Command::run(QFutureInterface<void> &future)
     QString stdOut;
     QString stdErr;
 
+    if (d->m_progressParser)
+        d->m_progressParser->setFuture(&future);
     const int count = d->m_jobs.size();
     d->m_lastExecExitCode = -1;
     d->m_lastExecSuccess = true;
@@ -233,6 +262,8 @@ void Command::run(QFutureInterface<void> &future)
             emit success(cookie());
     }
 
+    if (d->m_progressParser)
+        d->m_progressParser->setFuture(0);
     // As it is used asynchronously, we need to delete ourselves
     this->deleteLater();
 }
@@ -342,10 +373,10 @@ Utils::SynchronousProcessResponse Command::runVcs(const QStringList &arguments,
         }
 
         // connect stdout to the output window if desired
-        if (d->m_flags & VcsBasePlugin::ShowStdOutInLogWindow) {
-            process.setStdOutBufferedSignalsEnabled(true);
+        process.setStdOutBufferedSignalsEnabled(true);
+        connect(&process, SIGNAL(stdOutBuffered(QString,bool)), this, SLOT(bufferedOutput(QString)));
+        if (d->m_flags & VcsBasePlugin::ShowStdOutInLogWindow)
             connect(&process, SIGNAL(stdOutBuffered(QString,bool)), outputWindow, SLOT(append(QString)));
-        }
 
         process.setTimeOutMessageBoxEnabled(true);
 
@@ -479,6 +510,12 @@ bool Command::runFullySynchronous(const QStringList &arguments, int timeoutMS,
     return process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0;
 }
 
+void Command::bufferedOutput(const QString &text)
+{
+    if (d->m_progressParser)
+        d->m_progressParser->parseProgress(text);
+}
+
 const QVariant &Command::cookie() const
 {
     return d->m_cookie;
@@ -499,6 +536,39 @@ void Command::setCodec(QTextCodec *codec)
     d->m_codec = codec;
 }
 
+//! Use \a parser to parse progress data from stdout. Command takes ownership of \a parser
+void Command::setProgressParser(ProgressParser *parser)
+{
+    QTC_ASSERT(!d->m_progressParser, return);
+    d->m_progressParser = parser;
+}
+
+ProgressParser::ProgressParser() :
+    m_future(0),
+    m_futureMutex(new QMutex)
+{
+}
+
+ProgressParser::~ProgressParser()
+{
+    delete m_futureMutex;
+}
+
+void ProgressParser::setProgressAndMaximum(int value, int maximum)
+{
+    QMutexLocker lock(m_futureMutex);
+    if (!m_future)
+        return;
+    m_future->setProgressRange(0, maximum);
+    m_future->setProgressValue(value);
+}
+
+void ProgressParser::setFuture(QFutureInterface<void> *future)
+{
+    QMutexLocker lock(m_futureMutex);
+    m_future = future;
+}
+
 } // namespace VcsBase
 
 #include "command.moc"
diff --git a/src/plugins/vcsbase/command.h b/src/plugins/vcsbase/command.h
index 84b4d7c398cd0e1881691479e0f8ee4818163ef1..7931cc974eec116edc3e4217c485f4ee222794e1 100644
--- a/src/plugins/vcsbase/command.h
+++ b/src/plugins/vcsbase/command.h
@@ -37,6 +37,7 @@
 #include <QObject>
 
 QT_BEGIN_NAMESPACE
+class QMutex;
 class QStringList;
 class QVariant;
 class QProcessEnvironment;
@@ -48,6 +49,24 @@ namespace VcsBase {
 
 namespace Internal { class CommandPrivate; }
 
+class VCSBASE_EXPORT ProgressParser
+{
+public:
+    ProgressParser();
+    virtual ~ProgressParser();
+
+protected:
+    virtual void parseProgress(const QString &text) = 0;
+    void setProgressAndMaximum(int value, int maximum);
+
+private:
+    void setFuture(QFutureInterface<void> *future);
+
+    QFutureInterface<void> *m_future;
+    QMutex *m_futureMutex;
+    friend class Command;
+};
+
 class VCSBASE_EXPORT Command : public QObject
 {
     Q_OBJECT
@@ -80,6 +99,7 @@ public:
     QTextCodec *codec() const;
     void setCodec(QTextCodec *codec);
 
+    void setProgressParser(ProgressParser *parser);
 
     Utils::SynchronousProcessResponse runVcs(const QStringList &arguments, int timeoutMS);
     // Make sure to not pass through the event loop at all:
@@ -90,6 +110,9 @@ private:
     void run(QFutureInterface<void> &future);
     Utils::SynchronousProcessResponse runSynchronous(const QStringList &arguments, int timeoutMS);
 
+private slots:
+    void bufferedOutput(const QString &text);
+
 signals:
     void output(const QString &);
     void errorText(const QString &);