summaryrefslogtreecommitdiff
path: root/src/plugins/git
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/git')
-rw-r--r--src/plugins/git/branchmodel.cpp104
-rw-r--r--src/plugins/git/branchmodel.h3
-rw-r--r--src/plugins/git/branchview.cpp70
-rw-r--r--src/plugins/git/branchview.h3
-rw-r--r--src/plugins/git/gitclient.cpp46
-rw-r--r--src/plugins/git/gitclient.h6
6 files changed, 154 insertions, 78 deletions
diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp
index 3c4971fa73..7b57df0739 100644
--- a/src/plugins/git/branchmodel.cpp
+++ b/src/plugins/git/branchmodel.cpp
@@ -229,6 +229,7 @@ public:
QString currentSha;
QDateTime currentDateTime;
QStringList obsoleteLocalBranches;
+ std::unique_ptr<TaskTree> refreshTask;
bool oldBranchesIncluded = false;
struct OldEntry
@@ -399,50 +400,83 @@ void BranchModel::clear()
d->obsoleteLocalBranches.clear();
}
-bool BranchModel::refresh(const FilePath &workingDirectory, QString *errorMessage)
+void BranchModel::refresh(const FilePath &workingDirectory, ShowError showError)
{
+ if (d->refreshTask) {
+ endResetModel(); // for the running task tree.
+ d->refreshTask.reset(); // old running tree is reset, no handlers are being called
+ }
beginResetModel();
clear();
if (workingDirectory.isEmpty()) {
endResetModel();
- return true;
+ return;
}
- d->currentSha = d->client->synchronousTopRevision(workingDirectory, &d->currentDateTime);
- QStringList args = {"--format=%(objectname)\t%(refname)\t%(upstream:short)\t"
- "%(*objectname)\t%(committerdate:raw)\t%(*committerdate:raw)",
- "refs/heads/**",
- "refs/remotes/**"};
- if (d->client->settings().showTags.value())
- args << "refs/tags/**";
- QString output;
- if (!d->client->synchronousForEachRefCmd(workingDirectory, args, &output, errorMessage)) {
- endResetModel();
- return false;
- }
+ using namespace Tasking;
+ const Process topRevisionProc =
+ d->client->topRevision(workingDirectory,
+ [=](const QString &ref, const QDateTime &dateTime) {
+ d->currentSha = ref;
+ d->currentDateTime = dateTime;
+ });
+
+ const auto setupForEachRef = [=](QtcProcess &process) {
+ d->workingDirectory = workingDirectory;
+ QStringList args = {"for-each-ref",
+ "--format=%(objectname)\t%(refname)\t%(upstream:short)\t"
+ "%(*objectname)\t%(committerdate:raw)\t%(*committerdate:raw)",
+ "refs/heads/**",
+ "refs/remotes/**"};
+ if (d->client->settings().showTags.value())
+ args << "refs/tags/**";
+ d->client->setupCommand(process, workingDirectory, args);
+ };
- d->workingDirectory = workingDirectory;
- const QStringList lines = output.split('\n');
- for (const QString &l : lines)
- d->parseOutputLine(l);
- d->flushOldEntries();
+ const auto forEachRefDone = [=](const QtcProcess &process) {
+ const QString output = process.stdOut();
+ const QStringList lines = output.split('\n');
+ for (const QString &l : lines)
+ d->parseOutputLine(l);
+ d->flushOldEntries();
+
+ d->updateAllUpstreamStatus(d->rootNode->children.at(LocalBranches));
+ if (d->currentBranch) {
+ if (d->currentBranch->isLocal())
+ d->currentBranch = nullptr;
+ setCurrentBranch();
+ }
+ if (!d->currentBranch) {
+ BranchNode *local = d->rootNode->children.at(LocalBranches);
+ d->currentBranch = d->headNode = new BranchNode(
+ Tr::tr("Detached HEAD"), "HEAD", {}, d->currentDateTime);
+ local->prepend(d->headNode);
+ }
+ };
- d->updateAllUpstreamStatus(d->rootNode->children.at(LocalBranches));
- if (d->currentBranch) {
- if (d->currentBranch->isLocal())
- d->currentBranch = nullptr;
- setCurrentBranch();
- }
- if (!d->currentBranch) {
- BranchNode *local = d->rootNode->children.at(LocalBranches);
- d->currentBranch = d->headNode = new BranchNode(Tr::tr("Detached HEAD"), "HEAD", QString(),
- d->currentDateTime);
- local->prepend(d->headNode);
- }
+ const auto forEachRefError = [=](const QtcProcess &process) {
+ if (showError == ShowError::No)
+ return;
+ const QString message = Tr::tr("Cannot run \"%1\" in \"%2\": %3")
+ .arg("git for-each-ref")
+ .arg(workingDirectory.toUserOutput())
+ .arg(process.cleanedStdErr());
+ VcsBase::VcsOutputWindow::appendError(message);
+ };
- endResetModel();
+ const auto finalize = [this] {
+ endResetModel();
+ d->refreshTask.release()->deleteLater();
+ };
- return true;
+ const Group root {
+ topRevisionProc,
+ Process(setupForEachRef, forEachRefDone, forEachRefError),
+ OnGroupDone(finalize),
+ OnGroupError(finalize)
+ };
+ d->refreshTask.reset(new TaskTree(root));
+ d->refreshTask->start();
}
void BranchModel::setCurrentBranch()
@@ -469,7 +503,7 @@ void BranchModel::renameBranch(const QString &oldName, const QString &newName)
&output, &errorMessage))
VcsOutputWindow::appendError(errorMessage);
else
- refresh(d->workingDirectory, &errorMessage);
+ refresh(d->workingDirectory);
}
void BranchModel::renameTag(const QString &oldName, const QString &newName)
@@ -482,7 +516,7 @@ void BranchModel::renameTag(const QString &oldName, const QString &newName)
&output, &errorMessage)) {
VcsOutputWindow::appendError(errorMessage);
} else {
- refresh(d->workingDirectory, &errorMessage);
+ refresh(d->workingDirectory);
}
}
diff --git a/src/plugins/git/branchmodel.h b/src/plugins/git/branchmodel.h
index 580af61298..de126e9a5e 100644
--- a/src/plugins/git/branchmodel.h
+++ b/src/plugins/git/branchmodel.h
@@ -34,7 +34,8 @@ public:
Qt::ItemFlags flags(const QModelIndex &index) const override;
void clear();
- bool refresh(const Utils::FilePath &workingDirectory, QString *errorMessage);
+ enum class ShowError { No, Yes };
+ void refresh(const Utils::FilePath &workingDirectory, ShowError showError = ShowError::No);
void renameBranch(const QString &oldName, const QString &newName);
void renameTag(const QString &oldName, const QString &newName);
diff --git a/src/plugins/git/branchview.cpp b/src/plugins/git/branchview.cpp
index 528ec288f9..df9c255c58 100644
--- a/src/plugins/git/branchview.cpp
+++ b/src/plugins/git/branchview.cpp
@@ -160,9 +160,7 @@ void BranchView::refresh(const FilePath &repository, bool force)
if (!isVisible())
return;
- QString errorMessage;
- if (!m_model->refresh(m_repository, &errorMessage))
- VcsBase::VcsOutputWindow::appendError(errorMessage);
+ m_model->refresh(m_repository, BranchModel::ShowError::Yes);
}
void BranchView::refreshCurrentBranch()
@@ -225,6 +223,7 @@ void BranchView::slotCustomContextMenu(const QPoint &point)
const bool isTag = m_model->isTag(index);
const bool hasActions = m_model->isLeaf(index);
const bool currentLocal = m_model->isLocal(currentBranch);
+ std::unique_ptr<TaskTree> taskTree;
QMenu contextMenu;
contextMenu.addAction(Tr::tr("&Add..."), this, &BranchView::add);
@@ -268,19 +267,19 @@ void BranchView::slotCustomContextMenu(const QPoint &point)
resetMenu->addAction(Tr::tr("&Mixed"), this, [this] { reset("mixed"); });
resetMenu->addAction(Tr::tr("&Soft"), this, [this] { reset("soft"); });
contextMenu.addMenu(resetMenu);
- QString mergeTitle;
- if (isFastForwardMerge()) {
- contextMenu.addAction(Tr::tr("&Merge \"%1\" into \"%2\" (Fast-Forward)")
- .arg(indexName, currentName),
- this, [this] { merge(true); });
- mergeTitle = Tr::tr("Merge \"%1\" into \"%2\" (No &Fast-Forward)")
- .arg(indexName, currentName);
- } else {
- mergeTitle = Tr::tr("&Merge \"%1\" into \"%2\"")
- .arg(indexName, currentName);
- }
+ QAction *mergeAction = contextMenu.addAction(Tr::tr("&Merge \"%1\" into \"%2\"")
+ .arg(indexName, currentName),
+ this,
+ [this] { merge(false); });
+ taskTree.reset(onFastForwardMerge([&] {
+ auto ffMerge = new QAction(
+ Tr::tr("&Merge \"%1\" into \"%2\" (Fast-Forward)").arg(indexName, currentName));
+ connect(ffMerge, &QAction::triggered, this, [this] { merge(true); });
+ contextMenu.insertAction(mergeAction, ffMerge);
+ mergeAction->setText(Tr::tr("Merge \"%1\" into \"%2\" (No &Fast-Forward)")
+ .arg(indexName, currentName));
+ }));
- contextMenu.addAction(mergeTitle, this, [this] { merge(false); });
contextMenu.addAction(Tr::tr("&Rebase \"%1\" on \"%2\"")
.arg(currentName, indexName),
this, &BranchView::rebase);
@@ -523,13 +522,50 @@ bool BranchView::reset(const QByteArray &resetType)
return false;
}
-bool BranchView::isFastForwardMerge()
+TaskTree *BranchView::onFastForwardMerge(const std::function<void()> &callback)
{
+ using namespace Tasking;
+
const QModelIndex selected = selectedIndex();
QTC_CHECK(selected != m_model->currentBranch());
const QString branch = m_model->fullName(selected, true);
- return GitClient::instance()->isFastForwardMerge(m_repository, branch);
+
+ struct FastForwardStorage
+ {
+ QString mergeBase;
+ QString topRevision;
+ };
+
+ const TreeStorage<FastForwardStorage> storage;
+
+ GitClient *client = GitClient::instance();
+ const auto setupMergeBase = [=](QtcProcess &process) {
+ client->setupCommand(process, m_repository, {"merge-base", "HEAD", branch});
+ };
+ const auto onMergeBaseDone = [storage](const QtcProcess &process) {
+ storage->mergeBase = process.cleanedStdOut().trimmed();
+ };
+
+ const Process topRevisionProc = client->topRevision(
+ m_repository,
+ [storage](const QString &revision, const QDateTime &) {
+ storage->topRevision = revision;
+ });
+
+ const Group root {
+ Storage(storage),
+ parallel,
+ Process(setupMergeBase, onMergeBaseDone),
+ topRevisionProc,
+ OnGroupDone([storage, callback] {
+ if (storage->mergeBase == storage->topRevision)
+ callback();
+ })
+ };
+ auto taskTree = new TaskTree(root);
+ taskTree->start();
+ return taskTree;
}
bool BranchView::merge(bool allowFastForward)
diff --git a/src/plugins/git/branchview.h b/src/plugins/git/branchview.h
index 9a1a3c1e45..c1ac77c82b 100644
--- a/src/plugins/git/branchview.h
+++ b/src/plugins/git/branchview.h
@@ -20,6 +20,7 @@ QT_END_NAMESPACE;
namespace Utils {
class ElidingLabel;
class NavigationTreeView;
+class TaskTree;
} // Utils
namespace Git::Internal {
@@ -54,7 +55,7 @@ private:
bool remove();
bool rename();
bool reset(const QByteArray &resetType);
- bool isFastForwardMerge();
+ Utils::TaskTree *onFastForwardMerge(const std::function<void()> &callback);
bool merge(bool allowFastForward);
void rebase();
bool cherryPick();
diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp
index e419449fe0..66f03aa974 100644
--- a/src/plugins/git/gitclient.cpp
+++ b/src/plugins/git/gitclient.cpp
@@ -171,7 +171,7 @@ GitDiffEditorController::GitDiffEditorController(IDocument *document,
VcsOutputWindow::appendCommand(process.workingDirectory(), process.commandLine());
};
const auto onDiffDone = [diffInputStorage](const QtcProcess &process) {
- *diffInputStorage.activeStorage() = process.cleanedStdOut();
+ *diffInputStorage = process.cleanedStdOut();
};
const Group root {
@@ -258,7 +258,7 @@ FileListDiffController::FileListDiffController(IDocument *document, const QStrin
};
const auto onStagingDone = [storage, diffInputStorage] {
- *diffInputStorage.activeStorage() = storage->m_stagedOutput + storage->m_unstagedOutput;
+ *diffInputStorage = storage->m_stagedOutput + storage->m_unstagedOutput;
};
const Group root {
@@ -455,7 +455,7 @@ ShowController::ShowController(IDocument *document, const QString &id)
VcsOutputWindow::appendCommand(process.workingDirectory(), process.commandLine());
};
const auto onDiffDone = [diffInputStorage](const QtcProcess &process) {
- *diffInputStorage.activeStorage() = process.cleanedStdOut();
+ *diffInputStorage = process.cleanedStdOut();
};
const Group root {
@@ -1730,19 +1730,28 @@ bool GitClient::synchronousRevParseCmd(const FilePath &workingDirectory, const Q
}
// Retrieve head revision
-QString GitClient::synchronousTopRevision(const FilePath &workingDirectory, QDateTime *dateTime)
+Utils::Tasking::Process GitClient::topRevision(
+ const FilePath &workingDirectory,
+ const std::function<void(const QString &, const QDateTime &)> &callback)
{
- const QStringList arguments = {"show", "-s", "--pretty=format:%H:%ct", HEAD};
- const CommandResult result = vcsSynchronousExec(workingDirectory, arguments, RunFlags::NoOutput);
- if (result.result() != ProcessResult::FinishedWithSuccess)
- return QString();
- const QStringList output = result.cleanedStdOut().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();
+ using namespace Tasking;
+
+ const auto setupProcess = [=](QtcProcess &process) {
+ setupCommand(process, workingDirectory, {"show", "-s", "--pretty=format:%H:%ct", HEAD});
+ };
+ const auto onProcessDone = [=](const QtcProcess &process) {
+ const QStringList output = process.cleanedStdOut().trimmed().split(':');
+ QDateTime dateTime;
+ if (output.size() > 1) {
+ bool ok = false;
+ const qint64 timeT = output.at(1).toLongLong(&ok);
+ if (ok)
+ dateTime = QDateTime::fromSecsSinceEpoch(timeT);
+ }
+ callback(output.first(), dateTime);
+ };
+
+ return Process(setupProcess, onProcessDone);
}
bool GitClient::isRemoteCommit(const FilePath &workingDirectory, const QString &commit)
@@ -1752,13 +1761,6 @@ bool GitClient::isRemoteCommit(const FilePath &workingDirectory, const QString &
return !result.rawStdOut().isEmpty();
}
-bool GitClient::isFastForwardMerge(const FilePath &workingDirectory, const QString &branch)
-{
- const CommandResult result = vcsSynchronousExec(workingDirectory,
- {"merge-base", HEAD, branch}, RunFlags::NoOutput);
- return result.cleanedStdOut().trimmed() == synchronousTopRevision(workingDirectory);
-}
-
// Format an entry in a one-liner for selection list using git log.
QString GitClient::synchronousShortDescription(const FilePath &workingDirectory, const QString &revision,
const QString &format) const
diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h
index 2dfd6ddaaa..5709a53b86 100644
--- a/src/plugins/git/gitclient.h
+++ b/src/plugins/git/gitclient.h
@@ -13,6 +13,7 @@
#include <utils/fileutils.h>
#include <utils/futuresynchronizer.h>
+#include <utils/qtcprocess.h>
#include <QObject>
#include <QString>
@@ -241,9 +242,10 @@ public:
QString synchronousTopic(const Utils::FilePath &workingDirectory) const;
bool synchronousRevParseCmd(const Utils::FilePath &workingDirectory, const QString &ref,
QString *output, QString *errorMessage = nullptr) const;
- QString synchronousTopRevision(const Utils::FilePath &workingDirectory, QDateTime *dateTime = nullptr);
+ Utils::Tasking::Process topRevision(
+ const Utils::FilePath &workingDirectory,
+ const std::function<void(const QString &, const QDateTime &)> &callback);
bool isRemoteCommit(const Utils::FilePath &workingDirectory, const QString &commit);
- bool isFastForwardMerge(const Utils::FilePath &workingDirectory, const QString &branch);
void fetch(const Utils::FilePath &workingDirectory, const QString &remote);
void pull(const Utils::FilePath &workingDirectory, bool rebase);