forked from qt-creator/qt-creator
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: Tobias Hunger <tobias.hunger@digia.com>
This commit is contained in:
committed by
Orgad Shaneh
parent
829357b397
commit
b75cf96868
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user