diff --git a/src/plugins/git/branchadddialog.cpp b/src/plugins/git/branchadddialog.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..64e2d32b2ee4bca7d1a0e8e115d77b7aec6c9abd
--- /dev/null
+++ b/src/plugins/git/branchadddialog.cpp
@@ -0,0 +1,47 @@
+#include "branchadddialog.h"
+#include "ui_branchadddialog.h"
+
+namespace Git {
+namespace Internal {
+
+BranchAddDialog::BranchAddDialog(QWidget *parent) :
+    QDialog(parent),
+    m_ui(new Ui::BranchAddDialog)
+{
+    m_ui->setupUi(this);
+}
+
+BranchAddDialog::~BranchAddDialog()
+{
+    delete m_ui;
+}
+
+void BranchAddDialog::setBranchName(const QString &n)
+{
+    m_ui->branchNameEdit->setText(n);
+    m_ui->branchNameEdit->selectAll();
+}
+
+QString BranchAddDialog::branchName() const
+{
+    return m_ui->branchNameEdit->text();
+}
+
+void BranchAddDialog::setTrackedBranchName(const QString &name, bool remote)
+{
+    m_ui->trackingCheckBox->setVisible(true);
+    if (!name.isEmpty())
+        m_ui->trackingCheckBox->setText(remote ? tr("Track remote branch \'%1\'").arg(name) :
+                                                 tr("Track local branch \'%1\'").arg(name));
+    else
+        m_ui->trackingCheckBox->setVisible(false);
+    m_ui->trackingCheckBox->setChecked(remote);
+}
+
+bool BranchAddDialog::track()
+{
+    return m_ui->trackingCheckBox->isVisible() && m_ui->trackingCheckBox->isChecked();
+}
+
+} // namespace Internal
+} // namespace Git
diff --git a/src/plugins/git/branchadddialog.h b/src/plugins/git/branchadddialog.h
new file mode 100644
index 0000000000000000000000000000000000000000..9fec0966a388ff83a84dc650b6d0c27ecac9b911
--- /dev/null
+++ b/src/plugins/git/branchadddialog.h
@@ -0,0 +1,36 @@
+#ifndef BRANCHADDDIALOG_H
+#define BRANCHADDDIALOG_H
+
+#include <QDialog>
+
+namespace Git {
+namespace Internal {
+
+
+namespace Ui {
+    class BranchAddDialog;
+}
+
+class BranchAddDialog : public QDialog
+{
+    Q_OBJECT
+
+public:
+    explicit BranchAddDialog(QWidget *parent = 0);
+    ~BranchAddDialog();
+
+    void setBranchName(const QString &);
+    QString branchName() const;
+
+    void setTrackedBranchName(const QString &name, bool remote);
+
+    bool track();
+
+private:
+    Ui::BranchAddDialog *m_ui;
+};
+
+} // namespace Internal
+} // namespace Git
+
+#endif // BRANCHADDDIALOG_H
diff --git a/src/plugins/git/branchadddialog.ui b/src/plugins/git/branchadddialog.ui
new file mode 100644
index 0000000000000000000000000000000000000000..38298fca2d724cb03c82e5d8ea384e8d216634d5
--- /dev/null
+++ b/src/plugins/git/branchadddialog.ui
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Git::Internal::BranchAddDialog</class>
+ <widget class="QDialog" name="Git::Internal::BranchAddDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>400</width>
+    <height>134</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Dialog</string>
+  </property>
+  <layout class="QGridLayout" name="gridLayout">
+   <item row="0" column="0">
+    <widget class="QLabel" name="branchNameLabel">
+     <property name="text">
+      <string>Branch Name:</string>
+     </property>
+    </widget>
+   </item>
+   <item row="0" column="1">
+    <widget class="QLineEdit" name="branchNameEdit"/>
+   </item>
+   <item row="1" column="0" colspan="2">
+    <widget class="QCheckBox" name="trackingCheckBox">
+     <property name="text">
+      <string>CheckBox</string>
+     </property>
+    </widget>
+   </item>
+   <item row="2" column="0" colspan="2">
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>Git::Internal::BranchAddDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>Git::Internal::BranchAddDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/git/branchdialog.cpp b/src/plugins/git/branchdialog.cpp
index 175325b37706cf92d8512939c1a10a9e9d083923..cb57a34417cc477c208af44dbe0b5837036debb4 100644
--- a/src/plugins/git/branchdialog.cpp
+++ b/src/plugins/git/branchdialog.cpp
@@ -31,12 +31,14 @@
 **************************************************************************/
 
 #include "branchdialog.h"
+#include "branchadddialog.h"
 #include "branchmodel.h"
 #include "gitclient.h"
 #include "gitplugin.h"
 #include "ui_branchdialog.h"
 #include "stashdialog.h" // Label helpers
 
+#include <utils/checkablemessagebox.h>
 #include <vcsbase/vcsbaseoutputwindow.h>
 
 #include <QtGui/QItemSelectionModel>
@@ -45,42 +47,13 @@
 
 #include <QtCore/QDebug>
 
