From bcd020f38209604ed96d44613b4e1c97b09dc615 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Fri, 19 Mar 2010 16:07:34 +0100
Subject: [PATCH] VCS[git]: Introduce optional pull --rebase.

Do 'git rebase --abort' if something fails.
---
 src/plugins/git/gitclient.cpp    | 38 +++++++++++++++++++++++++++++---
 src/plugins/git/gitclient.h      |  2 ++
 src/plugins/git/gitcommand.cpp   | 19 +++++++++++++---
 src/plugins/git/gitcommand.h     |  7 ++++--
 src/plugins/git/giteditor.cpp    |  2 +-
 src/plugins/git/giteditor.h      |  2 +-
 src/plugins/git/gitsettings.cpp  |  8 ++++++-
 src/plugins/git/gitsettings.h    |  1 +
 src/plugins/git/settingspage.cpp |  3 +++
 src/plugins/git/settingspage.ui  | 21 +++++++++++++++---
 10 files changed, 89 insertions(+), 14 deletions(-)

diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
index 6f2a5f5c0e0..ab8094672ba 100644
--- a/src/plugins/git/gitclient.cpp
+++ b/src/plugins/git/gitclient.cpp
@@ -302,7 +302,7 @@ void GitClient::status(const QString &workingDirectory)
     VCSBase::VCSBaseOutputWindow *outwin = VCSBase::VCSBaseOutputWindow::instance();
     outwin->setRepository(workingDirectory);
     GitCommand *command = executeGit(workingDirectory, statusArgs, 0, true);
-    connect(command, SIGNAL(finished(bool,QVariant)), outwin, SLOT(clearRepository()),
+    connect(command, SIGNAL(finished(bool,int,QVariant)), outwin, SLOT(clearRepository()),
             Qt::QueuedConnection);
 }
 
