diff --git a/src/plugins/git/branchdialog.cpp b/src/plugins/git/branchdialog.cpp
index 2403e83d37155a07a6bd41476d5505f96727ec11..1f9ce03bdb183c00c989cdff50d00c3a9f54d704 100644
--- a/src/plugins/git/branchdialog.cpp
+++ b/src/plugins/git/branchdialog.cpp
@@ -287,7 +287,7 @@ void BranchDialog::rename()
 
 void BranchDialog::diff()
 {
-    QString fullName = m_model->fullName(selectedIndex());
+    QString fullName = m_model->fullName(selectedIndex(), true);
     if (fullName.isEmpty())
         return;
     // Do not pass working dir by reference since it might change
@@ -296,7 +296,7 @@ void BranchDialog::diff()
 
 void BranchDialog::log()
 {
-    QString branchName = m_model->fullName(selectedIndex());
+    QString branchName = m_model->fullName(selectedIndex(), true);
     if (branchName.isEmpty())
         return;
     // Do not pass working dir by reference since it might change
@@ -309,7 +309,7 @@ void BranchDialog::merge()
     QTC_CHECK(m_model->isLocal(m_model->currentBranch())); // otherwise the button would not be enabled!
     QTC_CHECK(idx != m_model->currentBranch());            // otherwise the button would not be enabled!
 
-    const QString branch = m_model->fullName(idx);
+    const QString branch = m_model->fullName(idx, true);
     GitClient *client = GitPlugin::instance()->gitClient();
     if (client->beginStashScope(m_repository, QLatin1String("merge"), AllowUnstashed))
         client->synchronousMerge(m_repository, branch);
@@ -321,7 +321,7 @@ void BranchDialog::rebase()
     QTC_CHECK(m_model->isLocal(m_model->currentBranch())); // otherwise the button would not be enabled!
     QTC_CHECK(idx != m_model->currentBranch());            // otherwise the button would not be enabled!
 
-    const QString baseBranch = m_model->fullName(idx);
+    const QString baseBranch = m_model->fullName(idx, true);
     GitClient *client = GitPlugin::instance()->gitClient();
     if (client->beginStashScope(m_repository, QLatin1String("rebase")))
         client->rebase(m_repository, baseBranch);
diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp
index 0227beb9c19e9b00e135917200c937165c18c115..feee651ed8ae43d139ff7b7215eb623656e5cbc7 100644
--- a/src/plugins/git/branchmodel.cpp
+++ b/src/plugins/git/branchmodel.cpp
@@ -38,6 +38,12 @@
 namespace Git {
 namespace Internal {
 
+enum RootNodes {
+    LocalBranches = 0,
+    RemoteBranches = 1,
+    Tags = 2
+};
+
 // --------------------------------------------------------------------------
 // BranchNode:
 // --------------------------------------------------------------------------
@@ -77,18 +83,6 @@ public:
         return children.isEmpty();
     }
 
-    bool isTag() const
-    {
-        if (!parent)
-            return false;
-        for (const BranchNode *p = this; p->parent; p = p->parent) {
-            // find root child with name "tags"
-            if (!p->parent->parent && p->name == QLatin1String("tags"))
-                return true;
-        }
-        return false;
-    }
-
     bool childOf(BranchNode *node) const
     {
         if (this == node)
@@ -96,12 +90,22 @@ public:
         return parent ? parent->childOf(node) : false;
     }
 
-    bool isLocal() const
+    bool childOfRoot(RootNodes root) const
     {
         BranchNode *rn = rootNode();
         if (rn->isLeaf())
             return false;
-        return childOf(rn->children.at(0));
+        return childOf(rn->children.at(root));
+    }
+
+    bool isTag() const
+    {
+        return childOfRoot(Tags);
+    }
+
+    bool isLocal() const
+    {
+        return childOfRoot(LocalBranches);
     }
 
     BranchNode *childOfName(const QString &name) const
@@ -113,7 +117,7 @@ public:
         return 0;
     }
 
-    QStringList fullName() const
+    QStringList fullName(bool includePrefix = false) const
     {
         QTC_ASSERT(isLeaf(), return QStringList());
 
@@ -125,8 +129,9 @@ public:
             current = current->parent;
         }
 
-        if (current->children.at(0) == nodes.at(0))
-            nodes.removeFirst(); // remove local branch designation
+        if (includePrefix)
+            fn.append(nodes.first()->sha);
+        nodes.removeFirst();
 
         foreach (const BranchNode *n, nodes)
             fn.append(n->name);
@@ -191,7 +196,12 @@ BranchModel::BranchModel(GitClient *client, QObject *parent) :
     m_currentBranch(0)
 {
     QTC_CHECK(m_client);
-    m_rootNode->append(new BranchNode(tr("Local Branches")));
+
+    // Abuse the sha field for ref prefix
+    m_rootNode->append(new BranchNode(tr("Local Branches"), QLatin1String("refs/heads")));
+    m_rootNode->append(new BranchNode(tr("Remote Branches"), QLatin1String("refs/remotes")));
+    if (m_client->settings()->boolValue(GitSettings::showTagsKey))
+        m_rootNode->append(new BranchNode(tr("Tags"), QLatin1String("refs/tags")));
 }
 
 BranchModel::~BranchModel()
@@ -320,11 +330,9 @@ Qt::ItemFlags BranchModel::flags(const QModelIndex &index) const
 
 void BranchModel::clear()
 {
-    while (m_rootNode->count() > 1)
-        delete m_rootNode->children.takeLast();
-    BranchNode *locals = m_rootNode->children.at(0);
-    while (locals->count())
-        delete locals->children.takeLast();
+    foreach (BranchNode *root, m_rootNode->children)
+        while (root->count())
+            delete root->children.takeLast();
 
     m_currentBranch = 0;
 }
@@ -419,22 +427,20 @@ QModelIndex BranchModel::currentBranch() const
     return nodeToIndex(m_currentBranch);
 }
 
-QString BranchModel::fullName(const QModelIndex &idx) const
+QString BranchModel::fullName(const QModelIndex &idx, bool includePrefix) const
 {
     if (!idx.isValid())
         return QString();
     BranchNode *node = indexToNode(idx);
     if (!node || !node->isLeaf())
         return QString();
-    QStringList path = node->fullName();
-    if (node->isTag())
-        path.removeFirst();
+    QStringList path = node->fullName(includePrefix);
     return path.join(QString(QLatin1Char('/')));
 }
 
 QStringList BranchModel::localBranchNames() const
 {
-    if (!m_rootNode || m_rootNode->children.isEmpty())
+    if (!m_rootNode || !m_rootNode->count())
         return QStringList();
 
     return m_rootNode->children.at(0)->childrenNames();
@@ -509,7 +515,7 @@ void BranchModel::removeTag(const QModelIndex &idx)
 
 void BranchModel::checkoutBranch(const QModelIndex &idx)
 {
-    QString branch = fullName(idx);
+    QString branch = fullName(idx, !isLocal(idx));
     if (branch.isEmpty())
         return;
 
@@ -574,14 +580,15 @@ QModelIndex BranchModel::addBranch(const QString &name, bool track, const QModel
         return QModelIndex();
 
     const QString trackedBranch = fullName(startPoint);
+    const QString fullTrackedBranch = fullName(startPoint, true);
     QString output;
     QString errorMessage;
 
     QStringList args;
     args << (track ? QLatin1String("--track") : QLatin1String("--no-track"));
     args << name;
-    if (!trackedBranch.isEmpty())
-        args << trackedBranch;
+    if (!fullTrackedBranch.isEmpty())
+        args << fullTrackedBranch;
 
     if (!m_client->synchronousBranchCmd(m_workingDirectory, args, &output, &errorMessage)) {
         VcsBase::VcsBaseOutputWindow::instance()->appendError(errorMessage);
@@ -632,15 +639,18 @@ void BranchModel::parseOutputLine(const QString &line)
     QStringList nameParts = fullName.split(QLatin1Char('/'));
     nameParts.removeFirst(); // remove refs...
 
+    BranchNode *root = 0;
     if (nameParts.first() == QLatin1String("heads"))
-        nameParts[0] = m_rootNode->children.at(0)->name; // Insert the local designator
+        root = m_rootNode->children.at(0); // Insert the local designator
     else if (nameParts.first() == QLatin1String("remotes"))
-        nameParts.removeFirst(); // remove "remotes"
-    else if (nameParts.first() == QLatin1String("stash"))
-        return;
-    else if (!showTags && (nameParts.first() == QLatin1String("tags")))
+        root = m_rootNode->children.at(1);
+    else if (showTags && nameParts.first() == QLatin1String("tags"))
+        root = m_rootNode->children.at(2);
+    else
         return;
 
+    nameParts.removeFirst();
+
     // limit depth of list. Git basically only ever wants one / and considers the rest as part of
     // the name.
     while (nameParts.count() > 3) {
@@ -652,7 +662,7 @@ void BranchModel::parseOutputLine(const QString &line)
     nameParts.removeLast();
 
     BranchNode *newNode = new BranchNode(name, sha, lineParts.at(2));
-    m_rootNode->insert(nameParts, newNode);
+    root->insert(nameParts, newNode);
     if (current)
         m_currentBranch = newNode;
 }
diff --git a/src/plugins/git/branchmodel.h b/src/plugins/git/branchmodel.h
index 368e302acaa1ea1a286e16e4761f6508233962b7..f0bce5102152d49a1630fb3a4230e9422967d2c7 100644
--- a/src/plugins/git/branchmodel.h
+++ b/src/plugins/git/branchmodel.h
@@ -70,7 +70,7 @@ public:
     GitClient *client() const;
 
     QModelIndex currentBranch() const;
-    QString fullName(const QModelIndex &idx) const;
+    QString fullName(const QModelIndex &idx, bool includePrefix = false) const;
     QStringList localBranchNames() const;
     QString sha(const QModelIndex &idx) const;
     bool isLocal(const QModelIndex &idx) const;