diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index 1971020ac43..0ffcdbf2645 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -3127,23 +3127,69 @@ void GitClient::push(const QString &workingDirectory, const QStringList &pushArg VcsCommand *command = vcsExec( workingDirectory, QStringList({"push"}) + pushArgs, nullptr, true, VcsCommand::ShowSuccessMessage); - connect(command, &VcsCommand::stdErrText, this, [command](const QString &text) { + connect(command, &VcsCommand::stdErrText, this, [this, command](const QString &text) { if (text.contains("non-fast-forward")) - command->setCookie(true); + command->setCookie(NonFastForward); + else if (text.contains("has no upstream branch")) + command->setCookie(NoRemoteBranch); + + if (command->cookie().toInt() == NoRemoteBranch) { + const QStringList lines = text.split('\n', QString::SkipEmptyParts); + for (const QString &line : lines) { + /* Extract the suggested command from the git output which + * should be similar to the following: + * + * git push --set-upstream origin add_set_upstream_dialog + */ + const QString trimmedLine = line.trimmed(); + if (trimmedLine.startsWith("git push")) { + m_pushFallbackCommand = trimmedLine; + break; + } + } + } }); 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 " - "(rewrites remote history)?") - .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); + if (!success) { + switch (static_cast(command->cookie().toInt())) { + case NonFastForward: { + 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 " + "(rewrites remote history)?") + .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); + } + break; + } + case NoRemoteBranch: + if (QMessageBox::question( + Core::ICore::dialogParent(), tr("No Upstream Branch"), + tr("Push failed because the local branch \"%1\" " + "does not have an upstream branch on the remote.\n\n" + "Would you like to create the branch \"%1\" on the " + "remote and set it as upstream?") + .arg(synchronousCurrentLocalBranch(workingDirectory)), + QMessageBox::Yes | QMessageBox::No, + QMessageBox::No) == QMessageBox::Yes) { + + const QStringList fallbackCommandParts = + m_pushFallbackCommand.split(' ', QString::SkipEmptyParts); + VcsCommand *rePushCommand = vcsExec(workingDirectory, + fallbackCommandParts.mid(1), + nullptr, true, VcsCommand::ShowSuccessMessage); + connect(rePushCommand, &VcsCommand::success, + this, [workingDirectory]() { + GitPlugin::instance()->updateBranches(workingDirectory); + } + ); + } + break; } } }); diff --git a/src/plugins/git/gitclient.h b/src/plugins/git/gitclient.h index 753afd07711..c4412af1b2e 100644 --- a/src/plugins/git/gitclient.h +++ b/src/plugins/git/gitclient.h @@ -78,6 +78,11 @@ enum StashFlag { NoPrompt = 0x02 }; +enum PushFailure { + NonFastForward, + NoRemoteBranch +}; + class SubmoduleData { public: @@ -381,6 +386,7 @@ private: QString m_gitQtcEditor; QMap m_stashInfo; + QString m_pushFallbackCommand; QStringList m_updatedSubmodules; bool m_disableEditor; QFutureSynchronizer m_synchronizer; // for commit updates