-enum { debug = 0 };
-
-// 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;
-}
-
-// Helper to select a row. No sooner said then done
-static inline void selectListRow(QAbstractItemView *iv, int row)
-{
-    const QModelIndex index = iv->model()->index(row, 0);
-    iv->selectionModel()->select(index, QItemSelectionModel::Select);
-}
-
 namespace Git {
-    namespace Internal {
-
-static inline GitClient *gitClient()
-{
-    return GitPlugin::instance()->gitClient();
-}
+namespace Internal {
 
 BranchDialog::BranchDialog(QWidget *parent) :
     QDialog(parent),
     m_ui(new Ui::BranchDialog),
-    m_checkoutButton(0),
-    m_diffButton(0),
-    m_logButton(0),
-    m_refreshButton(0),
-    m_deleteButton(0),
-    m_localModel(new LocalBranchModel(gitClient(), this)),
-    m_remoteModel(new RemoteBranchModel(gitClient(), this))
+    m_model(new BranchModel(GitPlugin::instance()->gitClient(), this))
 {
     setModal(false);
     setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
@@ -88,273 +61,135 @@ BranchDialog::BranchDialog(QWidget *parent) :
 
     m_ui->setupUi(this);
 
-    m_checkoutButton = m_ui->buttonBox->addButton(tr("Checkout"), QDialogButtonBox::ActionRole);
-    connect(m_checkoutButton, SIGNAL(clicked()), this, SLOT(slotCheckoutSelectedBranch()));
-
-    m_diffButton = m_ui->buttonBox->addButton(tr("Diff"), QDialogButtonBox::ActionRole);
-    connect(m_diffButton, SIGNAL(clicked()), this, SLOT(slotDiffSelected()));
-
-    m_logButton = m_ui->buttonBox->addButton(tr("Log"), QDialogButtonBox::ActionRole);
-    connect(m_logButton, SIGNAL(clicked()), this, SLOT(slotLog()));
+    connect(m_ui->refreshButton, SIGNAL(clicked()), this, SLOT(refresh()));
+    connect(m_ui->addButton, SIGNAL(clicked()), this, SLOT(add()));
+    connect(m_ui->checkoutButton, SIGNAL(clicked()), this, SLOT(checkout()));
+    connect(m_ui->removeButton, SIGNAL(clicked()), this, SLOT(remove()));
+    connect(m_ui->diffButton, SIGNAL(clicked()), this, SLOT(diff()));
+    connect(m_ui->logButton, SIGNAL(clicked()), this, SLOT(log()));
 
-    m_refreshButton = m_ui->buttonBox->addButton(tr("Refresh"), QDialogButtonBox::ActionRole);
-    connect(m_refreshButton, SIGNAL(clicked()), this, SLOT(slotRefresh()));
+    m_ui->branchView->setModel(m_model);
 
-    m_deleteButton = m_ui->buttonBox->addButton(tr("Delete..."), QDialogButtonBox::ActionRole);
-    connect(m_deleteButton, SIGNAL(clicked()), this, SLOT(slotDeleteSelectedBranch()));
+    connect(m_ui->branchView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
+            this, SLOT(enableButtons()));
 
-    connect(m_ui->localBranchListView, SIGNAL(doubleClicked(QModelIndex)), this,
-            SLOT(slotLocalBranchActivated()));
-    connect(m_ui->remoteBranchListView, SIGNAL(doubleClicked(QModelIndex)), this,
-            SLOT(slotRemoteBranchActivated(QModelIndex)));
-
-    connect(m_localModel, SIGNAL(newBranchEntered(QString)), this, SLOT(slotCreateLocalBranch(QString)));
-    m_ui->localBranchListView->setModel(m_localModel);
-    m_ui->remoteBranchListView->setModel(m_remoteModel);
-
-    connect(m_ui->localBranchListView->selectionModel(),
-            SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
-            this, SLOT(slotEnableButtons(QItemSelection)));
-    connect(m_ui->remoteBranchListView->selectionModel(),
-            SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
-            this, SLOT(slotEnableButtons(QItemSelection)));
-
-    slotEnableButtons();
+    enableButtons();
 }
 
 BranchDialog::~BranchDialog()
 {
     delete m_ui;
+    delete m_model;
+    m_model = 0;
 }
 
 void BranchDialog::refresh(const QString &repository, bool force)
 {
     if (m_repository == repository && !force)
-            return;
-        // Refresh
+        return;
+
     m_repository = repository;
     m_ui->repositoryLabel->setText(StashDialog::msgRepositoryLabel(m_repository));
-    if (m_repository.isEmpty()) {
-        m_localModel->clear();
-        m_remoteModel->clear();
-    } else {
-        QString errorMessage;
-        const bool success = m_localModel->refresh(m_repository, &errorMessage)
-                             && m_remoteModel->refresh(m_repository, &errorMessage);
-        if (!success)
-            VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
-    }
-    slotEnableButtons();
-}
-
-int BranchDialog::selectedLocalBranchIndex() const
-{
-    return selectedRow(m_ui->localBranchListView);
-}
+    QString errorMessage;
+    if (!m_model->refresh(m_repository, &errorMessage))
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
 
-int BranchDialog::selectedRemoteBranchIndex() const
-{
-    return selectedRow(m_ui->remoteBranchListView);
+    m_ui->branchView->expandAll();
 }
 
-void BranchDialog::slotEnableButtons(const QItemSelection &selected)
+void BranchDialog::enableButtons()
 {
-    if (!selected.indexes().isEmpty()) {
-        if (selected.indexes().at(0).model() == m_localModel)
-            m_ui->remoteBranchListView->clearSelection();
-        else
-            m_ui->localBranchListView->clearSelection();
-    }
+    QModelIndex idx = selectedIndex();
+    const bool hasSelection = idx.isValid();
+    const bool currentSelected = hasSelection && idx == m_model->currentBranch();
+    const bool isLocal = m_model->isLocal(idx);
+    const bool isLeaf = m_model->isLeaf(idx);
 
-    // We can switch to or delete branches that are not current.
-    const int selectedLocalRow = selectedLocalBranchIndex();
-    const bool hasRepository = !m_repository.isEmpty();
-    const bool hasLocalSelection = selectedLocalRow != -1 && !m_localModel->isNewBranchRow(selectedLocalRow);
-    const bool otherLocalSelected = hasLocalSelection && selectedLocalRow != m_localModel->currentBranch();
-    const bool branchSelected = hasLocalSelection || selectedRemoteBranchIndex() != -1;
-
-    m_checkoutButton->setEnabled(otherLocalSelected);
-    m_diffButton->setEnabled(branchSelected);
-    m_logButton->setEnabled(branchSelected);
-    m_deleteButton->setEnabled(otherLocalSelected);
-    m_refreshButton->setEnabled(hasRepository);
-    // Also disable <New Branch> entry of list view
-    m_ui->localBranchListView->setEnabled(hasRepository);
-    m_ui->remoteBranchListView->setEnabled(hasRepository);
+    m_ui->removeButton->setEnabled(hasSelection && !currentSelected && isLocal && isLeaf);
+    m_ui->logButton->setEnabled(hasSelection && isLeaf);
+    m_ui->diffButton->setEnabled(hasSelection && isLeaf);
+    m_ui->checkoutButton->setEnabled(hasSelection && !currentSelected && isLocal && isLeaf);
 }
 
-void BranchDialog::slotRefresh()
+void BranchDialog::refresh()
 {
     refresh(m_repository, true);
 }
 
-void BranchDialog::selectLocalBranch(const QString &b)
+void BranchDialog::add()
 {
-    // Select the newly created branch
-    const int row = m_localModel->findBranchByName(b);
-    if (row != -1)
-        selectListRow(m_ui->localBranchListView, row);
-}
+    QString trackedBranch = m_model->branchName(selectedIndex());
+    bool isLocal = m_model->isLocal(selectedIndex());
+    if (trackedBranch.isEmpty()) {
+        trackedBranch = m_model->branchName(m_model->currentBranch());
+        isLocal = true;
+    }
 
-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;
-}
+    QStringList localNames = m_model->localBranchNames();
 
-/* 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 (!gitClient()->synchronousBranchCmd(m_repository, args, &output, &errorMessage))
-            break;
-        if (!m_localModel->refresh(m_repository, &errorMessage))
-            break;
-        ok = true;
-    } while (false);
-    slotEnableButtons();
-    if (!ok)
-        QMessageBox::warning(this, tr("Failed to delete branch"), errorMessage);
-}
+    QString suggestedNameBase = trackedBranch.mid(trackedBranch.lastIndexOf(QLatin1Char('/')) + 1);
+    QString suggestedName = suggestedNameBase;
+    int i = 2;
+    while (localNames.contains(suggestedName)) {
+        suggestedName = suggestedNameBase + QString::number(i);
+        ++i;
+    }
 
-void BranchDialog::slotCreateLocalBranch(const QString &branchName)
-{
-    // Create
-    QString output;
-    QString errorMessage;
-    bool ok = false;
-    do {
-        if (!gitClient()->synchronousBranchCmd(m_repository, QStringList(branchName), &output, &errorMessage))
-            break;
-        if (!m_localModel->refresh(m_repository, &errorMessage))
-            break;
-        ok = true;
-    } while (false);
-    if (!ok) {
-        QMessageBox::warning(this, tr("Failed to create branch"), errorMessage);
-        return;
+    BranchAddDialog branchAddDialog;
+    branchAddDialog.setBranchName(suggestedName);
+    branchAddDialog.setTrackedBranchName(trackedBranch, !isLocal);
+
+    if (branchAddDialog.exec() == QDialog::Accepted && m_model) {
+        QModelIndex idx = m_model->addBranch(branchAddDialog.branchName(), branchAddDialog.track(), trackedBranch);
+        m_ui->branchView->selectionModel()->select(idx, QItemSelectionModel::Clear
+                                                        | QItemSelectionModel::Select
+                                                        | QItemSelectionModel::Current);
+        m_ui->branchView->scrollTo(idx);
     }
-    selectLocalBranch(branchName);
 }
 
-void BranchDialog::slotLocalBranchActivated()
+void BranchDialog::checkout()
 {
-    if (m_checkoutButton->isEnabled())
-        m_checkoutButton->animateClick();
-}
+    QModelIndex idx = selectedIndex();
+    Q_ASSERT(m_model->isLocal(idx));
 
-void BranchDialog::slotDiffSelected()
-{
-    int idx = selectedLocalBranchIndex();
-    if (idx != -1) {
-        gitClient()->diffBranch(m_repository, QStringList(), m_localModel->branchName(idx));
-        return;
-    }
-    idx = selectedRemoteBranchIndex();
-    if (idx != -1)
-        gitClient()->diffBranch(m_repository, QStringList(), m_remoteModel->branchName(idx));
+    m_model->checkoutBranch(idx);
 }
 
-void BranchDialog::slotLog()
+/* Prompt to delete a local branch and do so. */
+void BranchDialog::remove()
 {
-    int idx = selectedLocalBranchIndex();
-    if (idx != -1) {
-        gitClient()->graphLog(m_repository, m_localModel->branchName(idx));
+    QModelIndex selected = selectedIndex();
+    Q_ASSERT(selected != m_model->currentBranch()); // otherwise the button would not be enabled!
+
+    QString branchName = m_model->branchName(selected);
+    if (branchName.isEmpty())
         return;
-    }
-    idx = selectedRemoteBranchIndex();
-    if (idx != -1)
-        gitClient()->graphLog(m_repository, m_remoteModel->branchName(idx));
+
+    QString message = tr("Would you like to delete the branch '%1'?").arg(branchName);
+    bool wasMerged = m_model->branchIsMerged(selected);
+    if (!wasMerged)
+        message = tr("Would you like to delete the <b>unmerged</b> branch '%1'?").arg(branchName);
+
+    if (QMessageBox::question(this, tr("Delete Branch"), message, QMessageBox::Yes|QMessageBox::No,
+                              wasMerged ? QMessageBox::Yes : QMessageBox::No) == QMessageBox::Yes)
+        m_model->removeBranch(selected);
 }
 
-/* Ask to stash away changes and then close dialog and do an asynchronous
- * checkout. */
-void BranchDialog::slotCheckoutSelectedBranch()
+void BranchDialog::diff()
 {
-    const int idx = selectedLocalBranchIndex();
-    if (idx == -1)
-        return;
-    const QString name = m_localModel->branchName(idx);
-    QString errorMessage;
-    switch (gitClient()->ensureStash(m_repository, &errorMessage)) {
-        case GitClient::StashUnchanged:
-        case GitClient::Stashed:
-        case GitClient::NotStashed:
-        break;
-        case GitClient::StashCanceled:
+    QString branchName = m_model->branchName(selectedIndex());
+    if (branchName.isEmpty())
         return;
-        case GitClient::StashFailed:
-        QMessageBox::warning(this, tr("Failed to stash"), errorMessage);
-        return;
-    }
-    if (gitClient()->synchronousCheckoutBranch(m_repository, name, &errorMessage)) {
-        refresh(m_repository, true);
-    } else {
-        QMessageBox::warning(this, tr("Checkout failed"), errorMessage);
-    }
+    GitPlugin::instance()->gitClient()->diffBranch(m_repository, QStringList(), branchName);
 }
 
-void BranchDialog::slotRemoteBranchActivated(const QModelIndex &i)
+void BranchDialog::log()
 {
-    // Double click on a remote branch (origin/foo): Switch to matching
-    // local (foo) one or offer to create a tracking branch.
-    const QString remoteName = m_remoteModel->branchName(i.row());
-    // build the name of the corresponding local branch
-    // and look for it in the local model.
-    const int slashPos = remoteName.indexOf(QLatin1Char('/'));
-    if (slashPos == -1)
-        return;
-    const QString localBranch = remoteName.mid(slashPos + 1);
-    if (localBranch == QLatin1String("HEAD") || localBranch == QLatin1String("master"))
+    QString branchName = m_model->branchName(selectedIndex());
+    if (branchName.isEmpty())
         return;
-   const int localIndex = m_localModel->findBranchByName(localBranch);
-   if (debug)
-        qDebug() << Q_FUNC_INFO << remoteName << localBranch << localIndex;
-   // There is a matching a local one!
-   if (localIndex != -1) {
-       // Is it the current one? Just close.
-       if (m_localModel->currentBranch() == localIndex) {
-           accept();
-           return;
-       }
-       // Nope, select and trigger checkout
-       selectListRow(m_ui->localBranchListView, localIndex);
-       slotLocalBranchActivated();
-       return;
-    }
-    // Does not exist yet. Ask to create.
-    const QString msg = tr("Would you like to create a local branch '%1' tracking the remote branch '%2'?").arg(localBranch, remoteName);
-    if (!ask(tr("Create branch"), msg, true))
-        return;
-    QStringList args(QLatin1String("--track"));
-    args << localBranch << remoteName;
-    QString errorMessage;
-    bool ok = false;
-    do {
-        QString output;
-        if (!gitClient()->synchronousBranchCmd(m_repository, args, &output, &errorMessage))
-            break;
-        if (!m_localModel->refresh(m_repository, &errorMessage))
-            break;
-        ok = true;
-    } while (false);
-    if (!ok) {
-        QMessageBox::warning(this, tr("Failed to create a tracking branch"), errorMessage);
-        return;
-    }
-    // Select it
-    selectLocalBranch(localBranch);
+    GitPlugin::instance()->gitClient()->graphLog(m_repository, branchName);
 }
 
 void BranchDialog::changeEvent(QEvent *e)
@@ -369,5 +204,13 @@ void BranchDialog::changeEvent(QEvent *e)
     }
 }
 
+QModelIndex BranchDialog::selectedIndex()
+{
+    QModelIndexList selected = m_ui->branchView->selectionModel()->selectedIndexes();
+    if (selected.isEmpty())
+        return QModelIndex();
+    return selected.at(0);
+}
+
 } // namespace Internal
 } // namespace Git
diff --git a/src/plugins/git/branchdialog.h b/src/plugins/git/branchdialog.h
index 2fc9c7b031579e6c772e1d40087fa0eb6895b979..e1f240e5e0441a654d0d257363cf83fa3385d9fa 100644
--- a/src/plugins/git/branchdialog.h
+++ b/src/plugins/git/branchdialog.h
@@ -48,9 +48,8 @@ namespace Ui {
 class BranchDialog;
 }
 
-class GitClient;
-class LocalBranchModel;
-class RemoteBranchModel;
+class BranchAddDialog;
+class BranchModel;
 
 /**
  * Branch dialog. Displays a list of local branches at the top and remote
@@ -59,44 +58,33 @@ class RemoteBranchModel;
  */
 class BranchDialog : public QDialog {
     Q_OBJECT
-    Q_DISABLE_COPY(BranchDialog)
+
 public:
     explicit BranchDialog(QWidget *parent = 0);
-    virtual ~BranchDialog();
+    ~BranchDialog();
 
 public slots:
     void refresh(const QString &repository, bool force);
 
 private slots:
-    void slotEnableButtons(const QItemSelection &selected = QItemSelection());
-    void slotCheckoutSelectedBranch();
-    void slotDeleteSelectedBranch();
-    void slotDiffSelected();
-    void slotLog();
-    void slotRefresh();
-    void slotLocalBranchActivated();
-    void slotRemoteBranchActivated(const QModelIndex &);
-    void slotCreateLocalBranch(const QString &branchName);
+    void enableButtons();
+    void refresh();
+    void add();
+    void checkout();
+    void remove();
+    void diff();
+    void log();
 
 protected:
-    virtual void changeEvent(QEvent *e);
+    void changeEvent(QEvent *e);
 
 private:
-    bool ask(const QString &title, const QString &what, bool defaultButton);
-    void selectLocalBranch(const QString &b);
-
-    int selectedLocalBranchIndex() const;
-    int selectedRemoteBranchIndex() const;
+    QModelIndex selectedIndex();
 
     Ui::BranchDialog *m_ui;
-    QPushButton *m_checkoutButton;
-    QPushButton *m_diffButton;
-    QPushButton *m_logButton;
-    QPushButton *m_refreshButton;
-    QPushButton *m_deleteButton;
-
-    LocalBranchModel *m_localModel;
-    RemoteBranchModel *m_remoteModel;
+
+    BranchModel *m_model;
+
     QString m_repository;
 };
 
diff --git a/src/plugins/git/branchdialog.ui b/src/plugins/git/branchdialog.ui
index 872f7b19fa0f8ca429bf1ccc8417e31b8293bd65..1689119b66658e15aa513eaeb7de43329cf5b588 100644
--- a/src/plugins/git/branchdialog.ui
+++ b/src/plugins/git/branchdialog.ui
@@ -16,14 +16,33 @@
   <layout class="QVBoxLayout" name="verticalLayout_3">
    <item>
     <widget class="QGroupBox" name="infoGroupBox">
-     <layout class="QFormLayout" name="formLayout">
-      <item row="0" column="0" colspan="2">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <property name="topMargin">
+       <number>4</number>
+      </property>
+      <property name="bottomMargin">
+       <number>4</number>
+      </property>
+      <item>
        <widget class="QLabel" name="repositoryLabel">
         <property name="text">
          <string notr="true">Repository: Dummy</string>
         </property>
        </widget>
       </item>
+      <item>
+       <widget class="QPushButton" name="refreshButton">
+        <property name="sizePolicy">
+         <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+          <horstretch>0</horstretch>
+          <verstretch>0</verstretch>
+         </sizepolicy>
+        </property>
+        <property name="text">
+         <string>Re&amp;fresh</string>
+        </property>
+       </widget>
+      </item>
      </layout>
     </widget>
    </item>
@@ -32,21 +51,63 @@
      <property name="title">
       <string>Branches</string>
      </property>
-     <layout class="QVBoxLayout" name="verticalLayout">
-      <item>
-       <widget class="QListView" name="localBranchListView"/>
+     <layout class="QGridLayout" name="gridLayout">
+      <property name="topMargin">
+       <number>4</number>
+      </property>
+      <property name="bottomMargin">
+       <number>4</number>
+      </property>
+      <property name="verticalSpacing">
+       <number>9</number>
+      </property>
+      <item row="0" column="0" colspan="3">
+       <widget class="QTreeView" name="branchView">
+        <property name="rootIsDecorated">
+         <bool>false</bool>
+        </property>
+        <property name="uniformRowHeights">
+         <bool>true</bool>
+        </property>
+        <attribute name="headerVisible">
+         <bool>false</bool>
+        </attribute>
+       </widget>
       </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 row="1" column="0">
+       <widget class="QPushButton" name="addButton">
+        <property name="text">
+         <string>&amp;Add...</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="2">
+       <widget class="QPushButton" name="removeButton">
+        <property name="text">
+         <string>&amp;Remove</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="0">
+       <widget class="QPushButton" name="diffButton">
+        <property name="text">
+         <string>&amp;Diff</string>
+        </property>
+       </widget>
+      </item>
+      <item row="2" column="2">
+       <widget class="QPushButton" name="logButton">
+        <property name="text">
+         <string>&amp;Log</string>
+        </property>
+       </widget>
+      </item>
+      <item row="1" column="1">
+       <widget class="QPushButton" name="checkoutButton">
+        <property name="text">
+         <string>&amp;Checkout</string>
+        </property>
+       </widget>
       </item>
      </layout>
     </widget>
@@ -63,6 +124,16 @@
    </item>
   </layout>
  </widget>
+ <tabstops>
+  <tabstop>branchView</tabstop>
+  <tabstop>addButton</tabstop>
+  <tabstop>checkoutButton</tabstop>
+  <tabstop>removeButton</tabstop>
+  <tabstop>diffButton</tabstop>
+  <tabstop>logButton</tabstop>
+  <tabstop>buttonBox</tabstop>
+  <tabstop>refreshButton</tabstop>
+ </tabstops>
  <resources/>
  <connections>
   <connection>
diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp
index c209caf4e0ba4d9f1c3daed2ef794c10e2a3f579..428ddf3e6a917f9dcdb1fe65f4d2e1844b11f13f 100644
--- a/src/plugins/git/branchmodel.cpp
+++ b/src/plugins/git/branchmodel.cpp
@@ -33,260 +33,553 @@
 #include "branchmodel.h"
 #include "gitclient.h"
 
+#include <vcsbase/vcsbaseoutputwindow.h>
+
 #include <QtGui/QFont>
-#include <QtCore/QDebug>
 #include <QtCore/QRegExp>
 #include <QtCore/QTimer>
 
