forked from qt-creator/qt-creator
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: Tobias Hunger <tobias.hunger@digia.com>
This commit is contained in:
@@ -443,18 +443,11 @@ void BranchModel::checkoutBranch(const QModelIndex &idx)
|
||||
if (branch.isEmpty())
|
||||
return;
|
||||
|
||||
GitClient::StashGuard stashGuard(m_workingDirectory, QLatin1String("Branch-Checkout"));
|
||||
if (stashGuard.stashingFailed(false))
|
||||
return;
|
||||
stashGuard.preventPop();
|
||||
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);
|
||||
return;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
void GitPlugin::startCherryPickCommit()
|
||||
{
|
||||
startRevertOrCherryPick(false);
|
||||
}
|
||||
|
||||
void GitPlugin::startRevertOrCherryPick(bool isRevert)
|
||||
{
|
||||
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(workingDirectory, QLatin1String("Revert"));
|
||||
if (stashGuard.stashingFailed(true))
|
||||
return;
|
||||
|
||||
ChangeSelectionDialog changeSelectionDialog(workingDirectory);
|
||||
|
||||
if (changeSelectionDialog.exec() != QDialog::Accepted)
|
||||
return;
|
||||
const QString change = changeSelectionDialog.change();
|
||||
if (change.isEmpty())
|
||||
if (!change.isEmpty() && !m_gitClient->revertCommit(workingDirectory, change))
|
||||
stashGuard.preventPop();
|
||||
}
|
||||
|
||||
void GitPlugin::startCherryPickCommit()
|
||||
{
|
||||
const VcsBase::VcsBasePluginState state = currentState();
|
||||
QString workingDirectory = state.currentDirectoryOrTopLevel();
|
||||
if (workingDirectory.isEmpty())
|
||||
return;
|
||||
GitClient::StashGuard stashGuard(state.topLevel(), QLatin1String("Cherry-pick"));
|
||||
if (stashGuard.stashingFailed(true))
|
||||
return;
|
||||
ChangeSelectionDialog changeSelectionDialog(workingDirectory);
|
||||
|
||||
bool success = (isRevert ? m_gitClient->revertCommit(workingDirectory, change) :
|
||||
m_gitClient->cherryPickCommit(workingDirectory, change));
|
||||
|
||||
if (success && (stashResult == GitClient::Stashed))
|
||||
m_gitClient->stashPop(workingDirectory);
|
||||
if (changeSelectionDialog.exec() != QDialog::Accepted)
|
||||
return;
|
||||
const QString change = changeSelectionDialog.change();
|
||||
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();
|
||||
|
||||
Reference in New Issue
Block a user