Git: Offer creating remote branch if push fails due to the lack of it

If git push fails because the remote branch does not exists a dialog
will be shown which will allow the creation of the remote branch without
leaving the IDE (by executing the git push --set-upstream .. command
suggested by the git itself).

Fixes: QTCREATORBUG-21154
Change-Id: Id785fdc64e27865fba2255eafd2043367a5835ea
Reviewed-by: André Hartmann <aha_1980@gmx.de>
This commit is contained in:
Miklós Márton
2019-12-11 21:31:39 +01:00
parent 5cebf2a79a
commit 5ef320d9fc
2 changed files with 65 additions and 13 deletions

View File

@@ -3127,13 +3127,33 @@ void GitClient::push(const QString &workingDirectory, const QStringList &pushArg
VcsCommand *command = vcsExec( VcsCommand *command = vcsExec(
workingDirectory, QStringList({"push"}) + pushArgs, nullptr, true, workingDirectory, QStringList({"push"}) + pushArgs, nullptr, true,
VcsCommand::ShowSuccessMessage); 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")) 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, connect(command, &VcsCommand::finished,
this, [this, command, workingDirectory, pushArgs](bool success) { this, [this, command, workingDirectory, pushArgs](bool success) {
if (!success && command->cookie().toBool()) { if (!success) {
switch (static_cast<PushFailure>(command->cookie().toInt())) {
case NonFastForward: {
const QColor warnColor = Utils::creatorTheme()->color(Theme::TextColorError); const QColor warnColor = Utils::creatorTheme()->color(Theme::TextColorError);
if (QMessageBox::question( if (QMessageBox::question(
Core::ICore::dialogParent(), tr("Force Push"), Core::ICore::dialogParent(), tr("Force Push"),
@@ -3145,6 +3165,32 @@ void GitClient::push(const QString &workingDirectory, const QStringList &pushArg
vcsExec(workingDirectory, QStringList({"push", "--force-with-lease"}) + pushArgs, vcsExec(workingDirectory, QStringList({"push", "--force-with-lease"}) + pushArgs,
nullptr, true, VcsCommand::ShowSuccessMessage); 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;
}
} }
}); });
} }

View File

@@ -78,6 +78,11 @@ enum StashFlag {
NoPrompt = 0x02 NoPrompt = 0x02
}; };
enum PushFailure {
NonFastForward,
NoRemoteBranch
};
class SubmoduleData class SubmoduleData
{ {
public: public:
@@ -381,6 +386,7 @@ private:
QString m_gitQtcEditor; QString m_gitQtcEditor;
QMap<QString, StashInfo> m_stashInfo; QMap<QString, StashInfo> m_stashInfo;
QString m_pushFallbackCommand;
QStringList m_updatedSubmodules; QStringList m_updatedSubmodules;
bool m_disableEditor; bool m_disableEditor;
QFutureSynchronizer<void> m_synchronizer; // for commit updates QFutureSynchronizer<void> m_synchronizer; // for commit updates