-enum { debug = 0 };
-
 namespace Git {
-    namespace Internal {
+namespace Internal {
+
+// --------------------------------------------------------------------------
+// BranchNode:
+// --------------------------------------------------------------------------
 
-// Parse a branch line: " *name sha description".
-bool RemoteBranchModel::Branch::parse(const QString &lineIn, bool *isCurrent)
+class BranchNode
 {
-    if (debug)
-        qDebug() << Q_FUNC_INFO << lineIn;
+public:
+    BranchNode() :
+        parent(0), current(false)
+    { }
+
+    BranchNode(const QString &n, const QString &s = QString(), bool c = false) :
+        parent(0), current(c), name(n), sha(s)
+    { }
+
+    ~BranchNode()
+    {
+        qDeleteAll(children);
+    }
 
-    *isCurrent = lineIn.startsWith(QLatin1String("* "));
-    if (lineIn.size() < 3)
-        return false;
+    BranchNode *rootNode()
+    {
+        return parent ? parent->rootNode() : this;
+    }
 
-    const QString branchInfo = lineIn.mid(2);
-    QStringList tokens;
-    if (*isCurrent && branchInfo.startsWith(QLatin1String("(no branch)")))
-        return false;
-    else
-        tokens = branchInfo.split(QLatin1Char(' '), QString::SkipEmptyParts);
-    if (tokens.size() < 2)
-        return false;
-    name = tokens.at(0);
-    currentSHA= tokens.at(1);
-    toolTip.clear();
-    return true;
-}
+    int count()
+    {
+        return children.count();
+    }
+
+    bool isLeaf()
+    {
+        return children.isEmpty();
+    }
+
+    bool childOf(BranchNode *node)
+    {
+        if (this == node)
+            return true;
+        return parent ? parent->childOf(node) : false;
+    }
+
+    bool isLocal()
+    {
+        BranchNode *rn = rootNode();
+        if (rn->isLeaf())
+            return false;
+        return childOf(rn->children.at(0));
+    }
+
+    BranchNode *childOfName(const QString &name)
+    {
+        for (int i = 0; i < children.count(); ++i) {
+            if (children.at(i)->name == name)
+                return children.at(i);
+        }
+        return 0;
+    }
+
+    QStringList fullName()
+    {
+        Q_ASSERT(isLeaf());
+
+        QStringList fn;
+        QList<BranchNode *> nodes;
+        BranchNode *current = this;
+        while (current->parent) {
+            nodes.prepend(current);
+            current = current->parent;
+        }
+
+        if (current->children.at(0) == nodes.at(0))
+            nodes.removeFirst(); // remove local branch designation
+
+        foreach (BranchNode *n, nodes)
+            fn.append(n->name);
+
+        return fn;
+    }
+
+    void insert(const QStringList path, BranchNode *n)
+    {
+        BranchNode *current = this;
+        for (int i = 0; i < path.count(); ++i) {
+            BranchNode *c = current->childOfName(path.at(i));
+            if (c)
+                current = c;
+            else
+                current = current->append(new BranchNode(path.at(i)));
+        }
+        current->append(n);
+    }
+
+    BranchNode *append(BranchNode *n)
+    {
+        n->parent = this;
+        children.append(n);
+        return n;
+    }
+
+    QStringList childrenNames()
+    {
+        if (children.count() > 0) {
+            QStringList names;
+            foreach (BranchNode *n, children) {
+                names.append(n->childrenNames());
+            }
+            return names;
+        }
+        return QStringList(fullName().join(QString('/')));
+    }
 
-// ------ RemoteBranchModel
-RemoteBranchModel::RemoteBranchModel(GitClient *client, QObject *parent) :
-    QAbstractListModel(parent),
-    m_flags(Qt::ItemIsSelectable|Qt::ItemIsEnabled),
-    m_client(client)
+    BranchNode *parent;
+    QList<BranchNode *> children;
+
+    bool current;
+    QString name;
+    QString sha;
+    mutable QString toolTip;
+};
+
+// --------------------------------------------------------------------------
+// BranchModel:
+// --------------------------------------------------------------------------
+
+BranchModel::BranchModel(GitClient *client, QObject *parent) :
+    QAbstractItemModel(parent),
+    m_client(client),
+    m_rootNode(new BranchNode)
 {
+    Q_ASSERT(m_client);
+    m_rootNode->append(new BranchNode(tr("Local Branches")));
 }
 
-bool RemoteBranchModel::refresh(const QString &workingDirectory, QString *errorMessage)
+BranchModel::~BranchModel()
 {
-    int currentBranch;
-    return refreshBranches(workingDirectory, true, &currentBranch, errorMessage);
+    delete m_rootNode;
 }
 
-QString RemoteBranchModel::branchName(int row) const
+QModelIndex BranchModel::index(int row, int column, const QModelIndex &parent) const
 {
-    return m_branches.at(row).name;
+    BranchNode *node = m_rootNode;
+    if (parent.isValid())
+        node = static_cast<BranchNode *>(parent.internalPointer());
+    if (row >= node->count())
+        return QModelIndex();
+    return createIndex(row, column, static_cast<void *>(node->children.at(row)));
 }
 
-QString RemoteBranchModel::workingDirectory() const
+QModelIndex BranchModel::parent(const QModelIndex &index) const
 {
-    return m_workingDirectory;
+    BranchNode *node = static_cast<BranchNode *>(index.internalPointer());
+    if (node->parent == m_rootNode)
+        return QModelIndex();
+    int row = node->parent->children.indexOf(node);
+    return createIndex(row, 0, static_cast<void *>(node->parent));
 }
 
-int RemoteBranchModel::branchCount() const
+int BranchModel::rowCount(const QModelIndex &parent) const
 {
-    return m_branches.size();
+    if (!parent.isValid())
+        return m_rootNode->count();
+    if (parent.column() != 0)
+        return 0;
+    return static_cast<BranchNode *>(parent.internalPointer())->count();
 }
 
-int RemoteBranchModel::rowCount(const QModelIndex & /* parent */) const
+int BranchModel::columnCount(const QModelIndex &parent) const
 {
-    return branchCount();
+    Q_UNUSED(parent);
+    return 1;
 }
 
-QVariant RemoteBranchModel::data(const QModelIndex &index, int role) const
+QVariant BranchModel::data(const QModelIndex &index, int role) const
 {
-    const int row = index.row();
+    BranchNode *node = static_cast<BranchNode *>(index.internalPointer());
+
     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;
-        default:
-        break;
+    case Qt::DisplayRole:
+    case Qt::EditRole:
+        return node->name;
+    case Qt::ToolTipRole:
+        if (!node->isLeaf())
+            return QVariant();
+        if (node->toolTip.isEmpty())
+            node->toolTip = toolTip(node->sha);
+        return node->toolTip;
+    case Qt::FontRole:
+    {
+        QFont font;
+        if (!node->isLeaf()) {
+            font.setBold(true);
+        } else if (node->current) {
+            font.setBold(true);
+            font.setUnderline(true);
+        }
+        return font;
+    }
+    default:
+        return QVariant();
     }
-    return QVariant();
 }
 
-Qt::ItemFlags RemoteBranchModel::flags(const QModelIndex & /* index */) const
+bool BranchModel::setData(const QModelIndex &index, const QVariant &value, int role)
 {
-    return m_flags;
-}
+    if (role != Qt::EditRole)
+        return false;
+    BranchNode *node = static_cast<BranchNode *>(index.internalPointer());
+
+    const QString newName = value.toString();
+    if (newName.isEmpty())
+        return false;
+
+    if (node->name == newName)
+        return true;
+
+    QStringList oldFullName = node->fullName();
+    node->name = newName;
+    QStringList newFullName = node->fullName();
 
-QString RemoteBranchModel::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;
+    if (!m_client->synchronousBranchCmd(m_workingDirectory,
+                                        QStringList() << QLatin1String("-m")
+                                                      << oldFullName.last()
+                                                      << newFullName.last(),
+                                        &output, &errorMessage)) {
+        node->name = oldFullName.last();
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
+        return false;
+    }
+
+    emit dataChanged(index, index);
+    return true;
 }
 
