From defc270896bfc852faa7cad19b154a314b2661e7 Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <qtc-committer@nokia.com>
Date: Fri, 19 Dec 2008 17:42:08 +0100
Subject: [PATCH] Fixes: Start a git branch dialog.

---
 src/plugins/git/branchdialog.cpp | 174 +++++++++++++++++++++++++++++++
 src/plugins/git/branchdialog.h   |  60 +++++++++++
 src/plugins/git/branchdialog.ui  |  95 +++++++++++++++++
 src/plugins/git/branchmodel.cpp  | 136 ++++++++++++++++++++++++
 src/plugins/git/branchmodel.h    |  58 +++++++++++
 src/plugins/git/git.pro          |  14 +--
 src/plugins/git/gitclient.cpp    |  42 ++++++++
 src/plugins/git/gitclient.h      |   6 ++
 src/plugins/git/gitplugin.cpp    |  21 +++-
 9 files changed, 596 insertions(+), 10 deletions(-)
 create mode 100644 src/plugins/git/branchdialog.cpp
 create mode 100644 src/plugins/git/branchdialog.h
 create mode 100644 src/plugins/git/branchdialog.ui
 create mode 100644 src/plugins/git/branchmodel.cpp
 create mode 100644 src/plugins/git/branchmodel.h

diff --git a/src/plugins/git/branchdialog.cpp b/src/plugins/git/branchdialog.cpp
new file mode 100644
index 00000000000..0918f2d6c07
--- /dev/null
+++ b/src/plugins/git/branchdialog.cpp
@@ -0,0 +1,174 @@
+#include "branchdialog.h"
+#include "branchmodel.h"
+#include "gitclient.h"
+#include "ui_branchdialog.h"
+
+#include <QtGui/QItemSelectionModel>
+#include <QtGui/QPushButton>
+#include <QtGui/QMessageBox>
+
+// Single selection helper
+static inline int selectedRow(const QAbstractItemView *listView)
+{
+    const QModelIndexList indexList = listView->selectionModel()->selectedIndexes();
+    if (indexList.size() == 1)
+        return indexList.front().row();
+    return -1;
+}
+
+namespace Git {
+    namespace Internal {
+
+BranchDialog::BranchDialog(QWidget *parent) :
+    QDialog(parent),
+    m_client(0),
+    m_ui(new Ui::BranchDialog),
+    m_checkoutButton(0),
+    m_deleteButton(0),
+    m_localModel(0),
+    m_remoteModel(0)
+{
+    m_ui->setupUi(this);
+    m_checkoutButton = m_ui->buttonBox->addButton(tr("Checkout"), QDialogButtonBox::AcceptRole);
+    connect(m_checkoutButton, SIGNAL(clicked()), this, SLOT(slotCheckoutSelectedBranch()));
+
+    m_deleteButton = m_ui->buttonBox->addButton(tr("Delete"), QDialogButtonBox::ActionRole);
+    connect(m_deleteButton, SIGNAL(clicked()), this, SLOT(slotDeleteSelectedBranch()));
+
+    connect(m_ui->localBranchListView, SIGNAL(doubleClicked(QModelIndex)), this,
+            SLOT(slotLocalBranchActivated()));
+}
+
+BranchDialog::~BranchDialog()
+{
+    delete m_ui;
+}
+
+bool BranchDialog::init(GitClient *client, const QString &workingDirectory, QString *errorMessage)
+{
+    // Find repository and populate models.
+    m_client = client;
+    m_repoDirectory = GitClient::findRepositoryForDirectory(workingDirectory);
+    if (m_repoDirectory.isEmpty()) {
+        *errorMessage = tr("Unable to find the repository directory for '%1'.").arg(workingDirectory);
+        return false;
+    }
+    m_ui->repositoryFieldLabel->setText(m_repoDirectory);
+
+    m_localModel = new BranchModel(client, BranchModel::LocalBranches, this);
+    m_remoteModel = new BranchModel(client, BranchModel::RemoteBranches, this);
+    if (!m_localModel->refresh(workingDirectory, errorMessage)
+        || !m_remoteModel->refresh(workingDirectory, errorMessage))
+        return false;
+
+    m_ui->localBranchListView->setModel(m_localModel);
+    m_ui->remoteBranchListView->setModel(m_remoteModel);
+    // Selection model comes into existence only now
+    connect(m_ui->localBranchListView->selectionModel(),
+            SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
+            this, SLOT(slotEnableButtons()));
+    connect(m_ui->remoteBranchListView->selectionModel(),
+            SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
+            this, SLOT(slotEnableButtons()));
+    slotEnableButtons();
+    return true;
+}
+
+int BranchDialog::selectedLocalBranchIndex() const
+{
+    return selectedRow(m_ui->localBranchListView);
+}
+
+int BranchDialog::selectedRemoteBranchIndex() const
+{
+    return selectedRow(m_ui->remoteBranchListView);
+}
+
+void BranchDialog::slotEnableButtons()
+{
+    // We can switch to or delete branches that are not current.
+    const int selectedLocalRow = selectedLocalBranchIndex();
+    const int currentLocalBranch = m_localModel->currentBranch();
+
+    const bool hasSelection = selectedLocalRow != -1;
+    const bool currentIsNotSelected = hasSelection && selectedLocalRow != currentLocalBranch;
+
+    m_checkoutButton->setEnabled(currentIsNotSelected);
+    m_deleteButton->setEnabled(currentIsNotSelected);
+}
+
+bool BranchDialog::ask(const QString &title, const QString &what, bool defaultButton)
+{
+    return QMessageBox::question(this, title, what, QMessageBox::Yes|QMessageBox::No,
+                                 defaultButton ? QMessageBox::Yes : QMessageBox::No) == QMessageBox::Yes;
+}
+
+/* Prompt to delete a local branch and do so. */
+void BranchDialog::slotDeleteSelectedBranch()
+{
+    const int idx = selectedLocalBranchIndex();
+    if (idx == -1)
+        return;
+    const QString name = m_localModel->branchName(idx);
+    if (!ask(tr("Delete Branch"), tr("Would you like to delete the branch '%1'?").arg(name), true))
+        return;
+    QString errorMessage;
+    bool ok = false;
+    do {
+        QString output;
+        QStringList args(QLatin1String("-D"));
+        args << name;
+        if (!m_client->synchronousBranchCmd(m_repoDirectory, args, &output, &errorMessage))
+            break;
+        if (!m_localModel->refresh(m_repoDirectory, &errorMessage))
+            break;
+        ok = true;
+    } while (false);
+    slotEnableButtons();
+    if (!ok)
+        QMessageBox::warning(this, tr("Failed to delete branch"), errorMessage);
+}
+
+void BranchDialog::slotLocalBranchActivated()
+{
+    if (m_checkoutButton->isEnabled())
+        m_checkoutButton->animateClick();
+}
+
+/* Ask to stash away changes and then close dialog and do an asynchronous
+ * checkout. */
+void BranchDialog::slotCheckoutSelectedBranch()
+{
+    const int idx = selectedLocalBranchIndex();
+    if (idx == -1)
+        return;
+    const QString name = m_localModel->branchName(idx);
+    QString errorMessage;
+    switch (m_client->ensureStash(m_repoDirectory, &errorMessage)) {
+        case GitClient::StashUnchanged:
+        case GitClient::Stashed:
+        case GitClient::NotStashed:
+        break;
+        case GitClient::StashCanceled:
+        return;
+        case GitClient::StashFailed:
+        QMessageBox::warning(this, tr("Failed to stash"), errorMessage);
+        return;
+    }
+    accept();
+    m_client->checkoutBranch(m_repoDirectory, name);
+}
+
+void BranchDialog::changeEvent(QEvent *e)
+{
+    switch (e->type()) {
+    case QEvent::LanguageChange:
+        m_ui->retranslateUi(this);
+        break;
+    default:
+        break;
+    }
+}
+
+} // namespace Internal
+} // namespace Git
diff --git a/src/plugins/git/branchdialog.h b/src/plugins/git/branchdialog.h
new file mode 100644
index 00000000000..064719b8ff0
--- /dev/null
+++ b/src/plugins/git/branchdialog.h
@@ -0,0 +1,60 @@
+#ifndef BRANCHDIALOG_H
+#define BRANCHDIALOG_H
+
+#include <QtGui/QDialog>
+
+QT_BEGIN_NAMESPACE
+class QPushButton;
+QT_END_NAMESPACE
+
+namespace Git {
+    namespace Internal {
+        namespace Ui {
+            class BranchDialog;
+        }
+
+        class GitClient;
+        class BranchModel;
+
+        /* Branch dialog: Display a list of local branches at the top
+         * and remote branches below. Offers to checkout/delete local
+         * branches.
+         * TODO: Add new branch (optionally tracking a remote one).
+         * How to find out that a local branch is a tracking one? */
+        class BranchDialog : public QDialog {
+            Q_OBJECT
+            Q_DISABLE_COPY(BranchDialog)
+        public:
+            explicit BranchDialog(QWidget *parent = 0);
+
+            bool init(GitClient *client, const QString &workingDirectory, QString *errorMessage);
+
+            virtual ~BranchDialog();
+
+        protected:
+            virtual void changeEvent(QEvent *e);
+
+        private slots:
+            void slotEnableButtons();
+            void slotCheckoutSelectedBranch();
+            void slotDeleteSelectedBranch();
+            void slotLocalBranchActivated();
+
+        private:
+            bool ask(const QString &title, const QString &what, bool defaultButton);
+
+            int selectedLocalBranchIndex() const;
+            int selectedRemoteBranchIndex() const;
+
+            GitClient *m_client;
+            Ui::BranchDialog *m_ui;
+            QPushButton *m_checkoutButton;
+            QPushButton *m_deleteButton;
+
+            BranchModel *m_localModel;
+            BranchModel *m_remoteModel;
+            QString m_repoDirectory;
+        };
+    } // namespace Internal
+} // namespace Git
+#endif // BRANCHDIALOG_H
diff --git a/src/plugins/git/branchdialog.ui b/src/plugins/git/branchdialog.ui
new file mode 100644
index 00000000000..07f7ff656b1
--- /dev/null
+++ b/src/plugins/git/branchdialog.ui
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Git::Internal::BranchDialog</class>
+ <widget class="QDialog" name="Git::Internal::BranchDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>544</width>
+    <height>631</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Branches</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_3">
+   <item>
+    <widget class="QGroupBox" name="infoGroupBox">
+     <property name="title">
+      <string>General information</string>
+     </property>
+     <layout class="QFormLayout" name="formLayout">
+      <item row="0" column="0">
+       <widget class="QLabel" name="repositoryLabel">
+        <property name="text">
+         <string>Repository:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1">
+       <widget class="QLabel" name="repositoryFieldLabel">
+        <property name="text">
+         <string>TextLabel</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="localBranchGroupBox">
+     <property name="title">
+      <string>Branches</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout">
+      <item>
+       <widget class="QListView" name="localBranchListView"/>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="remoteBranchGroupBox">
+     <property name="title">
+      <string>Remote branches</string>
+     </property>
+     <layout class="QVBoxLayout" name="verticalLayout_2">
+      <item>
+       <widget class="QListView" name="remoteBranchListView"/>
+      </item>
+     </layout>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Close</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>Git::Internal::BranchDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>466</x>
+     <y>614</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>544</x>
+     <y>23</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp
new file mode 100644
index 00000000000..0881aea654b
--- /dev/null
+++ b/src/plugins/git/branchmodel.cpp
@@ -0,0 +1,136 @@
+#include "branchmodel.h"
+#include "gitclient.h"
+
+#include <QtCore/QDebug>
+
+enum { debug = 0 };
+
+namespace Git {
+    namespace Internal {
+
+// Parse a branch line: " *name sha description".  Return  true if it is
+// the current one
+bool BranchModel::Branch::parse(const QString &lineIn, bool *isCurrent)
+{
+    if (debug)
+        qDebug() << Q_FUNC_INFO << lineIn;
+
+    *isCurrent = lineIn.startsWith(QLatin1String("* "));
+    if (lineIn.size() < 3)
+        return false;
+
+    const QStringList tokens =lineIn.mid(2).split(QLatin1Char(' '), QString::SkipEmptyParts);
+    if (tokens.size() < 2)
+        return false;
+    name = tokens.at(0);
+    currentSHA= tokens.at(1);
+    toolTip.clear();
+    return true;
+}
+
+static inline Qt::ItemFlags typeToModelFlags(BranchModel::Type t)
+{
+    Qt::ItemFlags rc = Qt::ItemIsSelectable|Qt::ItemIsEnabled;
+    if (t == BranchModel::BranchModel::LocalBranches)
+        rc |= Qt::ItemIsUserCheckable;
+    return rc;
+}
+
+// --- BranchModel
+BranchModel::BranchModel(GitClient *client, Type type, QObject *parent) :
+    QAbstractListModel(parent),
+    m_type(type),
+    m_flags(typeToModelFlags(type)),
+    m_client(client),
+    m_currentBranch(-1)
+{
+}
+
+int BranchModel::currentBranch() const
+{
+    return m_currentBranch;
+}
+
+QString BranchModel::branchName(int row) const
+{
+    return m_branches.at(row).name;
+}
+
+int BranchModel::rowCount(const QModelIndex & /* parent */) const
+{
+    return m_branches.size();
+}
+
+QVariant BranchModel::data(const QModelIndex &index, int role) const
+{
+    const int row = index.row();
+    switch (role) {
+        case Qt::DisplayRole:
+        return branchName(row);
+        case Qt::ToolTipRole:
+        if (m_branches.at(row).toolTip.isEmpty())
+            m_branches.at(row).toolTip = toolTip(m_branches.at(row).currentSHA);
+        return m_branches.at(row).toolTip;
+        break;
+        case Qt::CheckStateRole:
+        if (m_type == RemoteBranches)
+            return QVariant();
+        return row == m_currentBranch ? Qt::Checked : Qt::Unchecked;
+        default:
+        break;
+    }
+    return QVariant();
+}
+
+Qt::ItemFlags BranchModel::flags(const QModelIndex & /*index */) const
+{
+    return m_flags;
+}
+
+bool BranchModel::refresh(const QString &workingDirectory, QString *errorMessage)
+{
+    // Run branch command with verbose.
+    QStringList branchArgs(QLatin1String("-v"));
+    QString output;
+    if (m_type == RemoteBranches)
+        branchArgs.push_back(QLatin1String("-r"));
+    if (!m_client->synchronousBranchCmd(workingDirectory, branchArgs, &output, errorMessage))
+        return false;
+    if (debug)
+        qDebug() << Q_FUNC_INFO << workingDirectory << output;
+    // Parse output
+    m_workingDirectory = workingDirectory;
+    m_branches.clear();
+    m_currentBranch = -1;
+    const QStringList branches = output.split(QLatin1Char('\n'));
+    const int branchCount = branches.size();
+    bool isCurrent;
+    for (int b = 0; b < branchCount; b++) {
+        Branch newBranch;
+        if (newBranch.parse(branches.at(b), &isCurrent)) {
+            m_branches.push_back(newBranch);
+            if (isCurrent)
+                m_currentBranch = b;
+        }
+    }
+    reset();
+    return true;
+}
+
+QString BranchModel::toolTip(const QString &sha) const
+{
+    // Show the sha description excluding diff as toolTip
+    QString output;
+    QString errorMessage;
+    if (!m_client->synchronousShow(m_workingDirectory, sha, &output, &errorMessage))
+        return errorMessage;
+    // Remove 'diff' output
+    const int diffPos = output.indexOf(QLatin1String("\ndiff --"));
+    if (diffPos != -1)
+        output.remove(diffPos, output.size() - diffPos);
+    return output;
+}
+
+}
+}
+
diff --git a/src/plugins/git/branchmodel.h b/src/plugins/git/branchmodel.h
new file mode 100644
index 00000000000..5083a1c377c
--- /dev/null
+++ b/src/plugins/git/branchmodel.h
@@ -0,0 +1,58 @@
+#ifndef BRANCHMODEL_H
+#define BRANCHMODEL_H
+
+#include <QtCore/QAbstractListModel>
+#include <QtCore/QList>
+
+namespace Git {
+    namespace Internal {
+
+class GitClient;
+
+/* A model to list git branches in a simple list of branch names. Local
+ * branches will have a read-only checkbox indicating the current one. The
+ * [delayed] tooltip describes the latest commit. */
+
+class BranchModel : public QAbstractListModel {
+public:
+    enum Type { LocalBranches, RemoteBranches };
+
+    explicit BranchModel(GitClient *client,
+                         Type type = LocalBranches,
+                         QObject *parent = 0);
+
+    bool refresh(const QString &workingDirectory, QString *errorMessage);
+
+    int currentBranch() const;
+    QString branchName(int row) const;
+
+    // QAbstractListModel
+    virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
+    virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+    virtual Qt::ItemFlags flags(const QModelIndex &index) const;
+
+private:
+    QString toolTip(const QString &sha) const;
+
+    struct Branch {
+        bool parse(const QString &line, bool *isCurrent);
+
+        QString name;
+        QString currentSHA;
+        mutable QString toolTip;
+    };
+    typedef QList<Branch> BranchList;
+
+    const Type m_type;
+    const Qt::ItemFlags m_flags;
+    GitClient *m_client;
+
+    QString m_workingDirectory;
+    BranchList m_branches;
+    int m_currentBranch;
+};
+
+}
+}
+
+#endif // BRANCHMODEL_H
diff --git a/src/plugins/git/git.pro b/src/plugins/git/git.pro
index 3c4ca176cb5..7f4ed2fc0cc 100644
--- a/src/plugins/git/git.pro
+++ b/src/plugins/git/git.pro
@@ -6,7 +6,6 @@ include(../../plugins/texteditor/texteditor.pri)
 include(../../plugins/coreplugin/coreplugin.pri)
 include(../../plugins/vcsbase/vcsbase.pri)
 include(../../libs/utils/utils.pri)
