Commit 56881e31 authored by Orgad Shaneh's avatar Orgad Shaneh Committed by Orgad Shaneh
Browse files

Git: Interactive rebase



Change-Id: I3d106ce5b071df4a7a3d77be43e7c24bd7c91dfa
Reviewed-by: default avatarTobias Hunger <tobias.hunger@digia.com>
parent 87058627
......@@ -340,6 +340,37 @@ private:
QString m_commit;
};
class RebaseManager : public QObject
{
Q_OBJECT
public:
RebaseManager(QObject *parent) : QObject(parent)
{
}
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()) {
GitPlugin::instance()->gitClient()->handleMergeConflicts(
workingDirectory.toString(), m_commit, QLatin1String("rebase"));
}
}
private:
QString m_commit;
};
Core::IEditor *locateEditor(const char *property, const QString &entry)
{
foreach (Core::IEditor *ed, Core::ICore::editorManager()->openedEditors())
......@@ -434,7 +465,7 @@ QString GitClient::findRepositoryForDirectory(const QString &dir)
return QString();
}
QString GitClient::findGitDirForRepository(const QString &repositoryDir)
QString GitClient::findGitDirForRepository(const QString &repositoryDir) const
{
static QHash<QString, QString> repoDirCache;
QString &res = repoDirCache[repositoryDir];
......@@ -2335,6 +2366,19 @@ bool GitClient::synchronousMerge(const QString &workingDirectory, const QString
return executeAndHandleConflicts(workingDirectory, arguments, command);
}
bool GitClient::canRebase(const QString &workingDirectory) const
{
const QString gitDir = findGitDirForRepository(workingDirectory);
if (QFileInfo(gitDir + QLatin1String("/rebase-apply")).exists()
|| QFileInfo(gitDir + QLatin1String("/rebase-merge")).exists()) {
VcsBase::VcsBaseOutputWindow::instance()->appendError(
tr("Rebase, merge or am is in progress. Please finish "
"or abort it then try again"));
return false;
}
return true;
}
bool GitClient::synchronousRebase(const QString &workingDirectory, const QString &baseBranch,
const QString &topicBranch)
{
......@@ -2366,6 +2410,21 @@ bool GitClient::cherryPickCommit(const QString &workingDirectory, const QString
return executeAndHandleConflicts(workingDirectory, arguments, command);
}
void GitClient::interactiveRebase(const QString &workingDirectory, const QString &commit)
{
QStringList arguments;
arguments << QLatin1String("rebase") << QLatin1String("-i") << commit;
outputWindow()->appendCommand(workingDirectory, settings()->stringValue(GitSettings::binaryPathKey), arguments);
VcsBase::Command *command = createCommand(workingDirectory, 0, true);
command->addJob(arguments, -1);
command->execute();
command->setCookie(workingDirectory);
RebaseManager *rebaseManager = new RebaseManager(command);
connect(command, SIGNAL(errorText(QString)), rebaseManager, SLOT(readStdErr(QString)));
connect(command, SIGNAL(finished(bool,int,QVariant)),
rebaseManager, SLOT(finished(bool,int,QVariant)));
}
QString GitClient::msgNoChangedFiles()
{
return tr("There are no modified files.");
......
......@@ -111,7 +111,7 @@ public:
unsigned gitVersion(QString *errorMessage = 0) const;
QString findRepositoryForDirectory(const QString &dir);
QString findGitDirForRepository(const QString &repositoryDir);
QString findGitDirForRepository(const QString &repositoryDir) const;
void diff(const QString &workingDirectory, const QStringList &diffArgs, const QString &fileName);
void diff(const QString &workingDirectory, const QStringList &diffArgs,
......@@ -199,11 +199,13 @@ public:
bool synchronousPull(const QString &workingDirectory, bool rebase);
bool synchronousPush(const QString &workingDirectory, const QString &remote = QString());
bool synchronousMerge(const QString &workingDirectory, const QString &branch);
bool canRebase(const QString &workingDirectory) const;
bool synchronousRebase(const QString &workingDirectory,
const QString &baseBranch,
const QString &topicBranch = QString());
bool revertCommit(const QString &workingDirectory, const QString &commit);
bool cherryPickCommit(const QString &workingDirectory, const QString &commit);
void interactiveRebase(const QString &workingDirectory, const QString &commit);
void synchronousAbortCommand(const QString &workingDir, const QString &abortCommand);
// git svn support (asynchronous).
......
......@@ -435,6 +435,10 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
tr("Reset..."), Core::Id("Git.Reset"),
globalcontext, false, SLOT(resetRepository()));
createRepositoryAction(localRepositoryMenu,
tr("Interactive Rebase..."), Core::Id("Git.Rebase"),
globalcontext, true, SLOT(startRebase()));
createRepositoryAction(localRepositoryMenu,
tr("Revert Single Commit..."), Core::Id("Git.Revert"),
globalcontext, true, SLOT(startRevertCommit()));
......@@ -719,6 +723,24 @@ void GitPlugin::resetRepository()
}
}
void GitPlugin::startRebase()
{
QString workingDirectory = currentState().currentDirectoryOrTopLevel();
if (workingDirectory.isEmpty() || !m_gitClient->canRebase(workingDirectory))
return;
GitClient::StashGuard stashGuard(workingDirectory, QLatin1String("Rebase-i"));
if (stashGuard.stashingFailed(true))
return;
stashGuard.preventPop();
LogChangeDialog dialog(false);
dialog.setWindowTitle(tr("Interactive Rebase"));
if (!dialog.runDialog(workingDirectory))
return;
const QString change = dialog.commit();
if (!change.isEmpty())
m_gitClient->interactiveRebase(workingDirectory, change);
}
void GitPlugin::startRevertCommit()
{
const VcsBase::VcsBasePluginState state = currentState();
......
......@@ -116,6 +116,7 @@ private slots:
void undoFileChanges(bool revertStaging = true);
void undoUnstagedFileChanges();
void resetRepository();
void startRebase();
void startRevertCommit();
void startCherryPickCommit();
void stageFile();
......
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