-bool RemoteBranchModel::runGitBranchCommand(const QString &workingDirectory, const QStringList &additionalArgs, QString *output, QString *errorMessage)
+Qt::ItemFlags BranchModel::flags(const QModelIndex &index) const
 {
-    return m_client->synchronousBranchCmd(workingDirectory, additionalArgs, output, errorMessage);
+    BranchNode *node = static_cast<BranchNode *>(index.internalPointer());
+    if (node->isLeaf() && node->isLocal())
+        return Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsEnabled;
+    else
+        return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
 }
 
-void RemoteBranchModel::clear()
+void BranchModel::clear()
 {
-    if (!m_branches.isEmpty()) {
-        m_branches.clear();
-        reset();
+    while (m_rootNode->count() > 1) {
+        BranchNode *n = m_rootNode->children.takeLast();
+        delete n;
+    }
+    BranchNode *locals = m_rootNode->children.at(0);
+    while (locals->count()) {
+        BranchNode *n = locals->children.takeLast();
+        delete n;
     }
 }
 
-bool RemoteBranchModel::refreshBranches(const QString &workingDirectory, bool remoteBranches,
-                                        int *currentBranch, QString *errorMessage)
+bool BranchModel::refresh(const QString &workingDirectory, QString *errorMessage)
 {
-    // Run branch command with verbose.
+    if (workingDirectory.isEmpty())
+        return false;
+
     QStringList branchArgs;
-    branchArgs << QLatin1String(GitClient::noColorOption) << QLatin1String("-v");
+    branchArgs << QLatin1String(GitClient::noColorOption)
+               << QLatin1String("-v") << QLatin1String("-a");
     QString output;
-    *currentBranch = -1;
-    if (remoteBranches)
-        branchArgs.push_back(QLatin1String("-r"));
-    if (!runGitBranchCommand(workingDirectory, branchArgs, &output, errorMessage))
+    if (!m_client->synchronousBranchCmd(workingDirectory, branchArgs, &output, errorMessage)) {
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(*errorMessage);
         return false;
-    if (debug)
-        qDebug() << Q_FUNC_INFO << workingDirectory << output;
-    // Parse output
-    m_workingDirectory = workingDirectory;
-    m_branches.clear();
-    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)
-                *currentBranch = b;
-        }
     }
-    reset();
+
+    beginResetModel();
+
+    clear();
+
+    m_workingDirectory = workingDirectory;
+    const QStringList lines = output.split(QLatin1Char('\n'));
+    foreach (const QString &l, lines)
+        parseOutputLine(l);
+
+    endResetModel();
     return true;
 }
 
-int RemoteBranchModel::findBranchByName(const QString &name) const
+void BranchModel::renameBranch(const QString &oldName, const QString &newName)
 {
-    const int count = branchCount();
-    for (int i = 0; i < count; i++)
-        if (branchName(i) == name)
-            return i;
-    return -1;
+    QString errorMessage;
+    QString output;
+    if (!m_client->synchronousBranchCmd(m_workingDirectory,
+                                        QStringList() << QLatin1String("-m") << oldName << newName,
+                                        &output, &errorMessage))
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
+    else
+        refresh(m_workingDirectory, &errorMessage);
 }
 
-// --- LocalBranchModel
-LocalBranchModel::LocalBranchModel(GitClient *client, QObject *parent) :
-    RemoteBranchModel(client, parent),
-    m_typeHere(tr("<New branch>")),
-    m_typeHereToolTip(tr("Type to create a new branch")),
-    m_currentBranch(-1)
+QString BranchModel::workingDirectory() const
 {
+    return m_workingDirectory;
 }
 
-int LocalBranchModel::currentBranch() const
+GitClient *BranchModel::client() const
 {
-    return m_currentBranch;
+    return m_client;
 }
 
-bool LocalBranchModel::isNewBranchRow(int row) const
+QModelIndex BranchModel::currentBranch() const
 {
-    return row >= branchCount();
+    if (!m_rootNode || !m_rootNode->count())
+        return QModelIndex();
+    BranchNode *localBranches = m_rootNode->children.at(0);
+    QModelIndex localIdx = index(0, 0, QModelIndex());
+    for (int i = 0; i < localBranches->count(); ++i) {
+        if (localBranches->children.at(i)->current)
+            return index(i, 0, localIdx);
+    }
+    return QModelIndex();
 }
 
-Qt::ItemFlags LocalBranchModel::flags(const QModelIndex & index) const
+QString BranchModel::branchName(const QModelIndex &idx) const
 {
-    if (isNewBranchRow(index))
-        return Qt::ItemIsEditable|Qt::ItemIsSelectable|Qt::ItemIsEnabled| Qt::ItemIsUserCheckable;
-    return RemoteBranchModel::flags(index) | Qt::ItemIsUserCheckable;
+    if (!idx.isValid())
+        return QString();
+    BranchNode *node = static_cast<BranchNode *>(idx.internalPointer());
+    if (!node->isLeaf())
+        return QString();
+    QStringList path = node->fullName();
+    return path.join(QString('/'));
 }
 
-int LocalBranchModel::rowCount(const QModelIndex & /* parent */) const
+QStringList BranchModel::localBranchNames() const
 {
-    return branchCount() + 1;
+    if (!m_rootNode || m_rootNode->children.isEmpty())
+        return QStringList();
+
+    return m_rootNode->children.at(0)->childrenNames();
 }
 
-QVariant LocalBranchModel::data(const QModelIndex &index, int role) const
+QString BranchModel::sha(const QModelIndex &idx) const
 {
-    if (isNewBranchRow(index)) {
-        switch (role) {
-        case Qt::DisplayRole:
-            return m_typeHere;
-        case Qt::ToolTipRole:
-            return m_typeHereToolTip;
-        }
-        return QVariant();
-    }
+    if (!idx.isValid())
+        return QString();
+    BranchNode *node = static_cast<BranchNode *>(idx.internalPointer());
+    return node->sha;
+}
 
