Commit 5551c1e9 authored by Orgad Shaneh's avatar Orgad Shaneh

Git: Introduce StashGuard

Offers the user to stash changes (if relevant), stores
the results and pops the stash when it goes out of scope
(unless disabled)

Change-Id: Ibc0d2a5d3e3c953062fb17ecba903ca814524837
Reviewed-by: default avatarTobias Hunger <tobias.hunger@digia.com>
parent c670a66f
......@@ -443,18 +443,11 @@ void BranchModel::checkoutBranch(const QModelIndex &idx)
if (branch.isEmpty())
return;
QString errorMessage;
switch (m_client->ensureStash(m_workingDirectory, QLatin1String("Branch-Checkout"), true, 0, &errorMessage)) {
case GitClient::StashUnchanged:
case GitClient::Stashed:
case GitClient::NotStashed:
break;
case GitClient::StashCanceled:
return;
case GitClient::StashFailed:
VcsBase::VcsBaseOutputWindow::instance()->appendError(errorMessage);
GitClient::StashGuard stashGuard(m_workingDirectory, QLatin1String("Branch-Checkout"));
if (stashGuard.stashingFailed(false))
return;
}
stashGuard.preventPop();
QString errorMessage;
if (m_client->synchronousCheckoutBranch(m_workingDirectory, branch, &errorMessage)) {
if (errorMessage.isEmpty()) {
QModelIndex currentIdx = currentBranch();
......
......@@ -80,6 +80,8 @@ QString ChangeSelectionDialog::workingDirectory() const
void ChangeSelectionDialog::setWorkingDirectory(const QString &s)
{
if (s.isEmpty())
return;
m_ui.workingDirectoryEdit->setText(QDir::toNativeSeparators(s));
m_ui.changeNumberEdit->setFocus(Qt::ActiveWindowFocusReason);
m_ui.changeNumberEdit->setText(QLatin1String("HEAD"));
......
......@@ -1567,16 +1567,6 @@ static inline int askWithDetailedText(QWidget *parent,
return msgBox.exec();
}
// Convenience that pops up an msg box.
GitClient::StashResult GitClient::ensureStash(const QString &workingDirectory, const QString &keyword, QString *message)
{
QString errorMessage;
const StashResult sr = ensureStash(workingDirectory, keyword, true, message, &errorMessage);
if (sr == StashFailed)
outputWindow()->appendError(errorMessage);
return sr;
}
// Ensure that changed files are stashed before a pull or similar
GitClient::StashResult GitClient::ensureStash(const QString &workingDirectory,
const QString &keyword,
......@@ -2540,6 +2530,41 @@ unsigned GitClient::synchronousGitVersion(QString *errorMessage) const
return version(major, minor, patch);
}
GitClient::StashGuard::StashGuard(const QString &workingDirectory, const QString &keyword) :
pop(true),
workingDir(workingDirectory)
{
client = GitPlugin::instance()->gitClient();
QString errorMessage;
stashResult = client->ensureStash(workingDir, keyword, true, &message, &errorMessage);
if (stashResult == GitClient::StashFailed)
VcsBase::VcsBaseOutputWindow::instance()->appendError(errorMessage);
}
GitClient::StashGuard::~StashGuard()
{
if (pop && stashResult == GitClient::Stashed)
client->stashPop(workingDir, message);
}
void GitClient::StashGuard::preventPop()
{
pop = false;
}
bool GitClient::StashGuard::stashingFailed(bool includeNotStashed) const
{
switch (stashResult) {
case GitClient::StashCanceled:
case GitClient::StashFailed:
return true;
case GitClient::NotStashed:
return includeNotStashed;
default:
return false;
}
}
} // namespace Internal
} // namespace Git
......
......@@ -82,6 +82,27 @@ class GitClient : public QObject
Q_OBJECT
public:
enum StashResult { StashUnchanged, StashCanceled, StashFailed,
Stashed, NotStashed /* User did not want it */ };
class StashGuard
{
public:
StashGuard(const QString &workingDirectory, const QString &keyword);
~StashGuard();
void preventPop();
bool stashingFailed(bool includeNotStashed) const;
StashResult result() const { return stashResult; }
private:
bool pop;
StashResult stashResult;
QString message;
QString workingDir;
GitClient *client;
};
static const char *stashNamePrefix;
explicit GitClient(GitSettings *settings);
......@@ -210,9 +231,6 @@ public:
QString readConfigValue(const QString &workingDirectory, const QString &configVar) const;
enum StashResult { StashUnchanged, StashCanceled, StashFailed,
Stashed, NotStashed /* User did not want it */ };
StashResult ensureStash(const QString &workingDirectory, const QString &keyword, QString *message = 0);
StashResult ensureStash(const QString &workingDirectory, const QString &keyword, bool askUser,
QString *message, QString *errorMessage = 0);
......
......@@ -714,54 +714,40 @@ void GitPlugin::resetRepository()
}
}
void GitPlugin::startRevertCommit()
{
startRevertOrCherryPick(true);
}
const VcsBase::VcsBasePluginState state = currentState();
QString workingDirectory = state.currentDirectoryOrTopLevel();
if (workingDirectory.isEmpty())
return;
GitClient::StashGuard stashGuard(workingDirectory, QLatin1String("Revert"));
if (stashGuard.stashingFailed(true))
return;
ChangeSelectionDialog changeSelectionDialog(workingDirectory);
void GitPlugin::startCherryPickCommit()
{
startRevertOrCherryPick(false);
if (changeSelectionDialog.exec() != QDialog::Accepted)
return;
const QString change = changeSelectionDialog.change();
if (!change.isEmpty() && !m_gitClient->revertCommit(workingDirectory, change))
stashGuard.preventPop();
}
void GitPlugin::startRevertOrCherryPick(bool isRevert)
void GitPlugin::startCherryPickCommit()
{
const VcsBase::VcsBasePluginState state = currentState();
QString stashKeyword = (isRevert ? QLatin1String("Revert") : QLatin1String("Cherry-pick"));
GitClient::StashResult stashResult =
m_gitClient->ensureStash(state.topLevel(), stashKeyword);
switch (stashResult) {
case GitClient::StashUnchanged:
case GitClient::Stashed:
break;
default:
QString workingDirectory = state.currentDirectoryOrTopLevel();
if (workingDirectory.isEmpty())
return;
}
QString workingDirectory;
if (state.hasFile())
workingDirectory = state.currentFileDirectory();
else if (state.hasTopLevel())
workingDirectory = state.topLevel();
else
GitClient::StashGuard stashGuard(state.topLevel(), QLatin1String("Cherry-pick"));
if (stashGuard.stashingFailed(true))
return;
ChangeSelectionDialog changeSelectionDialog(workingDirectory);
if (changeSelectionDialog.exec() != QDialog::Accepted)
return;
const QString change = changeSelectionDialog.change();
if (change.isEmpty())
return;
bool success = (isRevert ? m_gitClient->revertCommit(workingDirectory, change) :
m_gitClient->cherryPickCommit(workingDirectory, change));
if (success && (stashResult == GitClient::Stashed))
m_gitClient->stashPop(workingDirectory);
if (!change.isEmpty() && !m_gitClient->cherryPickCommit(workingDirectory, change))
stashGuard.preventPop();
}
void GitPlugin::stageFile()
......@@ -960,20 +946,11 @@ void GitPlugin::pull()
}
}
GitClient::StashResult stashResult = m_gitClient->ensureStash(state.topLevel(), QLatin1String("Pull"));
switch (stashResult) {
case GitClient::StashUnchanged:
case GitClient::Stashed:
if (m_gitClient->synchronousPull(state.topLevel(), rebase) && (stashResult == GitClient::Stashed))
m_gitClient->stashPop(state.topLevel());
break;
case GitClient::NotStashed:
if (!rebase)
m_gitClient->synchronousPull(state.topLevel(), false);
break;
default:
break;
}
GitClient::StashGuard stashGuard(state.topLevel(), QLatin1String("Pull"));
if (stashGuard.stashingFailed(false) || (rebase && (stashGuard.result() == GitClient::NotStashed)))
return;
if (!m_gitClient->synchronousPull(state.topLevel(), false))
stashGuard.preventPop();
}
void GitPlugin::push()
......@@ -1090,14 +1067,9 @@ void GitPlugin::promptApplyPatch()
void GitPlugin::applyPatch(const QString &workingDirectory, QString file)
{
// Ensure user has been notified about pending changes
switch (m_gitClient->ensureStash(workingDirectory, QLatin1String("Apply-Patch"))) {
case GitClient::StashUnchanged:
case GitClient::Stashed:
case GitClient::NotStashed:
break;
default:
GitClient::StashGuard stashGuard(workingDirectory, QLatin1String("Apply-Patch"));
if (stashGuard.stashingFailed(false))
return;
}
// Prompt for file
if (file.isEmpty()) {
const QString filter = tr("Patches (*.patch *.diff)");
......@@ -1219,10 +1191,7 @@ void GitPlugin::showCommit()
if (!m_changeSelectionDialog)
m_changeSelectionDialog = new ChangeSelectionDialog();
if (state.hasFile())
m_changeSelectionDialog->setWorkingDirectory(state.currentFileDirectory());
else if (state.hasTopLevel())
m_changeSelectionDialog->setWorkingDirectory(state.topLevel());
m_changeSelectionDialog->setWorkingDirectory(state.currentDirectoryOrTopLevel());
if (m_changeSelectionDialog->exec() != QDialog::Accepted)
return;
......
......@@ -118,7 +118,6 @@ private slots:
void resetRepository();
void startRevertCommit();
void startCherryPickCommit();
void startRevertOrCherryPick(bool isRevert);
void stageFile();
void unstageFile();
void gitkForCurrentFile();
......
......@@ -409,6 +409,15 @@ QString VcsBasePluginState::topLevel() const
return hasFile() ? data->m_state.currentFileTopLevel : data->m_state.currentProjectTopLevel;
}
QString VcsBasePluginState::currentDirectoryOrTopLevel() const
{
if (hasFile())
return data->m_state.currentFileDirectory;
else if (data->m_state.hasProject())
return data->m_state.currentProjectTopLevel;
return QString();
}
bool VcsBasePluginState::equals(const Internal::State &rhs) const
{
return data->m_state.equals(rhs);
......
......@@ -99,6 +99,7 @@ public:
// the file one.
QString topLevel() const;
QString currentDirectoryOrTopLevel() const;
bool equals(const VcsBasePluginState &rhs) const;
friend VCSBASE_EXPORT QDebug operator<<(QDebug in, const VcsBasePluginState &state);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment