diff options
Diffstat (limited to 'src/plugins/git')
27 files changed, 296 insertions, 138 deletions
diff --git a/src/plugins/git/CMakeLists.txt b/src/plugins/git/CMakeLists.txt new file mode 100644 index 0000000000..7bf50b3276 --- /dev/null +++ b/src/plugins/git/CMakeLists.txt @@ -0,0 +1,41 @@ +add_qtc_plugin(Git + PLUGIN_DEPENDS Core DiffEditor TextEditor VcsBase + SOURCES + annotationhighlighter.cpp annotationhighlighter.h + branchadddialog.cpp branchadddialog.h branchadddialog.ui + branchcheckoutdialog.cpp branchcheckoutdialog.h branchcheckoutdialog.ui + branchmodel.cpp branchmodel.h + branchview.cpp branchview.h + changeselectiondialog.cpp changeselectiondialog.h changeselectiondialog.ui + commitdata.cpp commitdata.h + gerrit/authenticationdialog.cpp gerrit/authenticationdialog.h gerrit/authenticationdialog.ui + gerrit/branchcombobox.cpp gerrit/branchcombobox.h + gerrit/gerritdialog.cpp gerrit/gerritdialog.h gerrit/gerritdialog.ui + gerrit/gerritmodel.cpp gerrit/gerritmodel.h + gerrit/gerritoptionspage.cpp gerrit/gerritoptionspage.h + gerrit/gerritparameters.cpp gerrit/gerritparameters.h + gerrit/gerritplugin.cpp gerrit/gerritplugin.h + gerrit/gerritpushdialog.cpp gerrit/gerritpushdialog.h gerrit/gerritpushdialog.ui + gerrit/gerritremotechooser.cpp gerrit/gerritremotechooser.h + gerrit/gerritserver.cpp gerrit/gerritserver.h + git.qrc + gitclient.cpp gitclient.h + gitconstants.h + giteditor.cpp giteditor.h + gitgrep.cpp gitgrep.h + githighlighters.cpp githighlighters.h + gitplugin.cpp gitplugin.h + gitsettings.cpp gitsettings.h + gitsubmiteditor.cpp gitsubmiteditor.h + gitsubmiteditorwidget.cpp gitsubmiteditorwidget.h + gitsubmitpanel.ui + gitutils.cpp gitutils.h + gitversioncontrol.cpp gitversioncontrol.h + logchangedialog.cpp logchangedialog.h + mergetool.cpp mergetool.h + remoteadditiondialog.ui + remotedialog.cpp remotedialog.h remotedialog.ui + remotemodel.cpp remotemodel.h + settingspage.cpp settingspage.h settingspage.ui + stashdialog.cpp stashdialog.h stashdialog.ui +) diff --git a/src/plugins/git/branchadddialog.cpp b/src/plugins/git/branchadddialog.cpp index edc50889ec..8a131a363c 100644 --- a/src/plugins/git/branchadddialog.cpp +++ b/src/plugins/git/branchadddialog.cpp @@ -105,13 +105,31 @@ QWidget *BranchValidationDelegate::createEditor(QWidget *parent, return lineEdit; } -BranchAddDialog::BranchAddDialog(const QStringList &localBranches, bool addBranch, QWidget *parent) : +BranchAddDialog::BranchAddDialog(const QStringList &localBranches, Type type, QWidget *parent) : QDialog(parent), m_ui(new Ui::BranchAddDialog) { m_ui->setupUi(this); + m_ui->trackingCheckBox->setVisible(false); setCheckoutVisible(false); - setWindowTitle(addBranch ? tr("Add Branch") : tr("Rename Branch")); + + switch (type) { + case BranchAddDialog::AddBranch: + setWindowTitle(tr("Add Branch")); + break; + case BranchAddDialog::RenameBranch: + setWindowTitle(tr("Rename Branch")); + break; + case BranchAddDialog::AddTag: + setWindowTitle(tr("Add Tag")); + m_ui->branchNameLabel->setText(tr("Tag name:")); + break; + case BranchAddDialog::RenameTag: + setWindowTitle(tr("Rename Tag")); + m_ui->branchNameLabel->setText(tr("Tag name:")); + break; + } + m_ui->branchNameEdit->setValidator(new BranchNameValidator(localBranches, this)); connect(m_ui->branchNameEdit, &QLineEdit::textChanged, this, &BranchAddDialog::updateButtonStatus); } @@ -134,14 +152,14 @@ QString BranchAddDialog::branchName() const 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)); - m_ui->trackingCheckBox->setChecked(remote); - } else { + if (name.isEmpty()) { m_ui->trackingCheckBox->setVisible(false); m_ui->trackingCheckBox->setChecked(false); + } else { + m_ui->trackingCheckBox->setText(remote ? tr("Track remote branch \"%1\"").arg(name) : + tr("Track local branch \"%1\"").arg(name)); + m_ui->trackingCheckBox->setVisible(true); + m_ui->trackingCheckBox->setChecked(remote); } } diff --git a/src/plugins/git/branchadddialog.h b/src/plugins/git/branchadddialog.h index e90e71b581..fa2100bf2c 100644 --- a/src/plugins/git/branchadddialog.h +++ b/src/plugins/git/branchadddialog.h @@ -51,7 +51,14 @@ class BranchAddDialog : public QDialog Q_OBJECT public: - BranchAddDialog(const QStringList &localBranches, bool addBranch, QWidget *parent); + enum Type { + AddBranch, + RenameBranch, + AddTag, + RenameTag + }; + + BranchAddDialog(const QStringList &localBranches, Type type, QWidget *parent); ~BranchAddDialog() override; void setBranchName(const QString &); diff --git a/src/plugins/git/branchadddialog.ui b/src/plugins/git/branchadddialog.ui index 4ee0b5d787..41f9fc5caf 100644 --- a/src/plugins/git/branchadddialog.ui +++ b/src/plugins/git/branchadddialog.ui @@ -32,11 +32,7 @@ </widget> </item> <item row="2" column="0" colspan="2"> - <widget class="QCheckBox" name="trackingCheckBox"> - <property name="text"> - <string>CheckBox</string> - </property> - </widget> + <widget class="QCheckBox" name="trackingCheckBox"/> </item> <item row="4" column="0" colspan="2"> <widget class="QDialogButtonBox" name="buttonBox"> diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index cd2af5b02b..bf74f7b32c 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -36,6 +36,8 @@ #include <QDateTime> #include <QFont> +#include <set> + using namespace VcsBase; namespace Git { @@ -199,17 +201,24 @@ public: class BranchModel::Private { public: - Private(GitClient *client) : + explicit Private(GitClient *client) : client(client), rootNode(new BranchNode) { } + Private(const Private &) = delete; + Private &operator=(const Private &) = delete; + ~Private() { delete rootNode; } + bool hasTags() const { return rootNode->children.count() > Tags; } + void parseOutputLine(const QString &line, bool force = false); + void flushOldEntries(); + GitClient *client; QString workingDirectory; BranchNode *rootNode; @@ -220,6 +229,17 @@ public: QStringList obsoleteLocalBranches; Utils::FileSystemWatcher fsWatcher; bool oldBranchesIncluded = false; + + struct OldEntry + { + QString line; + QDateTime dateTime; + bool operator<(const OldEntry &other) const { return dateTime < other.dateTime; } + }; + + BranchNode *currentRoot = nullptr; + QString currentRemote; + std::set<OldEntry> oldEntries; }; // -------------------------------------------------------------------------- @@ -366,7 +386,7 @@ void BranchModel::clear() while (root->count()) delete root->children.takeLast(); } - if (hasTags()) + if (d->hasTags()) d->rootNode->children.takeLast(); d->currentSha.clear(); @@ -403,7 +423,8 @@ bool BranchModel::refresh(const QString &workingDirectory, QString *errorMessage } const QStringList lines = output.split('\n'); for (const QString &l : lines) - parseOutputLine(l); + d->parseOutputLine(l); + d->flushOldEntries(); if (d->currentBranch) { if (d->currentBranch->isLocal()) @@ -516,10 +537,7 @@ QDateTime BranchModel::dateTime(const QModelIndex &idx) const return node->dateTime; } -bool BranchModel::hasTags() const -{ - return d->rootNode->children.count() > Tags; -} + bool BranchModel::isHead(const QModelIndex &idx) const { @@ -547,7 +565,7 @@ bool BranchModel::isLeaf(const QModelIndex &idx) const bool BranchModel::isTag(const QModelIndex &idx) const { - if (!idx.isValid() || !hasTags()) + if (!idx.isValid() || !d->hasTags()) return false; return indexToNode(idx)->isTag(); } @@ -648,8 +666,6 @@ QModelIndex BranchModel::addBranch(const QString &name, bool track, const QModel startSha = sha(startPoint); branchDateTime = dateTime(startPoint); } else { - QString output; - QString errorMessage; const QStringList arguments({"-n1", "--format=%H %ct"}); if (d->client->synchronousLog(d->workingDirectory, arguments, &output, &errorMessage, VcsCommand::SuppressCommandLogging)) { @@ -722,7 +738,7 @@ Utils::optional<QString> BranchModel::remoteName(const QModelIndex &idx) const return Utils::nullopt; } -void BranchModel::parseOutputLine(const QString &line) +void BranchModel::Private::parseOutputLine(const QString &line, bool force) { if (line.size() < 3) return; @@ -734,7 +750,7 @@ void BranchModel::parseOutputLine(const QString &line) const QString fullName = lineParts.at(1); const QString upstream = lineParts.at(2); QDateTime dateTime; - const bool current = (sha == d->currentSha); + const bool current = (sha == currentSha); QString strDateTime = lineParts.at(5); if (strDateTime.isEmpty()) strDateTime = lineParts.at(4); @@ -743,34 +759,57 @@ void BranchModel::parseOutputLine(const QString &line) dateTime = QDateTime::fromSecsSinceEpoch(timeT); } - if (!d->oldBranchesIncluded && !current && dateTime.isValid()) { + bool isOld = false; + if (!oldBranchesIncluded && !force && !current && dateTime.isValid()) { const qint64 age = dateTime.daysTo(QDateTime::currentDateTime()); - if (age > Constants::OBSOLETE_COMMIT_AGE_IN_DAYS) { - const QString heads = "refs/heads/"; - if (fullName.startsWith(heads)) - d->obsoleteLocalBranches.append(fullName.mid(heads.size())); - return; - } + isOld = age > Constants::OBSOLETE_COMMIT_AGE_IN_DAYS; } - bool showTags = d->client->settings().boolValue(GitSettings::showTagsKey); + bool showTags = client->settings().boolValue(GitSettings::showTagsKey); // insert node into tree: QStringList nameParts = fullName.split('/'); nameParts.removeFirst(); // remove refs... BranchNode *root = nullptr; + BranchNode *oldEntriesRoot = nullptr; + RootNodes rootType; if (nameParts.first() == "heads") { - root = d->rootNode->children.at(LocalBranches); + rootType = LocalBranches; + if (isOld) + obsoleteLocalBranches.append(fullName.mid(sizeof("refs/heads/")-1)); } else if (nameParts.first() == "remotes") { - root = d->rootNode->children.at(RemoteBranches); + rootType = RemoteBranches; + const QString remoteName = nameParts.at(1); + root = rootNode->children.at(rootType); + oldEntriesRoot = root->childOfName(remoteName); + if (!oldEntriesRoot) + oldEntriesRoot = root->append(new BranchNode(remoteName)); } else if (showTags && nameParts.first() == "tags") { if (!hasTags()) // Tags is missing, add it - d->rootNode->append(new BranchNode(tr("Tags"), "refs/tags")); - root = d->rootNode->children.at(Tags); + rootNode->append(new BranchNode(tr("Tags"), "refs/tags")); + rootType = Tags; } else { return; } + root = rootNode->children.at(rootType); + if (!oldEntriesRoot) + oldEntriesRoot = root; + if (isOld) { + if (oldEntriesRoot->children.size() > Constants::MAX_OBSOLETE_COMMITS_TO_DISPLAY) + return; + if (currentRoot != oldEntriesRoot) { + flushOldEntries(); + currentRoot = oldEntriesRoot; + } + const bool eraseOldestEntry = oldEntries.size() >= Constants::MAX_OBSOLETE_COMMITS_TO_DISPLAY; + if (!eraseOldestEntry || dateTime > oldEntries.begin()->dateTime) { + if (eraseOldestEntry) + oldEntries.erase(oldEntries.begin()); + oldEntries.insert(Private::OldEntry{line, dateTime}); + } + return; + } nameParts.removeFirst(); // limit depth of list. Git basically only ever wants one / and considers the rest as part of @@ -786,7 +825,19 @@ void BranchModel::parseOutputLine(const QString &line) auto newNode = new BranchNode(name, sha, upstream, dateTime); root->insert(nameParts, newNode); if (current) - d->currentBranch = newNode; + currentBranch = newNode; +} + +void BranchModel::Private::flushOldEntries() +{ + if (!currentRoot) + return; + for (int size = currentRoot->children.size(); size > 0 && !oldEntries.empty(); --size) + oldEntries.erase(oldEntries.begin()); + for (const Private::OldEntry &entry : oldEntries) + parseOutputLine(entry.line, true); + oldEntries.clear(); + currentRoot = nullptr; } BranchNode *BranchModel::indexToNode(const QModelIndex &index) const diff --git a/src/plugins/git/branchmodel.h b/src/plugins/git/branchmodel.h index 083f6d59f7..5c163801fd 100644 --- a/src/plugins/git/branchmodel.h +++ b/src/plugins/git/branchmodel.h @@ -71,7 +71,6 @@ public: QStringList localBranchNames() const; 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; @@ -87,7 +86,6 @@ public: Utils::optional<QString> remoteName(const QModelIndex &idx) const; private: - void parseOutputLine(const QString &line); void setCurrentBranch(); BranchNode *indexToNode(const QModelIndex &index) const; QModelIndex nodeToIndex(BranchNode *node, int column) const; diff --git a/src/plugins/git/branchview.cpp b/src/plugins/git/branchview.cpp index 8a07af74f0..21f9c63e14 100644 --- a/src/plugins/git/branchview.cpp +++ b/src/plugins/git/branchview.cpp @@ -230,8 +230,11 @@ void BranchView::slotCustomContextMenu(const QPoint &point) contextMenu.addAction(tr("&Log"), this, [this] { log(selectedIndex()); }); contextMenu.addSeparator(); if (!currentSelected) { - if (currentLocal) - contextMenu.addAction(tr("Re&set"), this, &BranchView::reset); + auto resetMenu = new QMenu(tr("Re&set"), &contextMenu); + resetMenu->addAction(tr("&Hard"), this, [this] { reset("hard"); }); + resetMenu->addAction(tr("&Mixed"), this, [this] { reset("mixed"); }); + resetMenu->addAction(tr("&Soft"), this, [this] { reset("soft"); }); + contextMenu.addMenu(resetMenu); QString mergeTitle; if (isFastForwardMerge()) { contextMenu.addAction(tr("&Merge (Fast-Forward)"), this, [this] { merge(true); }); @@ -313,7 +316,7 @@ bool BranchView::add() } } - BranchAddDialog branchAddDialog(localNames, true, this); + BranchAddDialog branchAddDialog(localNames, BranchAddDialog::Type::AddBranch, this); branchAddDialog.setBranchName(suggestedName); branchAddDialog.setTrackedBranchName(isTracked ? trackedBranch : QString(), !isLocal); branchAddDialog.setCheckoutVisible(true); @@ -444,11 +447,10 @@ bool BranchView::rename() if (!isTag) localNames = m_model->localBranchNames(); - BranchAddDialog branchAddDialog(localNames, false, this); - if (isTag) - branchAddDialog.setWindowTitle(tr("Rename Tag")); + const BranchAddDialog::Type type = isTag ? BranchAddDialog::Type::RenameTag + : BranchAddDialog::Type::RenameBranch; + BranchAddDialog branchAddDialog(localNames, type, this); branchAddDialog.setBranchName(oldName); - branchAddDialog.setTrackedBranchName(QString(), false); branchAddDialog.exec(); @@ -467,17 +469,17 @@ bool BranchView::rename() return false; } -bool BranchView::reset() +bool BranchView::reset(const QByteArray &resetType) { const QString currentName = m_model->fullName(m_model->currentBranch()); const QString branchName = m_model->fullName(selectedIndex()); if (currentName.isEmpty() || branchName.isEmpty()) return false; - if (QMessageBox::question(this, tr("Git Reset"), tr("Hard reset branch \"%1\" to \"%2\"?") + if (QMessageBox::question(this, tr("Git Reset"), tr("Reset branch \"%1\" to \"%2\"?") .arg(currentName).arg(branchName), QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { - GitPlugin::client()->reset(m_repository, "--hard", branchName); + GitPlugin::client()->reset(m_repository, QLatin1String("--" + resetType), branchName); return true; } return false; diff --git a/src/plugins/git/branchview.h b/src/plugins/git/branchview.h index 7e400b704a..71b2aeef39 100644 --- a/src/plugins/git/branchview.h +++ b/src/plugins/git/branchview.h @@ -76,7 +76,7 @@ private: bool checkout(); bool remove(); bool rename(); - bool reset(); + bool reset(const QByteArray &resetType); bool isFastForwardMerge(); bool merge(bool allowFastForward); void rebase(); diff --git a/src/plugins/git/changeselectiondialog.h b/src/plugins/git/changeselectiondialog.h index b87ce10eed..1de142ac7d 100644 --- a/src/plugins/git/changeselectiondialog.h +++ b/src/plugins/git/changeselectiondialog.h @@ -79,7 +79,7 @@ private: Ui::ChangeSelectionDialog *m_ui; QProcess *m_process = nullptr; - Utils::FileName m_gitExecutable; + Utils::FilePath m_gitExecutable; QProcessEnvironment m_gitEnvironment; ChangeCommand m_command = NoCommand; QStringListModel *m_changeModel = nullptr; diff --git a/src/plugins/git/gerrit/gerritdialog.cpp b/src/plugins/git/gerrit/gerritdialog.cpp index f26df525fa..0f7907f99f 100644 --- a/src/plugins/git/gerrit/gerritdialog.cpp +++ b/src/plugins/git/gerrit/gerritdialog.cpp @@ -213,7 +213,7 @@ void GerritDialog::refresh() const QString &query = m_ui->queryLineEdit->text().trimmed(); updateCompletions(query); m_model->refresh(m_server, query); - m_ui->treeView->sortByColumn(-1); + m_ui->treeView->sortByColumn(-1, Qt::DescendingOrder); } void GerritDialog::scheduleUpdateRemotes() diff --git a/src/plugins/git/gerrit/gerritmodel.cpp b/src/plugins/git/gerrit/gerritmodel.cpp index 6c53345ef9..ea3e311b52 100644 --- a/src/plugins/git/gerrit/gerritmodel.cpp +++ b/src/plugins/git/gerrit/gerritmodel.cpp @@ -284,7 +284,7 @@ QueryContext::QueryContext(const QString &query, connect(&m_process, &QProcess::readyReadStandardOutput, this, [this] { m_output.append(m_process.readAllStandardOutput()); }); - connect(&m_process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), + connect(&m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &QueryContext::processFinished); connect(&m_process, &QProcess::errorOccurred, this, &QueryContext::processError); connect(&m_watcher, &QFutureWatcherBase::canceled, this, &QueryContext::terminate); @@ -315,7 +315,7 @@ void QueryContext::start() m_progress.reportStarted(); // Order: synchronous call to error handling if something goes wrong. VcsOutputWindow::appendCommand( - m_process.workingDirectory(), Utils::FileName::fromString(m_binary), m_arguments); + m_process.workingDirectory(), Utils::FilePath::fromString(m_binary), m_arguments); m_timer.start(); m_process.start(m_binary, m_arguments); m_process.closeWriteChannel(); @@ -376,7 +376,7 @@ void QueryContext::timeout() arg(timeOutMS / 1000), QMessageBox::NoButton, parent); QPushButton *terminateButton = box.addButton(tr("Terminate"), QMessageBox::YesRole); box.addButton(tr("Keep Running"), QMessageBox::NoRole); - connect(&m_process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), + connect(&m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), &box, &QDialog::reject); box.exec(); if (m_process.state() != QProcess::Running) @@ -842,7 +842,7 @@ QList<QStandardItem *> GerritModel::changeToRow(const GerritChangePtr &c) const { QList<QStandardItem *> row; const QVariant filterV = QVariant(c->filterString()); - const QVariant changeV = qVariantFromValue(c); + const QVariant changeV = QVariant::fromValue(c); for (int i = 0; i < GerritModel::ColumnCount; ++i) { auto item = new QStandardItem; item->setData(changeV, GerritModel::GerritChangeRole); diff --git a/src/plugins/git/gerrit/gerritparameters.cpp b/src/plugins/git/gerrit/gerritparameters.cpp index a505bda6e4..7cbe62dbab 100644 --- a/src/plugins/git/gerrit/gerritparameters.cpp +++ b/src/plugins/git/gerrit/gerritparameters.cpp @@ -57,11 +57,10 @@ static inline QString detectApp(const char *defaultExe) if (!app.isEmpty() || !HostOsInfo::isWindowsHost()) return app; // Windows: Use app.exe from git if it cannot be found. - const FileName gitBinDir = GerritPlugin::gitBinDirectory(); + const FilePath gitBinDir = GerritPlugin::gitBinDirectory(); if (gitBinDir.isEmpty()) return QString(); - FileName path = gitBinDir; - path.appendPath(defaultApp); + FilePath path = gitBinDir.pathAppended(defaultApp); if (path.exists()) return path.toString(); @@ -74,7 +73,7 @@ static inline QString detectApp(const char *defaultExe) const QStringList entries = dir.entryList({"mingw*"}); if (entries.isEmpty()) return QString(); - path.appendPath(entries.first()).appendPath("bin").appendPath(defaultApp); + path = path.pathAppended(entries.first()).pathAppended("bin").pathAppended(defaultApp); if (path.exists()) return path.toString(); return QString(); diff --git a/src/plugins/git/gerrit/gerritplugin.cpp b/src/plugins/git/gerrit/gerritplugin.cpp index 3cc82f5c45..7dfdc5de61 100644 --- a/src/plugins/git/gerrit/gerritplugin.cpp +++ b/src/plugins/git/gerrit/gerritplugin.cpp @@ -91,7 +91,7 @@ class FetchContext : public QObject Q_OBJECT public: FetchContext(const QSharedPointer<GerritChange> &change, - const QString &repository, const Utils::FileName &git, + const QString &repository, const Utils::FilePath &git, const GerritServer &server, FetchMode fm, QObject *parent = nullptr); ~FetchContext() override; @@ -119,7 +119,7 @@ private: const QSharedPointer<GerritChange> m_change; const QString m_repository; const FetchMode m_fetchMode; - const Utils::FileName m_git; + const Utils::FilePath m_git; const GerritServer m_server; State m_state; QProcess m_process; @@ -128,7 +128,7 @@ private: }; FetchContext::FetchContext(const QSharedPointer<GerritChange> &change, - const QString &repository, const Utils::FileName &git, + const QString &repository, const Utils::FilePath &git, const GerritServer &server, FetchMode fm, QObject *parent) : QObject(parent) @@ -140,7 +140,7 @@ FetchContext::FetchContext(const QSharedPointer<GerritChange> &change, , m_state(FetchState) { connect(&m_process, &QProcess::errorOccurred, this, &FetchContext::processError); - connect(&m_process, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished), + connect(&m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &FetchContext::processFinished); connect(&m_process, &QProcess::readyReadStandardError, this, &FetchContext::processReadyReadStandardError); @@ -375,7 +375,7 @@ void GerritPlugin::push() push(currentRepository()); } -Utils::FileName GerritPlugin::gitBinDirectory() +Utils::FilePath GerritPlugin::gitBinDirectory() { return GitPlugin::client()->gitBinDirectory(); } @@ -389,7 +389,7 @@ QString GerritPlugin::branch(const QString &repository) void GerritPlugin::fetch(const QSharedPointer<GerritChange> &change, int mode) { // Locate git. - const Utils::FileName git = GitPlugin::client()->vcsBinary(); + const Utils::FilePath git = GitPlugin::client()->vcsBinary(); if (git.isEmpty()) { VcsBase::VcsOutputWindow::appendError(tr("Git is not available.")); return; @@ -493,7 +493,7 @@ QString GerritPlugin::findLocalRepository(QString project, const QString &branch branchRegexp.reset(); // Oops. } for (const QString &repository : gitRepositories) { - const QString fileName = Utils::FileName::fromString(repository).fileName(); + const QString fileName = Utils::FilePath::fromString(repository).fileName(); if ((!branchRegexp.isNull() && branchRegexp->exactMatch(fileName)) || fileName == project) { // Perform a check on the branch. diff --git a/src/plugins/git/gerrit/gerritplugin.h b/src/plugins/git/gerrit/gerritplugin.h index 5151235496..3c6ebb5335 100644 --- a/src/plugins/git/gerrit/gerritplugin.h +++ b/src/plugins/git/gerrit/gerritplugin.h @@ -57,7 +57,7 @@ public: bool initialize(Core::ActionContainer *ac); - static Utils::FileName gitBinDirectory(); + static Utils::FilePath gitBinDirectory(); static QString branch(const QString &repository); void addToLocator(Core::CommandLocator *locator); void push(const QString &topLevel); diff --git a/src/plugins/git/gerrit/gerritpushdialog.cpp b/src/plugins/git/gerrit/gerritpushdialog.cpp index 70f0ffa3b6..a59f615b57 100644 --- a/src/plugins/git/gerrit/gerritpushdialog.cpp +++ b/src/plugins/git/gerrit/gerritpushdialog.cpp @@ -146,10 +146,10 @@ GerritPushDialog::GerritPushDialog(const QString &workingDir, const QString &rev } m_ui->localBranchComboBox->init(workingDir); - connect(m_ui->localBranchComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), + connect(m_ui->localBranchComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &GerritPushDialog::updateCommits); - connect(m_ui->targetBranchComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), + connect(m_ui->targetBranchComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &GerritPushDialog::setChangeRange); connect(m_ui->targetBranchComboBox, &QComboBox::currentTextChanged, diff --git a/src/plugins/git/gerrit/gerritserver.cpp b/src/plugins/git/gerrit/gerritserver.cpp index 9e85606c76..c07f22adcc 100644 --- a/src/plugins/git/gerrit/gerritserver.cpp +++ b/src/plugins/git/gerrit/gerritserver.cpp @@ -243,7 +243,7 @@ int GerritServer::testConnection() static GitClient *const client = GitPlugin::client(); const QStringList arguments = curlArguments() << (url(RestUrl) + accountUrlC); const SynchronousProcessResponse resp = client->vcsFullySynchronousExec( - QString(), FileName::fromString(curlBinary), arguments, + QString(), FilePath::fromString(curlBinary), arguments, Core::ShellCommand::NoOutput); if (resp.result == SynchronousProcessResponse::Finished) { QString output = resp.stdOut(); @@ -345,7 +345,7 @@ void GerritServer::resolveVersion(const GerritParameters &p, bool forceReload) arguments << p.portFlag << QString::number(port); arguments << hostArgument() << "gerrit" << "version"; const SynchronousProcessResponse resp = client->vcsFullySynchronousExec( - QString(), FileName::fromString(p.ssh), arguments, + QString(), FilePath::fromString(p.ssh), arguments, Core::ShellCommand::NoOutput); QString stdOut = resp.stdOut().trimmed(); stdOut.remove("gerrit version "); @@ -353,7 +353,7 @@ void GerritServer::resolveVersion(const GerritParameters &p, bool forceReload) } else { const QStringList arguments = curlArguments() << (url(RestUrl) + versionUrlC); const SynchronousProcessResponse resp = client->vcsFullySynchronousExec( - QString(), FileName::fromString(curlBinary), arguments, + QString(), FilePath::fromString(curlBinary), arguments, Core::ShellCommand::NoOutput); // REST endpoint for version is only available from 2.8 and up. Do not consider invalid // if it fails. diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 550a8489e4..f95cda6e00 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -780,16 +780,15 @@ QString GitClient::findRepositoryForDirectory(const QString &directory) const return QString(); // QFileInfo is outside loop, because it is faster this way QFileInfo fileInfo; - FileName parent; - for (FileName dir = FileName::fromString(directory); !dir.isEmpty(); dir = dir.parentDir()) { - FileName gitName = FileName(dir).appendPath(GIT_DIRECTORY); + FilePath parent; + for (FilePath dir = FilePath::fromString(directory); !dir.isEmpty(); dir = dir.parentDir()) { + const FilePath gitName = dir.pathAppended(GIT_DIRECTORY); if (!gitName.exists()) continue; // parent might exist fileInfo.setFile(gitName.toString()); if (fileInfo.isFile()) return dir.toString(); - gitName.appendPath("config"); - if (gitName.exists()) + if (gitName.pathAppended("config").exists()) return dir.toString(); } return QString(); @@ -1186,7 +1185,7 @@ QStringList GitClient::setupCheckoutArguments(const QString &workingDirectory, } } - BranchAddDialog branchAddDialog(localBranches, true, ICore::dialogParent()); + BranchAddDialog branchAddDialog(localBranches, BranchAddDialog::Type::AddBranch, ICore::dialogParent()); branchAddDialog.setTrackedBranchName(remoteBranch, true); if (branchAddDialog.exec() != QDialog::Accepted) @@ -2341,7 +2340,7 @@ void GitClient::launchGitK(const QString &workingDirectory, const QString &fileN } Environment sysEnv = Environment::systemEnvironment(); - const FileName exec = sysEnv.searchInPath("gitk"); + const FilePath exec = sysEnv.searchInPath("gitk"); if (!exec.isEmpty() && tryLauchingGitK(env, workingDirectory, fileName, exec.parentDir().toString())) { @@ -2378,7 +2377,7 @@ bool GitClient::tryLauchingGitK(const QProcessEnvironment &env, arguments.append(QtcProcess::splitArgs(gitkOpts, HostOsInfo::hostOs())); if (!fileName.isEmpty()) arguments << "--" << fileName; - VcsOutputWindow::appendCommand(workingDirectory, FileName::fromString(binary), arguments); + VcsOutputWindow::appendCommand(workingDirectory, FilePath::fromString(binary), arguments); // This should always use QProcess::startDetached (as not to kill // the child), but that does not have an environment parameter. bool success = false; @@ -2402,7 +2401,7 @@ bool GitClient::tryLauchingGitK(const QProcessEnvironment &env, bool GitClient::launchGitGui(const QString &workingDirectory) { bool success = true; - FileName gitBinary = vcsBinary(); + FilePath gitBinary = vcsBinary(); if (gitBinary.isEmpty()) { success = false; } else { @@ -2416,11 +2415,11 @@ bool GitClient::launchGitGui(const QString &workingDirectory) { return success; } -FileName GitClient::gitBinDirectory() +FilePath GitClient::gitBinDirectory() { const QString git = vcsBinary().toString(); if (git.isEmpty()) - return FileName(); + return FilePath(); // Is 'git\cmd' in the path (folder containing .bats)? QString path = QFileInfo(git).absolutePath(); @@ -2440,15 +2439,15 @@ FileName GitClient::gitBinDirectory() path = usrBinPath; } } - return FileName::fromString(path); + return FilePath::fromString(path); } -FileName GitClient::vcsBinary() const +FilePath GitClient::vcsBinary() const { bool ok; - Utils::FileName binary = static_cast<GitSettings &>(settings()).gitExecutable(&ok); + Utils::FilePath binary = static_cast<GitSettings &>(settings()).gitExecutable(&ok); if (!ok) - return Utils::FileName(); + return Utils::FilePath(); return binary; } @@ -2613,7 +2612,7 @@ bool GitClient::getCommitData(const QString &workingDirectory, if (!QFile::exists(templateFilename)) templateFilename = gitDirectory.absoluteFilePath("SQUASH_MSG"); if (!QFile::exists(templateFilename)) { - FileName templateName = FileName::fromUserInput( + FilePath templateName = FilePath::fromUserInput( readConfigValue(workingDirectory, "commit.template")); templateFilename = templateName.toString(); } @@ -3024,8 +3023,29 @@ void GitClient::subversionDeltaCommit(const QString &workingDirectory) void GitClient::push(const QString &workingDirectory, const QStringList &pushArgs) { - vcsExec(workingDirectory, QStringList({"push"}) + pushArgs, nullptr, true, - VcsCommand::ShowSuccessMessage); + VcsCommand *command = vcsExec( + workingDirectory, QStringList({"push"}) + pushArgs, nullptr, true, + VcsCommand::ShowSuccessMessage); + connect(command, &VcsCommand::stdErrText, this, [command](const QString &text) { + if (text.contains("non-fast-forward")) + command->setCookie(true); + }); + connect(command, &VcsCommand::finished, + this, [this, command, workingDirectory, pushArgs](bool success) { + if (!success && command->cookie().toBool()) { + const QColor warnColor = Utils::creatorTheme()->color(Theme::TextColorError); + if (QMessageBox::question( + Core::ICore::dialogParent(), tr("Force Push"), + tr("Push failed. Would you like to force-push <span style=\"color:#%1\">" + "(rewrites remote history)</span>?") + .arg(QString::number(warnColor.rgba(), 16)), + QMessageBox::Yes | QMessageBox::No, + QMessageBox::No) == QMessageBox::Yes) { + vcsExec(workingDirectory, QStringList({"push", "--force-with-lease"}) + pushArgs, + nullptr, true, VcsCommand::ShowSuccessMessage); + } + } + }); } bool GitClient::synchronousMerge(const QString &workingDirectory, const QString &branch, @@ -3239,7 +3259,7 @@ QString GitClient::readOneLine(const QString &workingDirectory, const QStringLis // determine version as '(major << 16) + (minor << 8) + patch' or 0. unsigned GitClient::gitVersion(QString *errorMessage) const { - const FileName newGitBinary = vcsBinary(); + const FilePath newGitBinary = vcsBinary(); if (m_gitVersionForBinary != newGitBinary && !newGitBinary.isEmpty()) { // Do not execute repeatedly if that fails (due to git // not being installed) until settings are changed. diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 103e269824..abde02f40d 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -121,7 +121,7 @@ public: explicit GitClient(); - Utils::FileName vcsBinary() const override; + Utils::FilePath vcsBinary() const override; unsigned gitVersion(QString *errorMessage = nullptr) const; VcsBase::VcsCommand *vcsExecAbortable(const QString &workingDirectory, @@ -306,7 +306,7 @@ public: void launchGitK(const QString &workingDirectory, const QString &fileName); void launchGitK(const QString &workingDirectory) { launchGitK(workingDirectory, QString()); } bool launchGitGui(const QString &workingDirectory); - Utils::FileName gitBinDirectory(); + Utils::FilePath gitBinDirectory(); void launchRepositoryBrowser(const QString &workingDirectory); @@ -369,7 +369,7 @@ private: QString msgBoxText, const QString &buttonName, const QString &gitCommand, ContinueCommandMode continueMode); - mutable Utils::FileName m_gitVersionForBinary; + mutable Utils::FilePath m_gitVersionForBinary; mutable unsigned m_cachedGitVersion; QString m_gitQtcEditor; diff --git a/src/plugins/git/gitconstants.h b/src/plugins/git/gitconstants.h index fb97b16b1d..9cb9ddada1 100644 --- a/src/plugins/git/gitconstants.h +++ b/src/plugins/git/gitconstants.h @@ -51,6 +51,7 @@ const char SUBMIT_MIMETYPE[] = "text/vnd.qtcreator.git.submit"; const char C_GITEDITORID[] = "Git Editor"; const int OBSOLETE_COMMIT_AGE_IN_DAYS = 90; +const int MAX_OBSOLETE_COMMITS_TO_DISPLAY = 5; const char EXPAND_BRANCHES[] = "Branches: <Expand>"; diff --git a/src/plugins/git/giteditor.cpp b/src/plugins/git/giteditor.cpp index 38074520ad..fbe90448d7 100644 --- a/src/plugins/git/giteditor.cpp +++ b/src/plugins/git/giteditor.cpp @@ -26,6 +26,7 @@ #include "giteditor.h" #include "annotationhighlighter.h" +#include "branchadddialog.h" #include "gitplugin.h" #include "gitclient.h" #include "gitsettings.h" @@ -290,34 +291,46 @@ bool GitEditorWidget::isValidRevision(const QString &revision) const void GitEditorWidget::addChangeActions(QMenu *menu, const QString &change) { m_currentChange = change; - if (contentType() != OtherContent) { - connect(menu->addAction(tr("Cherr&y-Pick Change %1").arg(change)), &QAction::triggered, - this, [this]() { - GitPlugin::client()->synchronousCherryPick(sourceWorkingDirectory(), m_currentChange); - }); - connect(menu->addAction(tr("Re&vert Change %1").arg(change)), &QAction::triggered, - this, [this]() { - GitPlugin::client()->synchronousRevert(sourceWorkingDirectory(), m_currentChange); - }); - connect(menu->addAction(tr("C&heckout Change %1").arg(change)), &QAction::triggered, - this, [this]() { - GitPlugin::client()->checkout(sourceWorkingDirectory(), m_currentChange); - }); - connect(menu->addAction(tr("&Log for Change %1").arg(change)), &QAction::triggered, - this, [this]() { - GitPlugin::client()->log( - sourceWorkingDirectory(), QString(), false, {m_currentChange}); - }); - - QMenu *resetMenu = new QMenu(tr("&Reset to Change %1").arg(change), menu); - connect(resetMenu->addAction(tr("&Hard")), &QAction::triggered, - this, [this]() { resetChange("hard"); }); - connect(resetMenu->addAction(tr("&Mixed")), &QAction::triggered, - this, [this]() { resetChange("mixed"); }); - connect(resetMenu->addAction(tr("&Soft")), &QAction::triggered, - this, [this]() { resetChange("soft"); }); - menu->addMenu(resetMenu); - } + if (contentType() == OtherContent) + return; + + menu->addAction(tr("Cherr&y-Pick Change %1").arg(change), this, [this] { + GitPlugin::client()->synchronousCherryPick(sourceWorkingDirectory(), m_currentChange); + }); + menu->addAction(tr("Re&vert Change %1").arg(change), this, [this] { + GitPlugin::client()->synchronousRevert(sourceWorkingDirectory(), m_currentChange); + }); + menu->addAction(tr("C&heckout Change %1").arg(change), this, [this] { + GitPlugin::client()->checkout(sourceWorkingDirectory(), m_currentChange); + }); + menu->addAction(tr("&Log for Change %1").arg(change), this, [this] { + GitPlugin::client()->log(sourceWorkingDirectory(), QString(), false, {m_currentChange}); + }); + menu->addAction(tr("Add &Tag for Change %1...").arg(change), this, [this] { + QString output; + QString errorMessage; + GitPlugin::client()->synchronousTagCmd(sourceWorkingDirectory(), QStringList(), + &output, &errorMessage); + + const QStringList tags = output.split('\n'); + BranchAddDialog dialog(tags, BranchAddDialog::Type::AddTag, Core::ICore::dialogParent()); + + if (dialog.exec() == QDialog::Rejected) + return; + + GitPlugin::client()->synchronousTagCmd(sourceWorkingDirectory(), + {dialog.branchName(), m_currentChange}, + &output, &errorMessage); + VcsOutputWindow::append(output); + if (!errorMessage.isEmpty()) + VcsOutputWindow::append(errorMessage, VcsOutputWindow::MessageStyle::Error); + }); + + auto resetMenu = new QMenu(tr("&Reset to Change %1").arg(change), menu); + resetMenu->addAction(tr("&Hard"), this, [this] { resetChange("hard"); }); + resetMenu->addAction(tr("&Mixed"), this, [this] { resetChange("mixed"); }); + resetMenu->addAction(tr("&Soft"), this, [this] { resetChange("soft"); }); + menu->addMenu(resetMenu); } QString GitEditorWidget::revisionSubject(const QTextBlock &inBlock) const @@ -355,7 +368,7 @@ QString GitEditorWidget::fileNameForLine(int line) const QString GitEditorWidget::sourceWorkingDirectory() const { - Utils::FileName path = Utils::FileName::fromString(source()); + Utils::FilePath path = Utils::FilePath::fromString(source()); if (!path.isEmpty() && !path.toFileInfo().isDir()) path = path.parentDir(); while (!path.isEmpty() && !path.exists()) diff --git a/src/plugins/git/gitgrep.cpp b/src/plugins/git/gitgrep.cpp index e02adf12cc..65d698ec0b 100644 --- a/src/plugins/git/gitgrep.cpp +++ b/src/plugins/git/gitgrep.cpp @@ -44,6 +44,7 @@ #include <utils/synchronousprocess.h> #include <utils/textfileformat.h> +#include <QCheckBox> #include <QFuture> #include <QFutureWatcher> #include <QHBoxLayout> @@ -59,6 +60,8 @@ class GitGrepParameters { public: QString ref; + bool recurseSubmodules = false; + QString id() const { return recurseSubmodules ? ref + ".Rec" : ref; } }; using namespace Core; @@ -169,10 +172,10 @@ public: arguments << "-P"; else arguments << "-F"; - if (client->gitVersion() >= 0x021300) - arguments << "--recurse-submodules"; arguments << "-e" << m_parameters.text; GitGrepParameters params = m_parameters.searchEngineParameters.value<GitGrepParameters>(); + if (params.recurseSubmodules) + arguments << "--recurse-submodules"; if (!params.ref.isEmpty()) { arguments << params.ref; m_ref = params.ref + ':'; @@ -245,6 +248,10 @@ GitGrep::GitGrep(QObject *parent) const QRegularExpression refExpression("[\\S]*"); m_treeLineEdit->setValidator(new QRegularExpressionValidator(refExpression, this)); layout->addWidget(m_treeLineEdit); + if (GitPlugin::client()->gitVersion() >= 0x021300) { + m_recurseSubmodules = new QCheckBox(tr("Recurse submodules")); + layout->addWidget(m_recurseSubmodules); + } TextEditor::FindInFiles *findInFiles = TextEditor::FindInFiles::instance(); QTC_ASSERT(findInFiles, return); connect(findInFiles, &TextEditor::FindInFiles::pathChanged, @@ -282,7 +289,9 @@ QVariant GitGrep::parameters() const { GitGrepParameters params; params.ref = m_treeLineEdit->text(); - return qVariantFromValue(params); + if (m_recurseSubmodules) + params.recurseSubmodules = m_recurseSubmodules->isChecked(); + return QVariant::fromValue(params); } void GitGrep::readSettings(QSettings *settings) @@ -325,7 +334,7 @@ IEditor *GitGrep::openEditor(const SearchResultItem &item, } const QString documentId = QLatin1String(Git::Constants::GIT_PLUGIN) - + QLatin1String(".GitShow.") + params.ref + + QLatin1String(".GitShow.") + params.id() + QLatin1String(".") + relativePath; QString title = tr("Git Show %1:%2").arg(params.ref).arg(relativePath); IEditor *editor = EditorManager::openEditorWithContents(Id(), &title, content, documentId, diff --git a/src/plugins/git/gitgrep.h b/src/plugins/git/gitgrep.h index af7a40ca30..1e4f81ceed 100644 --- a/src/plugins/git/gitgrep.h +++ b/src/plugins/git/gitgrep.h @@ -29,6 +29,8 @@ #include <QCoreApplication> +QT_FORWARD_DECLARE_CLASS(QCheckBox); + namespace Utils { class FancyLineEdit; } namespace Git { @@ -56,6 +58,7 @@ public: private: QWidget *m_widget; Utils::FancyLineEdit *m_treeLineEdit; + QCheckBox *m_recurseSubmodules = nullptr; }; } // namespace Internal diff --git a/src/plugins/git/gitsettings.cpp b/src/plugins/git/gitsettings.cpp index cc84fade0e..ee47d3075e 100644 --- a/src/plugins/git/gitsettings.cpp +++ b/src/plugins/git/gitsettings.cpp @@ -69,7 +69,7 @@ GitSettings::GitSettings() declareKey(lastResetIndexKey, 0); } -Utils::FileName GitSettings::gitExecutable(bool *ok, QString *errorMessage) const +Utils::FilePath GitSettings::gitExecutable(bool *ok, QString *errorMessage) const { // Locate binary in path if one is specified, otherwise default // to pathless binary @@ -78,7 +78,7 @@ Utils::FileName GitSettings::gitExecutable(bool *ok, QString *errorMessage) cons if (errorMessage) errorMessage->clear(); - Utils::FileName binPath = binaryPath(); + Utils::FilePath binPath = binaryPath(); if (binPath.isEmpty()) { if (ok) *ok = false; diff --git a/src/plugins/git/gitsettings.h b/src/plugins/git/gitsettings.h index 4a33bdc876..b6778dfca5 100644 --- a/src/plugins/git/gitsettings.h +++ b/src/plugins/git/gitsettings.h @@ -58,7 +58,7 @@ public: static const QLatin1String firstParentKey; static const QLatin1String lastResetIndexKey; - Utils::FileName gitExecutable(bool *ok = nullptr, QString *errorMessage = nullptr) const; + Utils::FilePath gitExecutable(bool *ok = nullptr, QString *errorMessage = nullptr) const; GitSettings &operator = (const GitSettings &s); }; diff --git a/src/plugins/git/gitversioncontrol.cpp b/src/plugins/git/gitversioncontrol.cpp index e36a22239e..379eb67c64 100644 --- a/src/plugins/git/gitversioncontrol.cpp +++ b/src/plugins/git/gitversioncontrol.cpp @@ -76,7 +76,7 @@ Core::Id GitVersionControl::id() const return Core::Id(VcsBase::Constants::VCS_ID_GIT); } -bool GitVersionControl::isVcsFileOrDirectory(const Utils::FileName &fileName) const +bool GitVersionControl::isVcsFileOrDirectory(const Utils::FilePath &fileName) const { if (fileName.fileName().compare(".git", Utils::HostOsInfo::fileNameCaseSensitivity())) return false; @@ -150,7 +150,7 @@ QString GitVersionControl::vcsTopic(const QString &directory) } Core::ShellCommand *GitVersionControl::createInitialCheckoutCommand(const QString &url, - const Utils::FileName &baseDirectory, + const Utils::FilePath &baseDirectory, const QString &localName, const QStringList &extraArgs) { diff --git a/src/plugins/git/gitversioncontrol.h b/src/plugins/git/gitversioncontrol.h index 2df3c7c856..1e1025864d 100644 --- a/src/plugins/git/gitversioncontrol.h +++ b/src/plugins/git/gitversioncontrol.h @@ -42,7 +42,7 @@ public: QString displayName() const final; Core::Id id() const final; - bool isVcsFileOrDirectory(const Utils::FileName &fileName) const final; + bool isVcsFileOrDirectory(const Utils::FilePath &fileName) const final; bool managesDirectory(const QString &directory, QString *topLevel) const final; bool managesFile(const QString &workingDirectory, const QString &fileName) const final; @@ -59,7 +59,7 @@ public: QString vcsTopic(const QString &directory) final; Core::ShellCommand *createInitialCheckoutCommand(const QString &url, - const Utils::FileName &baseDirectory, + const Utils::FilePath &baseDirectory, const QString &localName, const QStringList &extraArgs) final; diff --git a/src/plugins/git/mergetool.cpp b/src/plugins/git/mergetool.cpp index c1fd1ec2df..8558163dfc 100644 --- a/src/plugins/git/mergetool.cpp +++ b/src/plugins/git/mergetool.cpp @@ -61,7 +61,7 @@ bool MergeTool::start(const QString &workingDirectory, const QStringList &files) m_process->setWorkingDirectory(workingDirectory); m_process->setProcessEnvironment(env); m_process->setProcessChannelMode(QProcess::MergedChannels); - const Utils::FileName binary = GitPlugin::client()->vcsBinary(); + const Utils::FilePath binary = GitPlugin::client()->vcsBinary(); VcsOutputWindow::appendCommand(workingDirectory, binary, arguments); m_process->start(binary.toString(), arguments); if (m_process->waitForStarted()) { |