-    if (role == Qt::FontRole && index.row() == m_currentBranch) {
-        QFont font = RemoteBranchModel::data(index, role).value<QFont>();
-        font.setBold(true);
-        font.setUnderline(true);
-        return font;
-    }
-    return RemoteBranchModel::data(index, role);
+bool BranchModel::isLocal(const QModelIndex &idx) const
+{
+    if (!idx.isValid())
+        return false;
+    BranchNode *node = static_cast<BranchNode *>(idx.internalPointer());
+    return node->isLocal();
 }
 
-void LocalBranchModel::clear()
+bool BranchModel::isLeaf(const QModelIndex &idx) const
 {
-    m_currentBranch = -1;
-    m_newBranch.clear();
-    RemoteBranchModel::clear();
+    if (!idx.isValid())
+        return false;
+    BranchNode *node = static_cast<BranchNode *>(idx.internalPointer());
+    return node->isLeaf();
 }
 
-bool LocalBranchModel::refresh(const QString &workingDirectory, QString *errorMessage)
+void BranchModel::removeBranch(const QModelIndex &idx)
 {
-    return refreshBranches(workingDirectory, false, &m_currentBranch, errorMessage);
+    QString branch = branchName(idx);
+    if (branch.isEmpty())
+        return;
+
+    QString errorMessage;
+    QString output;
+    QStringList args;
+
+    args << QLatin1String("-D") << branch;
+    if (!m_client->synchronousBranchCmd(m_workingDirectory, args, &output, &errorMessage)) {
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
+        return;
+    }
+
+    QModelIndex parentIdx = parent(idx);
+    beginRemoveRows(parentIdx, idx.row(), idx.row());
+    static_cast<BranchNode *>(parentIdx.internalPointer())->children.removeAt(parentIdx.row());
+    delete static_cast<BranchNode *>(idx.internalPointer());
+    endRemoveRows();
 }
 
-bool LocalBranchModel::checkNewBranchName(const QString &name) const
+void BranchModel::checkoutBranch(const QModelIndex &idx)
 {
-    // Syntax
-    const QRegExp pattern(QLatin1String("[a-zA-Z0-9-_]+"));
-    if (!pattern.exactMatch(name))
-        return false;
-    // existing
-    if (findBranchByName(name) != -1)
-        return false;
-    return true;
+    QString branch = branchName(idx);
+    if (branch.isEmpty())
+        return;
+
+    QString errorMessage;
+    switch (m_client->ensureStash(m_workingDirectory, &errorMessage)) {
+    case GitClient::StashUnchanged:
+    case GitClient::Stashed:
+    case GitClient::NotStashed:
+        break;
+    case GitClient::StashCanceled:
+        return;
+    case GitClient::StashFailed:
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
+        return;
+    }
+    if (m_client->synchronousCheckoutBranch(m_workingDirectory, branch, &errorMessage)) {
+        if (errorMessage.isEmpty()) {
+            static_cast<BranchNode *>(currentBranch().internalPointer())->current = false;
+            emit dataChanged(currentBranch(), currentBranch());
+            static_cast<BranchNode *>(idx.internalPointer())->current = true;
+            emit dataChanged(idx, idx);
+        } else {
+            refresh(m_workingDirectory, &errorMessage); // not sure all went well... better refresh!
+        }
+    }
+    if (!errorMessage.isEmpty())
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
 }
 
-bool LocalBranchModel::setData(const QModelIndex &index, const QVariant &value, int role)
+bool BranchModel::branchIsMerged(const QModelIndex &idx)
 {
-    // Verify
-    if (role != Qt::EditRole || index.row() < branchCount())
+    QString branch = branchName(idx);
+    if (branch.isEmpty())
+        return false;
+
+    QString errorMessage;
+    QString output;
+    QStringList args;
+
+    args << QLatin1String("--contains") << sha(idx);
+    if (!m_client->synchronousBranchCmd(m_workingDirectory, args, &output, &errorMessage)) {
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
         return false;
-    const QString branchName = value.toString();
-    // Delay the signal as we don't want ourselves to be reset while
-    // in setData().
-    if (checkNewBranchName(branchName)) {
-        m_newBranch = branchName;
-        QTimer::singleShot(0, this, SLOT(slotNewBranchDelayedRefresh()));
     }
-    return true;
+
+    QStringList lines = output.split(QLatin1Char('/'), QString::SkipEmptyParts);
+    foreach (const QString &l, lines) {
+        if (l.startsWith(QLatin1String("  ")) && l.count() >= 3)
+            return true;
+    }
+    return false;
 }
 
-void LocalBranchModel::slotNewBranchDelayedRefresh()
+QModelIndex BranchModel::addBranch(const QString &branchName, bool track, const QString &startPoint)
 {
-    emit newBranchEntered(m_newBranch);
+    if (!m_rootNode || !m_rootNode->count())
+        return QModelIndex();
+
+    QString output;
+    QString errorMessage;
+
+    QStringList args;
+    args << (track ? QLatin1String("--track") : QLatin1String("--no-track"));
+    args << branchName << startPoint;
+
+    if (!m_client->synchronousBranchCmd(m_workingDirectory, args, &output, &errorMessage)) {
+        VCSBase::VCSBaseOutputWindow::instance()->appendError(errorMessage);
+        return QModelIndex();
+    }
+
+    BranchNode *local = m_rootNode->children.at(0);
+    int pos = 0;
+    for (pos = 0; pos < local->count(); ++pos) {
+        if (local->children.at(pos)->name > branchName)
+            break;
+    }
+    BranchNode *newNode = new BranchNode(branchName);
+
+    // find the sha of the new branch:
+    output = toolTip(branchName); // abuse toolTip to get the data;-)
+    QStringList lines = output.split(QLatin1Char('\n'));
+    foreach (const QString &l, lines) {
+        if (l.startsWith("commit ")) {
+            newNode->sha = l.mid(7, 8);
+            break;
+        }
+    }
+
+    beginInsertRows(index(0, 0), pos, pos);
+    newNode->parent = local;
+    local->children.insert(pos, newNode);
+    endInsertRows();
+
+    return index(pos, 0, index(0, 0));
 }
 
+void BranchModel::parseOutputLine(const QString &line)
+{
+    if (line.size() < 3)
+        return;
+
+    bool current = line.startsWith(QLatin1String("* "));
+
+    const QString branchInfo = line.mid(2);
+    if (current && branchInfo.startsWith(QLatin1String("(no branch)")))
+        return;
+
+    QStringList tokens = branchInfo.split(QLatin1Char(' '), QString::SkipEmptyParts);
+    if (tokens.size() < 2)
+        return;
+
+    QString sha = tokens.at(1);
+
+    // insert node into tree:
+    QStringList nameParts = tokens.at(0).split(QLatin1Char('/'));
+    if (nameParts.count() < 1)
+        return;
+
+    QString name = nameParts.last();
+    nameParts.removeLast();
+
+    if (nameParts.isEmpty() || nameParts.at(0) != QLatin1String("remotes")) {
+        // local branch:
+        while (nameParts.count() > 2)
+            nameParts[1] = nameParts.at(1) + QLatin1Char('/') + nameParts.at(2);
+        m_rootNode->children.at(0)->insert(nameParts, new BranchNode(name, sha, current));
+    } else {
+        // remote branch:
+        nameParts.removeFirst(); // remove "remotes"
+        while (nameParts.count() > 2)
+            nameParts[1] = nameParts.at(1) + QLatin1Char('/') + nameParts.at(2);
+        m_rootNode->insert(nameParts, new BranchNode(name, sha, current));
+    }
 }
+
+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;
 }
 