@@ -985,7 +985,7 @@ GitCommand *GitClient::createCommand(const QString &workingDirectory,
     VCSBase::VCSBaseOutputWindow *outputWindow = VCSBase::VCSBaseOutputWindow::instance();
     GitCommand* command = new GitCommand(binary(), workingDirectory, processEnvironment(), QVariant(editorLineNumber));
     if (editor)
-        connect(command, SIGNAL(finished(bool,QVariant)), editor, SLOT(commandFinishedGotoLine(bool,QVariant)));
+        connect(command, SIGNAL(finished(bool,int,QVariant)), editor, SLOT(commandFinishedGotoLine(bool,int,QVariant)));
     if (outputToWindow) {
         if (editor) { // assume that the commands output is the important thing
             connect(command, SIGNAL(outputData(QByteArray)), outputWindow, SLOT(appendDataSilently(QByteArray)));
@@ -1445,8 +1445,40 @@ void GitClient::revert(const QStringList &files)
 
 void GitClient::pull(const QString &workingDirectory)
 {
-    GitCommand *cmd = executeGit(workingDirectory, QStringList(QLatin1String("pull")), 0, true, GitCommand::ReportStderr);
+    pull(workingDirectory, m_settings.pullRebase);
+}
+
+void GitClient::pull(const QString &workingDirectory, bool rebase)
+{
+    QStringList arguments(QLatin1String("pull"));
+    if (rebase)
+        arguments << QLatin1String("--rebase");
+    GitCommand *cmd = executeGit(workingDirectory, arguments, 0, true, GitCommand::ReportStderr);
     connectRepositoryChanged(workingDirectory, cmd);
+    // Need to clean up if something goes wrong
+    if (rebase) {
+        cmd->setCookie(QVariant(workingDirectory));
+        connect(cmd, SIGNAL(finished(bool,int,QVariant)), this, SLOT(slotPullRebaseFinished(bool,int,QVariant)),
+                Qt::QueuedConnection);
+    }
+}
+
+void GitClient::slotPullRebaseFinished(bool ok, int exitCode, const QVariant &cookie)
+{
+    if (ok && exitCode == 0)
+        return;
+    // Abort rebase to clean if something goes wrong
+    VCSBase::VCSBaseOutputWindow *outwin = VCSBase::VCSBaseOutputWindow::instance();
+    outwin->appendError(tr("git pull --rebase failed, aborting rebase."));
+    const QString workingDir = cookie.toString();
+    QStringList arguments;
+    arguments << QLatin1String("rebase") << QLatin1String("--abort");
+    QByteArray stdOut;
+    QByteArray stdErr;
+    const bool rc = synchronousGit(workingDir, arguments, &stdOut, &stdErr, true);
+    outwin->append(commandOutputFromLocal8Bit(stdOut));
+    if (!rc)
+        outwin->appendError(commandOutputFromLocal8Bit(stdErr));
 }
 
 // Subversion: git svn
diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h
index b285cd2496a..c81347e32aa 100644
--- a/src/plugins/git/gitclient.h
+++ b/src/plugins/git/gitclient.h
@@ -213,6 +213,7 @@ public slots:
 
 private slots:
     void slotBlameRevisionRequested(const QString &source, QString change, int lineNumber);
+    void slotPullRebaseFinished(bool ok, int exitCode, const QVariant &cookie);
 
 private:
     VCSBase::VCSBaseEditor *createVCSEditor(const QString &kind,
@@ -245,6 +246,7 @@ private:
     enum RevertResult { RevertOk, RevertUnchanged, RevertCanceled, RevertFailed };
     RevertResult revertI(QStringList files, bool *isDirectory, QString *errorMessage);
     void connectRepositoryChanged(const QString & repository, GitCommand *cmd);
+    void pull(const QString &workingDirectory, bool rebase);
 
     const QString m_msgWait;
     GitPlugin     *m_plugin;
diff --git a/src/plugins/git/gitcommand.cpp b/src/plugins/git/gitcommand.cpp
index 1362e0c6709..7483428eb91 100644
--- a/src/plugins/git/gitcommand.cpp
+++ b/src/plugins/git/gitcommand.cpp
@@ -133,6 +133,7 @@ void GitCommand::run()
     QString error;
 
     const int count = m_jobs.size();
+    int exitCode = -1;
     bool ok = true;
     for (int j = 0; j < count; j++) {
         if (Git::Constants::debug)
@@ -156,14 +157,15 @@ void GitCommand::run()
         }
 
         error += QString::fromLocal8Bit(stdErr);
+        exitCode = process.exitCode();
         switch (m_reportTerminationMode) {
         case NoReport:
             break;
         case ReportStdout:
-            stdOut += msgTermination(process.exitCode(), m_binaryPath, m_jobs.at(j).arguments).toUtf8();
+            stdOut += msgTermination(exitCode, m_binaryPath, m_jobs.at(j).arguments).toUtf8();
             break;
         case ReportStderr:
-            error += msgTermination(process.exitCode(), m_binaryPath, m_jobs.at(j).arguments);
+            error += msgTermination(exitCode, m_binaryPath, m_jobs.at(j).arguments);
             break;
         }
     }
@@ -183,7 +185,7 @@ void GitCommand::run()
     if (!error.isEmpty())
         emit errorText(error);
 
-    emit finished(ok, m_cookie);
+    emit finished(ok, exitCode, m_cookie);
     if (ok)
         emit success();
     // As it is used asynchronously, we need to delete ourselves
@@ -213,5 +215,16 @@ void GitCommand::removeColorCodes(QByteArray *data)
     }
 }
 
+void GitCommand::setCookie(const QVariant &cookie)
+{
+    m_cookie = cookie;
+}
+
+QVariant GitCommand::cookie() const
+{
+    return m_cookie;
+}
+
+
 } // namespace Internal
 } // namespace Git
diff --git a/src/plugins/git/gitcommand.h b/src/plugins/git/gitcommand.h
index 1e7dce1f248..c9cc058d019 100644
--- a/src/plugins/git/gitcommand.h
+++ b/src/plugins/git/gitcommand.h
@@ -72,13 +72,16 @@ public:
 
     static QString msgTimeout(int seconds);
 
+    void setCookie(const QVariant &cookie);
+    QVariant cookie() const;
+
 private:
     void run();
 
 Q_SIGNALS:
     void outputData(const QByteArray&);
     void errorText(const QString&);
-    void finished(bool ok, const QVariant &cookie);
+    void finished(bool ok, int exitCode, const QVariant &cookie);
     void success();
 
 private:
@@ -93,7 +96,7 @@ private:
     QStringList m_basicArguments;
     const QString m_workingDirectory;
     const QStringList m_environment;
-    const QVariant m_cookie;
+    QVariant m_cookie;
 
     QList<Job> m_jobs;
     TerminationReportMode m_reportTerminationMode;
diff --git a/src/plugins/git/giteditor.cpp b/src/plugins/git/giteditor.cpp
index 012317c3a33..bb89ffdc3c1 100644
--- a/src/plugins/git/giteditor.cpp
+++ b/src/plugins/git/giteditor.cpp
@@ -179,7 +179,7 @@ void GitEditor::setPlainTextDataFiltered(const QByteArray &a)
     }
 }
 
