Git: Show detached HEAD in branches view when applicable

Fixes: QTCREATORBUG-21311
Change-Id: Ia4297d23a965d83ea2814bd1e41f35a3017b8e9b
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
Orgad Shaneh
2018-11-10 21:14:21 +02:00
committed by Orgad Shaneh
parent e0a1b171f1
commit 92431932e3
5 changed files with 47 additions and 13 deletions

View File

@@ -161,6 +161,13 @@ public:
return n;
}
BranchNode *prepend(BranchNode *n)
{
n->parent = this;
children.prepend(n);
return n;
}
QStringList childrenNames() const
{
if (children.count() > 0) {
@@ -206,7 +213,9 @@ public:
QString workingDirectory;
BranchNode *rootNode;
BranchNode *currentBranch = nullptr;
BranchNode *headNode = nullptr;
QString currentSha;
QDateTime currentDateTime;
QStringList obsoleteLocalBranches;
bool oldBranchesIncluded = false;
};
@@ -340,7 +349,7 @@ Qt::ItemFlags BranchModel::flags(const QModelIndex &index) const
if (!node)
return Qt::NoItemFlags;
Qt::ItemFlags res = Qt::ItemIsSelectable | Qt::ItemIsEnabled;
if (node->isLeaf() && node->isLocal() && index.column() == 0)
if (node != d->headNode && node->isLeaf() && node->isLocal() && index.column() == 0)
res |= Qt::ItemIsEditable;
return res;
}
@@ -355,7 +364,9 @@ void BranchModel::clear()
d->rootNode->children.takeLast();
d->currentSha.clear();
d->currentDateTime = QDateTime();
d->currentBranch = nullptr;
d->headNode = nullptr;
d->obsoleteLocalBranches.clear();
}
@@ -368,7 +379,7 @@ bool BranchModel::refresh(const QString &workingDirectory, QString *errorMessage
return true;
}
d->currentSha = d->client->synchronousTopRevision(workingDirectory);
d->currentSha = d->client->synchronousTopRevision(workingDirectory, &d->currentDateTime);
const QStringList args = {"--format=%(objectname)\t%(refname)\t%(upstream:short)\t"
"%(*objectname)\t%(committerdate:raw)\t%(*committerdate:raw)"};
QString output;
@@ -387,6 +398,12 @@ bool BranchModel::refresh(const QString &workingDirectory, QString *errorMessage
d->currentBranch = nullptr;
setCurrentBranch();
}
if (!d->currentBranch) {
BranchNode *local = d->rootNode->children.at(LocalBranches);
d->currentBranch = d->headNode = new BranchNode(tr("Detached HEAD"), "HEAD", QString(),
d->currentDateTime);
local->prepend(d->headNode);
}
endResetModel();
@@ -458,6 +475,8 @@ QString BranchModel::fullName(const QModelIndex &idx, bool includePrefix) const
BranchNode *node = indexToNode(idx);
if (!node || !node->isLeaf())
return QString();
if (node == d->headNode)
return QString("HEAD");
return node->fullName(includePrefix).join('/');
}
@@ -490,12 +509,20 @@ bool BranchModel::hasTags() const
return d->rootNode->children.count() > Tags;
}
bool BranchModel::isHead(const QModelIndex &idx) const
{
if (!idx.isValid())
return false;
BranchNode *node = indexToNode(idx);
return node == d->headNode;
}
bool BranchModel::isLocal(const QModelIndex &idx) const
{
if (!idx.isValid())
return false;
BranchNode *node = indexToNode(idx);
return node->isLocal();
return node == d->headNode ? false : node->isLocal();
}
bool BranchModel::isLeaf(const QModelIndex &idx) const

View File

@@ -72,6 +72,7 @@ public:
QString sha(const QModelIndex &idx) const;
QDateTime dateTime(const QModelIndex &idx) const;
bool hasTags() const;
bool isHead(const QModelIndex &idx) const;
bool isLocal(const QModelIndex &idx) const;
bool isLeaf(const QModelIndex &idx) const;
bool isTag(const QModelIndex &idx) const;

View File

@@ -298,12 +298,12 @@ bool BranchView::add()
trackedBranch = m_model->fullName(trackedIndex);
}
const bool isLocal = m_model->isLocal(trackedIndex);
const bool isTag = m_model->isTag(trackedIndex);
const bool isTracked = !m_model->isHead(trackedIndex) && !m_model->isTag(trackedIndex);
const QStringList localNames = m_model->localBranchNames();
QString suggestedName;
if (!isTag) {
if (isTracked) {
const QString suggestedNameBase = trackedBranch.mid(trackedBranch.lastIndexOf('/') + 1);
suggestedName = suggestedNameBase;
int i = 2;
@@ -315,7 +315,7 @@ bool BranchView::add()
BranchAddDialog branchAddDialog(localNames, true, this);
branchAddDialog.setBranchName(suggestedName);
branchAddDialog.setTrackedBranchName(isTag ? QString() : trackedBranch, !isLocal);
branchAddDialog.setTrackedBranchName(isTracked ? trackedBranch : QString(), !isLocal);
if (branchAddDialog.exec() == QDialog::Accepted) {
QModelIndex idx = m_model->addBranch(branchAddDialog.branchName(), branchAddDialog.track(), trackedIndex);

View File

@@ -1557,14 +1557,20 @@ bool GitClient::synchronousRevParseCmd(const QString &workingDirectory, const QS
}
// Retrieve head revision
QString GitClient::synchronousTopRevision(const QString &workingDirectory)
QString GitClient::synchronousTopRevision(const QString &workingDirectory, QDateTime *dateTime)
{
QString revision;
QString errorMessage;
if (!synchronousRevParseCmd(workingDirectory, HEAD, &revision, &errorMessage))
const QStringList arguments = {"show", "-s", "--pretty=format:%H:%ct", HEAD};
const SynchronousProcessResponse resp = vcsFullySynchronousExec(
workingDirectory, arguments, silentFlags);
if (resp.result != SynchronousProcessResponse::Finished)
return QString();
return revision;
const QStringList output = resp.stdOut().trimmed().split(':');
if (dateTime && output.size() > 1) {
bool ok = false;
const qint64 timeT = output.at(1).toLongLong(&ok);
*dateTime = ok ? QDateTime::fromSecsSinceEpoch(timeT) : QDateTime();
}
return output.first();
}
void GitClient::synchronousTagsForCommit(const QString &workingDirectory, const QString &revision,

View File

@@ -234,7 +234,7 @@ public:
QString synchronousTopic(const QString &workingDirectory) const;
bool synchronousRevParseCmd(const QString &workingDirectory, const QString &ref,
QString *output, QString *errorMessage = nullptr) const;
QString synchronousTopRevision(const QString &workingDirectory);
QString synchronousTopRevision(const QString &workingDirectory, QDateTime *dateTime = nullptr);
void synchronousTagsForCommit(const QString &workingDirectory, const QString &revision,
QString &precedes, QString &follows) const;
bool isRemoteCommit(const QString &workingDirectory, const QString &commit);