-
 HEADERS += gitplugin.h \
     gitconstants.h \
     gitoutputwindow.h \
@@ -19,8 +18,9 @@ HEADERS += gitplugin.h \
     gitsubmiteditorwidget.h \
     gitsubmiteditor.h \
     gitversioncontrol.h \
-    gitsettings.h
-
+    gitsettings.h \
+    branchdialog.h \
+    branchmodel.h
 SOURCES += gitplugin.cpp \
     gitoutputwindow.cpp \
     gitclient.cpp \
@@ -32,8 +32,10 @@ SOURCES += gitplugin.cpp \
     gitsubmiteditorwidget.cpp \
     gitsubmiteditor.cpp \
     gitversioncontrol.cpp \
-    gitsettings.cpp
-
+    gitsettings.cpp \
+    branchdialog.cpp \
+    branchmodel.cpp
 FORMS += changeselectiondialog.ui \
     settingspage.ui \
-    gitsubmitpanel.ui
+    gitsubmitpanel.ui \
+    branchdialog.ui
diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
index 83dafdc1b66..f3d507171d2 100644
--- a/src/plugins/git/gitclient.cpp
+++ b/src/plugins/git/gitclient.cpp
@@ -276,6 +276,13 @@ void GitClient::blame(const QString &workingDirectory, const QString &fileName)
     executeGit(workingDirectory, arguments, editor);
 }
 
