Commit b75cf968 authored by Orgad Shaneh's avatar Orgad Shaneh Committed by Orgad Shaneh
Browse files

Git: Refactor stash handling



* Replace RebaseManager with ConflictHandler
* Store StashGuard in GitClient, allow popping after
  a whole process is done (e.g. pull with resolved conflicts)

Change-Id: I85784f32f515ff896c73f35303c7de26f8006f59
Reviewed-by: default avatarTobias Hunger <tobias.hunger@digia.com>
parent 829357b3
......@@ -189,14 +189,9 @@ void BranchDialog::checkout()
if (branchCheckoutDialog.makeStashOfCurrentBranch()
|| branchCheckoutDialog.moveLocalChangesToNextBranch()) {
GitClient::StashGuard stashGuard(m_repository,
currentBranch + QLatin1String("-AutoStash"),
NoPrompt);
if (stashGuard.stashingFailed())
if (!gitClient->beginStashScope(m_repository, currentBranch + QLatin1String("-AutoStash"), NoPrompt))
return;
stashGuard.preventPop();
stashMessage = stashGuard.stashMessage();
stashMessage = gitClient->stashInfo(m_repository).stashMessage();
} else if (branchCheckoutDialog.discardLocalChanges()) {
gitClient->synchronousReset(m_repository);
}
......@@ -295,9 +290,9 @@ void BranchDialog::merge()
QTC_CHECK(idx != m_model->currentBranch()); // otherwise the button would not be enabled!
const QString branch = m_model->branchName(idx);
GitClient::StashGuard stashGuard(m_repository, QLatin1String("merge"), AllowUnstashed);
if (!GitPlugin::instance()->gitClient()->synchronousMerge(m_repository, branch))
stashGuard.preventPop();
GitClient *client = GitPlugin::instance()->gitClient();
if (client->beginStashScope(m_repository, QLatin1String("merge"), AllowUnstashed))
client->synchronousMerge(m_repository, branch);
}
void BranchDialog::rebase()
......@@ -307,9 +302,9 @@ void BranchDialog::rebase()
QTC_CHECK(idx != m_model->currentBranch()); // otherwise the button would not be enabled!
const QString baseBranch = m_model->branchName(idx);
GitClient::StashGuard stashGuard(m_repository, QLatin1String("rebase"));
if (!GitPlugin::instance()->gitClient()->synchronousRebase(m_repository, baseBranch))
stashGuard.preventPop();
GitClient *client = GitPlugin::instance()->gitClient();
if (client->beginStashScope(m_repository, QLatin1String("rebase")))
client->synchronousRebase(m_repository, baseBranch);
}
QModelIndex BranchDialog::selectedIndex()
......
......@@ -634,22 +634,28 @@ class ConflictHandler : public QObject
{
Q_OBJECT
public:
ConflictHandler(QObject *parent,
ConflictHandler(VcsBase::Command *parentCommand,
const QString &workingDirectory,
const QString &command)
: QObject(parent),
: QObject(parentCommand),
m_workingDirectory(workingDirectory),
m_command(command)
{
if (parentCommand) {
connect(parentCommand, SIGNAL(outputData(QByteArray)), this, SLOT(readStdOut(QByteArray)));
connect(parentCommand, SIGNAL(errorText(QString)), this, SLOT(readStdErr(QString)));
}
}
~ConflictHandler()
{
if (m_commit.isEmpty())
if (m_commit.isEmpty()) {
GitPlugin::instance()->gitVersionControl()->emitRepositoryChanged(m_workingDirectory);
else
GitPlugin::instance()->gitClient()->endStashScope(m_workingDirectory);
} else {
GitPlugin::instance()->gitClient()->handleMergeConflicts(
m_workingDirectory, m_commit, m_command);
}
}
void readStdOutString(const QString &data)
......@@ -676,45 +682,6 @@ private:
QString m_commit;
};
class RebaseManager : public QObject
{
Q_OBJECT
public:
RebaseManager(GitClient::StashGuard &stashGuard, QObject *parent) :
QObject(parent),
m_stashGuard(&stashGuard)
{
}
~RebaseManager()
{
delete m_stashGuard;
}
public slots:
void readStdErr(const QString &error)
{
// rebase conflict is output to stdOut
QRegExp conflictedCommit(QLatin1String("Could not apply ([^\\n]*)"));
conflictedCommit.indexIn(error);
m_commit = conflictedCommit.cap(1);
}
void finished(bool ok, int exitCode, const QVariant &workingDirectory)
{
Q_UNUSED(ok);
if (exitCode != 0 && !m_commit.isEmpty()) {
m_stashGuard->preventPop();
GitPlugin::instance()->gitClient()->handleMergeConflicts(
workingDirectory.toString(), m_commit, QLatin1String("rebase"));
}
}
private:
QString m_commit;
GitClient::StashGuard *m_stashGuard;
};
Core::IEditor *locateEditor(const char *property, const QString &entry)
{
......@@ -2142,6 +2109,23 @@ QProcessEnvironment GitClient::processEnvironment() const
return environment;
}
bool GitClient::beginStashScope(const QString &workingDirectory, const QString &keyword, StashFlag flag)
{
StashInfo &stashInfo = m_stashInfo[workingDirectory];
return stashInfo.init(workingDirectory, keyword, flag);
}
GitClient::StashInfo &GitClient::stashInfo(const QString &workingDirectory)
{
QTC_CHECK(m_stashInfo.contains(workingDirectory));
return m_stashInfo[workingDirectory];
}
void GitClient::endStashScope(const QString &workingDirectory)
{
m_stashInfo[workingDirectory].end();
}
bool GitClient::isValidRevision(const QString &revision) const
{
if (revision.length() < 1)
......@@ -2339,9 +2323,7 @@ void GitClient::continuePreviousGitCommand(const QString &workingDirectory,
VcsBase::Command *command = createCommand(workingDirectory, 0, true);
command->addJob(arguments, -1);
command->execute();
ConflictHandler *handler = new ConflictHandler(command, workingDirectory, gitCommand);
connect(command, SIGNAL(outputData(QByteArray)), handler, SLOT(readStdOut(QByteArray)));
connect(command, SIGNAL(errorText(QString)), handler, SLOT(readStdErr(QString)));
new ConflictHandler(command, workingDirectory, gitCommand);
} else {
GitPlugin::instance()->startCommit();
}
......@@ -2880,7 +2862,8 @@ QString GitClient::synchronousTrackingBranch(const QString &workingDirectory, co
return remote + QLatin1Char('/') + rBranch;
}
void GitClient::handleMergeConflicts(const QString &workingDir, const QString &commit, const QString &abortCommand)
void GitClient::handleMergeConflicts(const QString &workingDir, const QString &commit,
const QString &abortCommand)
{
QString message = commit.isEmpty() ? tr("Conflicts detected")
: tr("Conflicts detected with commit %1").arg(commit);
......@@ -3006,8 +2989,7 @@ bool GitClient::synchronousCherryPick(const QString &workingDirectory, const QSt
return executeAndHandleConflicts(workingDirectory, arguments, command);
}
void GitClient::interactiveRebase(const QString &workingDirectory, const QString &commit,
StashGuard &stashGuard, bool fixup)
void GitClient::interactiveRebase(const QString &workingDirectory, const QString &commit, bool fixup)
{
QStringList arguments;
arguments << QLatin1String("rebase") << QLatin1String("-i");
......@@ -3021,10 +3003,7 @@ void GitClient::interactiveRebase(const QString &workingDirectory, const QString
command->addJob(arguments, -1);
command->execute();
command->setCookie(workingDirectory);
RebaseManager *rebaseManager = new RebaseManager(stashGuard, command);
connect(command, SIGNAL(errorText(QString)), rebaseManager, SLOT(readStdErr(QString)));
connect(command, SIGNAL(finished(bool,int,QVariant)),
rebaseManager, SLOT(finished(bool,int,QVariant)));
new ConflictHandler(command, workingDirectory, QLatin1String("rebase"));
if (fixup)
m_disableEditor = false;
}
......@@ -3299,14 +3278,16 @@ unsigned GitClient::synchronousGitVersion(QString *errorMessage) const
return version(major, minor, patch);
}
GitClient::StashGuard::StashGuard(const QString &workingDirectory, const QString &keyword,
StashFlag flag) :
m_pop(true),
m_workingDir(workingDirectory),
m_flags(flag)
GitClient::StashInfo::StashInfo() :
m_client(GitPlugin::instance()->gitClient())
{
m_client = GitPlugin::instance()->gitClient();
}
bool GitClient::StashInfo::init(const QString &workingDirectory, const QString &keyword,
StashFlag flag)
{
m_workingDir = workingDirectory;
m_flags = flag;
QString errorMessage;
QString statusOutput;
switch (m_client->gitStatus(m_workingDir, StatusMode(NoUntracked | NoSubmodules),
......@@ -3316,6 +3297,7 @@ GitClient::StashGuard::StashGuard(const QString &workingDirectory, const QString
executeStash(keyword, &errorMessage);
else
stashPrompt(keyword, statusOutput, &errorMessage);
break;
case GitClient::StatusUnchanged:
m_stashResult = StashUnchanged;
break;
......@@ -3326,19 +3308,11 @@ GitClient::StashGuard::StashGuard(const QString &workingDirectory, const QString
if (m_stashResult == StashFailed)
VcsBase::VcsBaseOutputWindow::instance()->appendError(errorMessage);
return !stashingFailed();
}
GitClient::StashGuard::~StashGuard()
{
if (m_pop && m_stashResult == Stashed) {
QString stashName;
if (m_client->stashNameFromMessage(m_workingDir, m_message, &stashName))
m_client->stashPop(m_workingDir, stashName);
}
}
void GitClient::StashGuard::stashPrompt(const QString &keyword, const QString &statusOutput,
QString *errorMessage)
void GitClient::StashInfo::stashPrompt(const QString &keyword, const QString &statusOutput,
QString *errorMessage)
{
QMessageBox msgBox(QMessageBox::Question, tr("Uncommitted Changes Found"),
tr("What would you like to do with local changes in:")
......@@ -3378,7 +3352,7 @@ void GitClient::StashGuard::stashPrompt(const QString &keyword, const QString &s
}
}
void GitClient::StashGuard::executeStash(const QString &keyword, QString *errorMessage)
void GitClient::StashInfo::executeStash(const QString &keyword, QString *errorMessage)
{
m_message = creatorStashMessage(keyword);
if (!m_client->executeSynchronousStash(m_workingDir, m_message, errorMessage))
......@@ -3387,12 +3361,7 @@ void GitClient::StashGuard::executeStash(const QString &keyword, QString *errorM
m_stashResult = Stashed;
}
void GitClient::StashGuard::preventPop()
{
m_pop = false;
}
bool GitClient::StashGuard::stashingFailed() const
bool GitClient::StashInfo::stashingFailed() const
{
switch (m_stashResult) {
case StashCanceled:
......@@ -3404,6 +3373,16 @@ bool GitClient::StashGuard::stashingFailed() const
return false;
}
}
void GitClient::StashInfo::end()
{
if (m_stashResult == Stashed) {
QString stashName;
if (m_client->stashNameFromMessage(m_workingDir, m_message, &stashName))
m_client->stashPop(m_workingDir, stashName);
}
m_stashResult = NotStashed;
}
} // namespace Internal
} // namespace Git
......
......@@ -94,18 +94,16 @@ public:
enum CommandInProgress { NoCommand, Revert, CherryPick,
Rebase, Merge, RebaseMerge };
class StashGuard
class StashInfo
{
public:
StashInfo();
enum StashResult { StashUnchanged, StashCanceled, StashFailed,
Stashed, NotStashed /* User did not want it */ };
StashGuard(const QString &workingDirectory, const QString &keyword,
StashFlag flag = Default);
~StashGuard();
void preventPop();
bool init(const QString &workingDirectory, const QString &keyword, StashFlag flag = Default);
bool stashingFailed() const;
void end();
StashResult result() const { return m_stashResult; }
QString stashMessage() const { return m_message; }
......@@ -113,7 +111,6 @@ public:
void stashPrompt(const QString &keyword, const QString &statusOutput, QString *errorMessage);
void executeStash(const QString &keyword, QString *errorMessage);
bool m_pop;
StashResult m_stashResult;
QString m_message;
QString m_workingDir;
......@@ -241,8 +238,7 @@ public:
const QString &topicBranch = QString());
bool synchronousRevert(const QString &workingDirectory, const QString &commit);
bool synchronousCherryPick(const QString &workingDirectory, const QString &commit);
void interactiveRebase(const QString &workingDirectory, const QString &commit,
StashGuard &stashGuard, bool fixup);
void interactiveRebase(const QString &workingDirectory, const QString &commit, bool fixup);
void synchronousAbortCommand(const QString &workingDir, const QString &abortCommand);
QString synchronousTrackingBranch(const QString &workingDirectory,
const QString &branch = QString());
......@@ -302,6 +298,9 @@ public:
QProcessEnvironment processEnvironment() const;
bool beginStashScope(const QString &workingDirectory, const QString &keyword, StashFlag flag = Default);
StashInfo &stashInfo(const QString &workingDirectory);
void endStashScope(const QString &workingDirectory);
bool isValidRevision(const QString &revision) const;
void handleMergeConflicts(const QString &workingDir, const QString &commit, const QString &abortCommand);
......@@ -386,6 +385,7 @@ private:
QSignalMapper *m_repositoryChangedSignalMapper;
GitSettings *m_settings;
QString m_gitQtcEditor;
QMap<QString, StashInfo> m_stashInfo;
bool m_disableEditor;
};
......
......@@ -769,14 +769,14 @@ void GitPlugin::startRebase()
QString workingDirectory = currentState().currentDirectoryOrTopLevel();
if (workingDirectory.isEmpty() || !m_gitClient->canRebase(workingDirectory))
return;
QScopedPointer<GitClient::StashGuard> stashGuard(
new GitClient::StashGuard(workingDirectory, QLatin1String("Rebase-i")));
if (stashGuard->stashingFailed())
if (!m_gitClient->beginStashScope(workingDirectory, QLatin1String("Rebase-i")))
return;
LogChangeDialog dialog(false);
dialog.setWindowTitle(tr("Interactive Rebase"));
if (dialog.runDialog(workingDirectory, QString(), false))
m_gitClient->interactiveRebase(workingDirectory, dialog.commit(), *stashGuard.take(), false);
m_gitClient->interactiveRebase(workingDirectory, dialog.commit(), false);
else
m_gitClient->endStashScope(workingDirectory);
}
void GitPlugin::startChangeRelatedAction()
......@@ -822,12 +822,10 @@ void GitPlugin::startChangeRelatedAction()
return;
}
GitClient::StashGuard stashGuard(workingDirectory, command);
if (stashGuard.stashingFailed())
if (!m_gitClient->beginStashScope(workingDirectory, command))
return;
if (!(m_gitClient->*commandFunction)(workingDirectory, change))
stashGuard.preventPop();
(m_gitClient->*commandFunction)(workingDirectory, change);
}
void GitPlugin::stageFile()
......@@ -1035,12 +1033,9 @@ bool GitPlugin::submitEditorAboutToClose()
if (closeEditor) {
cleanCommitMessageFile();
if (commitType == FixupCommit) {
QScopedPointer<GitClient::StashGuard> stashGuard(
new GitClient::StashGuard(m_submitRepository, QLatin1String("Rebase-fixup"),
NoPrompt));
if (stashGuard->stashingFailed())
if (!m_gitClient->beginStashScope(m_submitRepository, QLatin1String("Rebase-fixup"), NoPrompt))
return false;
m_gitClient->interactiveRebase(m_submitRepository, amendSHA1, *stashGuard.take(), true);
m_gitClient->interactiveRebase(m_submitRepository, amendSHA1, true);
} else {
m_gitClient->continueCommandIfNeeded(m_submitRepository);
}
......@@ -1069,12 +1064,9 @@ void GitPlugin::pull()
}
}
GitClient::StashGuard stashGuard(topLevel, QLatin1String("Pull"),
rebase ? Default : AllowUnstashed);
if (stashGuard.stashingFailed())
if (!m_gitClient->beginStashScope(topLevel, QLatin1String("Pull"), rebase ? Default : AllowUnstashed))
return;
if (!m_gitClient->synchronousPull(topLevel, rebase))
stashGuard.preventPop();
m_gitClient->synchronousPull(topLevel, rebase);
}
void GitPlugin::push()
......@@ -1222,8 +1214,7 @@ void GitPlugin::promptApplyPatch()
void GitPlugin::applyPatch(const QString &workingDirectory, QString file)
{
// Ensure user has been notified about pending changes
GitClient::StashGuard stashGuard(workingDirectory, QLatin1String("Apply-Patch"), AllowUnstashed);
if (stashGuard.stashingFailed())
if (!m_gitClient->beginStashScope(workingDirectory, QLatin1String("Apply-Patch"), AllowUnstashed))
return;
// Prompt for file
if (file.isEmpty()) {
......@@ -1231,8 +1222,10 @@ void GitPlugin::applyPatch(const QString &workingDirectory, QString file)
file = QFileDialog::getOpenFileName(Core::ICore::mainWindow(),
tr("Choose Patch"),
QString(), filter);
if (file.isEmpty())
if (file.isEmpty()) {
m_gitClient->endStashScope(workingDirectory);
return;
}
}
// Run!
VcsBase::VcsBaseOutputWindow *outwin = VcsBase::VcsBaseOutputWindow::instance();
......@@ -1245,6 +1238,7 @@ void GitPlugin::applyPatch(const QString &workingDirectory, QString file)
} else {
outwin->appendError(errorMessage);
}
m_gitClient->endStashScope(workingDirectory);
}
void GitPlugin::stash()
......@@ -1253,11 +1247,10 @@ void GitPlugin::stash()
const VcsBase::VcsBasePluginState state = currentState();
QTC_ASSERT(state.hasTopLevel(), return);
GitClient::StashGuard stashGuard(state.topLevel(), QString(), NoPrompt);
if (stashGuard.stashingFailed())
QString topLevel = state.topLevel();
if (!m_gitClient->beginStashScope(topLevel, QString(), NoPrompt))
return;
stashGuard.preventPop();
if (stashGuard.result() == GitClient::StashGuard::Stashed && m_stashDialog)
if (m_gitClient->stashInfo(topLevel).result() == GitClient::StashInfo::Stashed && m_stashDialog)
m_stashDialog->refresh(state.topLevel(), true);
}
......
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