-void GitEditor::commandFinishedGotoLine(bool ok, const QVariant &v)
+void GitEditor::commandFinishedGotoLine(bool ok, int /* exitCode */, const QVariant &v)
 {
     if (ok && v.type() == QVariant::Int) {
         const int line = v.toInt();
diff --git a/src/plugins/git/giteditor.h b/src/plugins/git/giteditor.h
index 962a05694b4..c82a501e545 100644
--- a/src/plugins/git/giteditor.h
+++ b/src/plugins/git/giteditor.h
@@ -52,7 +52,7 @@ public:
 public slots:
     void setPlainTextDataFiltered(const QByteArray &a);
     // Matches  the signature of the finished signal of GitCommand
-    void commandFinishedGotoLine(bool ok, const QVariant &v);
+    void commandFinishedGotoLine(bool ok, int exitCode, const QVariant &v);
 
 private:
     virtual QSet<QString> annotationChanges() const;
diff --git a/src/plugins/git/gitsettings.cpp b/src/plugins/git/gitsettings.cpp
index b5831f5e10f..9d67fcb2b7b 100644
--- a/src/plugins/git/gitsettings.cpp
+++ b/src/plugins/git/gitsettings.cpp
@@ -41,13 +41,15 @@ static const char sysEnvKeyC[] = "SysEnv";
 static const char pathKeyC[] = "Path";
 static const char logCountKeyC[] = "LogCount";
 static const char timeoutKeyC[] = "TimeOut";
+static const char pullRebaseKeyC[] = "PullRebase";
 static const char promptToSubmitKeyC[] = "PromptForSubmit";
 static const char omitAnnotationDateKeyC[] = "OmitAnnotationDate";
 static const char spaceIgnorantBlameKeyC[] = "SpaceIgnorantBlame";
 static const char diffPatienceKeyC[] = "DiffPatience";
 
 enum {
-    defaultLogCount =  100 ,
+    defaultPullRebase = 0,
+    defaultLogCount = 100,
 #ifdef Q_OS_WIN
     defaultTimeOut = 60
 #else	
@@ -62,6 +64,7 @@ GitSettings::GitSettings() :
     adoptPath(false),
     logCount(defaultLogCount),
     timeoutSeconds(defaultTimeOut),
+    pullRebase(bool(defaultPullRebase)),
     promptToSubmit(true),
     omitAnnotationDate(false),
     spaceIgnorantBlame(true),
@@ -76,6 +79,7 @@ void GitSettings::fromSettings(QSettings *settings)
     path = settings->value(QLatin1String(pathKeyC), QString()).toString();
     logCount = settings->value(QLatin1String(logCountKeyC), defaultLogCount).toInt();
     timeoutSeconds = settings->value(QLatin1String(timeoutKeyC), defaultTimeOut).toInt();
+    pullRebase = settings->value(QLatin1String(pullRebaseKeyC), bool(defaultPullRebase)).toBool();
     promptToSubmit = settings->value(QLatin1String(promptToSubmitKeyC), true).toBool();
     omitAnnotationDate = settings->value(QLatin1String(omitAnnotationDateKeyC), false).toBool();
     spaceIgnorantBlame = settings->value(QLatin1String(spaceIgnorantBlameKeyC), true).toBool();
@@ -90,6 +94,7 @@ void GitSettings::toSettings(QSettings *settings) const
     settings->setValue(QLatin1String(pathKeyC), path);
     settings->setValue(QLatin1String(logCountKeyC), logCount);
     settings->setValue(QLatin1String(timeoutKeyC), timeoutSeconds);
+    settings->setValue(QLatin1String(pullRebaseKeyC), pullRebase);
     settings->setValue(QLatin1String(promptToSubmitKeyC), promptToSubmit);
     settings->setValue(QLatin1String(omitAnnotationDateKeyC), omitAnnotationDate);
     settings->setValue(QLatin1String(spaceIgnorantBlameKeyC), spaceIgnorantBlame);
@@ -101,6 +106,7 @@ bool GitSettings::equals(const GitSettings &s) const
 {
     return adoptPath == s.adoptPath && path == s.path && logCount == s.logCount
            && timeoutSeconds == s.timeoutSeconds && promptToSubmit == s.promptToSubmit
+           && pullRebase == s.pullRebase
            && omitAnnotationDate == s.omitAnnotationDate && spaceIgnorantBlame == s.spaceIgnorantBlame
            && diffPatience == s.diffPatience;
 }
diff --git a/src/plugins/git/gitsettings.h b/src/plugins/git/gitsettings.h
index e103ae33aee..b3c51595ab6 100644
--- a/src/plugins/git/gitsettings.h
+++ b/src/plugins/git/gitsettings.h
@@ -55,6 +55,7 @@ struct GitSettings
     QString path;
     int logCount;
     int timeoutSeconds;
+    bool pullRebase;
     bool promptToSubmit;
     bool omitAnnotationDate;
     bool spaceIgnorantBlame;
diff --git a/src/plugins/git/settingspage.cpp b/src/plugins/git/settingspage.cpp
index 3aa9e6c02ea..11edb065ce3 100644
--- a/src/plugins/git/settingspage.cpp
+++ b/src/plugins/git/settingspage.cpp
@@ -56,6 +56,7 @@ GitSettings SettingsPageWidget::settings() const
     rc.adoptPath = m_ui.environmentGroupBox->isChecked() && !rc.path.isEmpty();
     rc.logCount = m_ui.logCountSpinBox->value();
     rc.timeoutSeconds = m_ui.timeoutSpinBox->value();
+    rc.pullRebase = m_ui.pullRebaseCheckBox->isChecked();
     rc.promptToSubmit = m_ui.promptToSubmitCheckBox->isChecked();
     rc.omitAnnotationDate = m_ui.omitAnnotationDataCheckBox->isChecked();
     rc.spaceIgnorantBlame = m_ui.spaceIgnorantBlameCheckBox->isChecked();
@@ -69,6 +70,7 @@ void SettingsPageWidget::setSettings(const GitSettings &s)
     m_ui.pathLineEdit->setText(s.path);
     m_ui.logCountSpinBox->setValue(s.logCount);
     m_ui.timeoutSpinBox->setValue(s.timeoutSeconds);
+    m_ui.pullRebaseCheckBox->setChecked(s.pullRebase);
     m_ui.promptToSubmitCheckBox->setChecked(s.promptToSubmit);
     m_ui.omitAnnotationDataCheckBox->setChecked(s.omitAnnotationDate);
     m_ui.spaceIgnorantBlameCheckBox->setChecked(s.spaceIgnorantBlame);
@@ -86,6 +88,7 @@ QString SettingsPageWidget::searchKeywords() const
     QTextStream(&rc) << ' ' << m_ui.pathlabel->text()  <<  ' ' << m_ui.logCountLabel->text()
         << ' ' << m_ui.timeoutLabel->text()
         << ' ' << m_ui.promptToSubmitCheckBox->text()
+        << ' ' << m_ui.promptToSubmitCheckBox->text()
         << ' ' << m_ui.omitAnnotationDataCheckBox->text()
         << ' ' << m_ui.environmentGroupBox->title()
         << ' ' << m_ui.spaceIgnorantBlameCheckBox->text();
diff --git a/src/plugins/git/settingspage.ui b/src/plugins/git/settingspage.ui
index 443a9e52b5d..159c3774f3a 100644
--- a/src/plugins/git/settingspage.ui
+++ b/src/plugins/git/settingspage.ui
@@ -2,6 +2,14 @@
 <ui version="4.0">
  <class>Git::Internal::SettingsPage</class>
  <widget class="QWidget" name="Git::Internal::SettingsPage">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>409</width>
+    <height>385</height>
+   </rect>
+  </property>
   <layout class="QVBoxLayout" name="verticalLayout">
    <item>
     <widget class="QGroupBox" name="environmentGroupBox">
@@ -113,27 +121,34 @@
         </property>
        </widget>
       </item>
-      <item row="4" column="0" colspan="2">
+      <item row="5" column="0" colspan="2">
        <widget class="QCheckBox" name="omitAnnotationDataCheckBox">
         <property name="text">
          <string>Omit date from annotation output</string>
         </property>
        </widget>
       </item>
-      <item row="5" column="0" colspan="2">
+      <item row="6" column="0" colspan="2">
        <widget class="QCheckBox" name="spaceIgnorantBlameCheckBox">
         <property name="text">
          <string>Ignore whitespace changes in annotation</string>
         </property>
        </widget>
       </item>
-      <item row="3" column="0">
+      <item row="4" column="0">
        <widget class="QCheckBox" name="diffPatienceCheckBox">
         <property name="text">
          <string>Use &quot;patience diff&quot; algorithm</string>
         </property>
        </widget>
       </item>
+      <item row="3" column="0" colspan="2">
+       <widget class="QCheckBox" name="pullRebaseCheckBox">
+        <property name="text">
+         <string>Pull with rebase</string>
+        </property>
+       </widget>
+      </item>
      </layout>
     </widget>
    </item>
-- 
GitLab