+} // namespace Internal
+} // namespace Git
+
diff --git a/src/plugins/git/branchmodel.h b/src/plugins/git/branchmodel.h
index 0516baf1ebbdfe533db2163d44a6142ca9a5f3d4..c56d20913856b61c10bb379422aca5175edcecb2 100644
--- a/src/plugins/git/branchmodel.h
+++ b/src/plugins/git/branchmodel.h
@@ -38,105 +38,63 @@
 #include <QtCore/QVariant>
 
 namespace Git {
-    namespace Internal {
+namespace Internal {
 
 class GitClient;
 
-/* A read-only model to list git remote branches in a simple list of branch names.
- * The tooltip describes the latest commit (delayed creation).
- * Provides virtuals to be able to derive a local branch model with the notion
- * of a "current branch". */
+class BranchNode;
 
-class RemoteBranchModel : public QAbstractListModel {
+// --------------------------------------------------------------------------
+// BranchModel:
+// --------------------------------------------------------------------------
+
+class BranchModel : public QAbstractItemModel {
     Q_OBJECT
-public:
-    explicit RemoteBranchModel(GitClient *client, QObject *parent = 0);
 
-    virtual void clear();
-    virtual bool refresh(const QString &workingDirectory, QString *errorMessage);
+public:
+    explicit BranchModel(GitClient *client, QObject *parent = 0);
+    ~BranchModel();
 
-    QString branchName(int row) const;
+    // QAbstractItemModel
+    QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
+    QModelIndex parent(const QModelIndex &index) const;
+    int rowCount(const QModelIndex &parent = QModelIndex()) const;
+    int columnCount(const QModelIndex &parent = QModelIndex()) const;
+    QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
+    Qt::ItemFlags flags(const QModelIndex &index) 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;
+    void clear();
+    bool refresh(const QString &workingDirectory, QString *errorMessage);
 
-    int branchCount() const;
+    void renameBranch(const QString &oldName, const QString &newName);
 
     QString workingDirectory() const;
-    int findBranchByName(const QString &name) const;
+    GitClient *client() const;
 
-protected:
-    struct Branch {
-        bool parse(const QString &line, bool *isCurrent);
+    QModelIndex currentBranch() const;
+    QString branchName(const QModelIndex &idx) const;
+    QStringList localBranchNames() const;
+    QString sha(const QModelIndex &idx) const;
+    bool isLocal(const QModelIndex &idx) const;
+    bool isLeaf(const QModelIndex &idx) const;
 
-        QString name;
-        QString currentSHA;
-        mutable QString toolTip;
-    };
-    typedef QList<Branch> BranchList;
-
-    /* Parse git output and populate m_branches. */
-    bool refreshBranches(const QString &workingDirectory, bool remoteBranches,
-                         int *currentBranch, QString *errorMessage);
-    bool runGitBranchCommand(const QString &workingDirectory, const QStringList &additionalArgs, QString *output, QString *errorMessage);
+    void removeBranch(const QModelIndex &idx);
+    void checkoutBranch(const QModelIndex &idx);
+    bool branchIsMerged(const QModelIndex &idx);
+    QModelIndex addBranch(const QString &branchName, bool track, const QString &trackedBranch);
 
 private:
-    QString toolTip(const QString &sha) const;
+    void parseOutputLine(const QString &line);
 
-    const Qt::ItemFlags m_flags;
+    QString toolTip(const QString &sha) const;
 
     GitClient *m_client;
     QString m_workingDirectory;
-    BranchList m_branches;
-};
-
-/* LocalBranchModel: Extends RemoteBranchModel by a read-only
- * checkable column indicating the current branch. Provides an
- * editable "Type here" new-branch-row at the bottom to create
- * a new branch. */
-
-class LocalBranchModel : public RemoteBranchModel {
-    Q_OBJECT
-public:
-
-    explicit LocalBranchModel(GitClient *client,
-                         QObject *parent = 0);
-
-    virtual void clear();
-    virtual bool refresh(const QString &workingDirectory, QString *errorMessage);
-
-    // is this the "type here" row?
-    bool isNewBranchRow(int row) const;
-    bool isNewBranchRow(const QModelIndex & index) const { return isNewBranchRow(index.row()); }
-
-    int currentBranch() const;
-
-    // QAbstractListModel
-    virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
-    virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
-    virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
-    virtual Qt::ItemFlags flags(const QModelIndex &index) const;
-
-signals:
-    void newBranchCreated(const QString &);
-    void newBranchEntered(const QString &);
-
-private slots:
-    void slotNewBranchDelayedRefresh();
-
-private:
-    bool checkNewBranchName(const QString &name) const;
-
-    const QVariant m_typeHere;
-    const QVariant m_typeHereToolTip;
-
-    int m_currentBranch;
-    QString m_newBranch;
+    BranchNode *m_rootNode;
 };
 
-}
-}
+} // namespace Internal
+} // namespace Git
 
 #endif // BRANCHMODEL_H
diff --git a/src/plugins/git/git.pro b/src/plugins/git/git.pro
index f0ee63159607313a0a64602575eb61c67da52cc3..4b4bb0bf7ab4b601023e8d67731d93cd54f827b9 100644
--- a/src/plugins/git/git.pro
+++ b/src/plugins/git/git.pro
@@ -27,6 +27,7 @@ HEADERS += gitplugin.h \
     gitutils.h \
     remotemodel.h \
     remotedialog.h \
+    branchadddialog.h
 
 SOURCES += gitplugin.cpp \
     gitclient.cpp \
@@ -48,6 +49,7 @@ SOURCES += gitplugin.cpp \
     gitutils.cpp \
     remotemodel.cpp \
     remotedialog.cpp \
+    branchadddialog.cpp
 
 FORMS += changeselectiondialog.ui \
     settingspage.ui \
@@ -56,8 +58,12 @@ FORMS += changeselectiondialog.ui \
     stashdialog.ui \
     remotedialog.ui \
     remoteadditiondialog.ui \
+    branchadddialog.ui
 
 include(gitorious/gitorious.pri)
 
 RESOURCES += \
     git.qrc
+
+
+