+void GitClient::checkoutBranch(const QString &workingDirectory, const QString &branch)
+{
+    QStringList arguments(QLatin1String("checkout"));
+    arguments <<  branch;
+    executeGit(workingDirectory, arguments, 0, true);
+}
+
 void GitClient::checkout(const QString &workingDirectory, const QString &fileName)
 {
     // Passing an empty argument as the file name is very dangereous, since this makes
@@ -395,6 +402,41 @@ bool GitClient::synchronousStash(const QString &workingDirectory, QString *error
     return true;
 }
 
+bool GitClient::synchronousBranchCmd(const QString &workingDirectory, QStringList branchArgs,
+                                     QString *output, QString *errorMessage)
+{
+    if (Git::Constants::debug)
+        qDebug() << Q_FUNC_INFO << workingDirectory << branchArgs;
+    branchArgs.push_front(QLatin1String("branch"));
+    QByteArray outputText;
+    QByteArray errorText;
+    const bool rc = synchronousGit(workingDirectory, branchArgs, &outputText, &errorText);
+    if (!rc) {
+        *errorMessage = tr("Unable to run branch command: %1: %2").arg(workingDirectory, QString::fromLocal8Bit(errorText));
+        return false;
+    }
+    *output = QString::fromLocal8Bit(outputText).remove(QLatin1Char('\r'));
+    return true;
+}
+
+bool GitClient::synchronousShow(const QString &workingDirectory, const QString &id,
+                                 QString *output, QString *errorMessage)
+{
+    if (Git::Constants::debug)
+        qDebug() << Q_FUNC_INFO << workingDirectory << id;
+    QStringList args(QLatin1String("show"));
+    args << id;
+    QByteArray outputText;
+    QByteArray errorText;
+    const bool rc = synchronousGit(workingDirectory, args, &outputText, &errorText);
+    if (!rc) {
+        *errorMessage = tr("Unable to run show: %1: %2").arg(workingDirectory, QString::fromLocal8Bit(errorText));
+        return false;
+    }
+    *output = QString::fromLocal8Bit(outputText).remove(QLatin1Char('\r'));
+    return true;
+}
+
 
 void GitClient::executeGit(const QString &workingDirectory, const QStringList &arguments,
                            VCSBase::VCSBaseEditor* editor,
diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h
index af45bbb9a36..f09daa00ab8 100644
--- a/src/plugins/git/gitclient.h
+++ b/src/plugins/git/gitclient.h
@@ -86,6 +86,7 @@ public:
     void blame(const QString &workingDirectory, const QString &fileName);
     void showCommit(const QString &workingDirectory, const QString &commit);
     void checkout(const QString &workingDirectory, const QString &file);
+    void checkoutBranch(const QString &workingDirectory, const QString &branch);
     void hardReset(const QString &workingDirectory, const QString &commit);
     void addFile(const QString &workingDirectory, const QString &fileName);
     bool synchronousAdd(const QString &workingDirectory, const QStringList &files);
@@ -93,6 +94,11 @@ public:
     bool synchronousReset(const QString &workingDirectory, const QStringList &files, QString *errorMessage);
     bool synchronousCheckout(const QString &workingDirectory, const QStringList &files, QString *errorMessage);
     bool synchronousStash(const QString &workingDirectory, QString *errorMessage);
+    bool synchronousBranchCmd(const QString &workingDirectory, QStringList branchArgs,
+                              QString *output, QString *errorMessage);
+    bool synchronousShow(const QString &workingDirectory, const QString &id,
+                              QString *output, QString *errorMessage);
+
     void pull(const QString &workingDirectory);
     void push(const QString &workingDirectory);
 
diff --git a/src/plugins/git/gitplugin.cpp b/src/plugins/git/gitplugin.cpp
index 85af681d209..fe2d93adbff 100644
--- a/src/plugins/git/gitplugin.cpp
+++ b/src/plugins/git/gitplugin.cpp
@@ -40,6 +40,7 @@
 #include "giteditor.h"
 #include "gitsubmiteditor.h"
 #include "gitversioncontrol.h"
+#include "branchdialog.h"
 
 #include <coreplugin/icore.h>
 #include <coreplugin/coreconstants.h>
@@ -401,7 +402,7 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *error_message)
 
     gitContainer->addAction(createSeparator(actionManager, globalcontext, QLatin1String("Git.Sep.Branch"), this));
 
-    m_branchListAction = new QAction(tr("List branches"), this);
+    m_branchListAction = new QAction(tr("Branches..."), this);
     command = actionManager->registerAction(m_branchListAction, "Git.BranchList", globalcontext);
     command->setAttribute(Core::ICommand::CA_UpdateText);
     connect(m_branchListAction, SIGNAL(triggered()), this, SLOT(branchList()));
@@ -494,7 +495,6 @@ QString GitPlugin::getWorkingDirectory()
         qDebug() << Q_FUNC_INFO << "file" << workingDirectory;
 
     if (workingDirectory.isEmpty()) {
-        m_outputWindow->clearContents();
         m_outputWindow->append(tr("Could not find working directory"));
         m_outputWindow->popup(false);
         return QString();
@@ -740,8 +740,21 @@ void GitPlugin::stashPop()
 void GitPlugin::branchList()
 {
     const QString workingDirectory = getWorkingDirectory();
-    if (!workingDirectory.isEmpty())
-        m_gitClient->branchList(workingDirectory);
+    if (workingDirectory.isEmpty())
+        return;
+#ifndef USE_BRANCHDIALOG
+    QString errorMessage;
+    BranchDialog dialog(m_core->mainWindow());
+
+    if (!dialog.init(m_gitClient, workingDirectory, &errorMessage)) {
+        m_outputWindow->append(errorMessage);
+        m_outputWindow->popup(false);
+        return;
+    }
+    dialog.exec();
+#else
+    m_gitClient->branchList(workingDirectory);
+#endif
 }
 
 void GitPlugin::stashList()
-- 
GitLab