Git: Added Revert and cherry-pick

Change-Id: Ic8ba7434e79b12eca680a67c2845c82915dc0088
Reviewed-by: Orgad Shaneh <orgads@gmail.com>
Reviewed-by: Tobias Hunger <tobias.hunger@digia.com>
This commit is contained in:
Petar Perisin
2013-01-11 00:02:08 +01:00
committed by Tobias Hunger
parent 8f4da818c8
commit 65aef73ec4
6 changed files with 132 additions and 15 deletions

View File

@@ -2119,7 +2119,8 @@ bool GitClient::executeAndHandleConflicts(const QString &workingDirectory, const
const bool ok = resp.result == Utils::SynchronousProcessResponse::Finished; const bool ok = resp.result == Utils::SynchronousProcessResponse::Finished;
if (ok) if (ok)
GitPlugin::instance()->gitVersionControl()->emitRepositoryChanged(workingDirectory); GitPlugin::instance()->gitVersionControl()->emitRepositoryChanged(workingDirectory);
else if (resp.stdOut.contains(QLatin1String("CONFLICT"))) else if (resp.stdOut.contains(QLatin1String("CONFLICT"))
|| resp.stdErr.contains(QLatin1String("conflict")))
handleMergeConflicts(workingDirectory, abortCommand); handleMergeConflicts(workingDirectory, abortCommand);
return ok; return ok;
} }
@@ -2248,6 +2249,24 @@ bool GitClient::synchronousRebase(const QString &workingDirectory, const QString
return executeAndHandleConflicts(workingDirectory, arguments, command); return executeAndHandleConflicts(workingDirectory, arguments, command);
} }
bool GitClient::revertCommit(const QString &workingDirectory, const QString &commit)
{
QStringList arguments;
QString command = QLatin1String("revert");
arguments << command << QLatin1String("--no-edit") << commit;
return executeAndHandleConflicts(workingDirectory, arguments, command);
}
bool GitClient::cherryPickCommit(const QString &workingDirectory, const QString &commit)
{
QStringList arguments;
QString command = QLatin1String("cherry-pick");
arguments << command << commit;
return executeAndHandleConflicts(workingDirectory, arguments, command);
}
QString GitClient::msgNoChangedFiles() QString GitClient::msgNoChangedFiles()
{ {
return tr("There are no modified files."); return tr("There are no modified files.");

View File

@@ -184,6 +184,9 @@ public:
bool synchronousRebase(const QString &workingDirectory, bool synchronousRebase(const QString &workingDirectory,
const QString &baseBranch, const QString &baseBranch,
const QString &topicBranch = QString()); const QString &topicBranch = QString());
bool revertCommit(const QString &workingDirectory, const QString &commit);
bool cherryPickCommit(const QString &workingDirectory, const QString &commit);
void synchronousAbortCommand(const QString &workingDir, const QString &abortCommand);
// git svn support (asynchronous). // git svn support (asynchronous).
void synchronousSubversionFetch(const QString &workingDirectory); void synchronousSubversionFetch(const QString &workingDirectory);
@@ -303,7 +306,6 @@ private:
void connectRepositoryChanged(const QString & repository, VcsBase::Command *cmd); void connectRepositoryChanged(const QString & repository, VcsBase::Command *cmd);
bool executeAndHandleConflicts(const QString &workingDirectory, const QStringList &arguments, bool executeAndHandleConflicts(const QString &workingDirectory, const QStringList &arguments,
const QString &abortCommand = QString()); const QString &abortCommand = QString());
void synchronousAbortCommand(const QString &workingDir, const QString &abortCommand);
void handleMergeConflicts(const QString &workingDir, const QString &abortCommand); void handleMergeConflicts(const QString &workingDir, const QString &abortCommand);
bool tryLauchingGitK(const QProcessEnvironment &env, bool tryLauchingGitK(const QProcessEnvironment &env,
const QString &workingDirectory, const QString &workingDirectory,

View File

@@ -425,11 +425,21 @@ bool GitPlugin::initialize(const QStringList &arguments, QString *errorMessage)
createRepositoryAction(localRepositoryMenu, createRepositoryAction(localRepositoryMenu,
tr("Amend Last Commit..."), Core::Id("Git.AmendCommit"), tr("Amend Last Commit..."), Core::Id("Git.AmendCommit"),
globalcontext, true, SLOT(startAmendCommit())); globalcontext, true, SLOT(startAmendCommit()));
// --------------
localRepositoryMenu->addSeparator(globalcontext);
createRepositoryAction(localRepositoryMenu, createRepositoryAction(localRepositoryMenu,
tr("Reset..."), Core::Id("Git.Reset"), tr("Reset..."), Core::Id("Git.Reset"),
globalcontext, false, SLOT(resetRepository())); globalcontext, false, SLOT(resetRepository()));
createRepositoryAction(localRepositoryMenu,
tr("Revert Single Commit..."), Core::Id("Git.Revert"),
globalcontext, true, SLOT(startRevertCommit()));
createRepositoryAction(localRepositoryMenu,
tr("Cherry-Pick Commit..."), Core::Id("Git.CherryPick"),
globalcontext, true, SLOT(startCherryPickCommit()));
// -------------- // --------------
localRepositoryMenu->addSeparator(globalcontext); localRepositoryMenu->addSeparator(globalcontext);
@@ -704,6 +714,56 @@ 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:
return;
}
QString workingDirectory;
if (state.hasFile())
workingDirectory = state.currentFileDirectory();
else if (state.hasTopLevel())
workingDirectory = state.topLevel();
else
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);
}
void GitPlugin::stageFile() void GitPlugin::stageFile()
{ {
const VcsBase::VcsBasePluginState state = currentState(); const VcsBase::VcsBasePluginState state = currentState();

View File

@@ -100,6 +100,9 @@ public:
GitClient *gitClient() const; GitClient *gitClient() const;
public slots:
void startCommit();
private slots: private slots:
void diffCurrentFile(); void diffCurrentFile();
void diffCurrentProject(); void diffCurrentProject();
@@ -113,6 +116,9 @@ private slots:
void undoFileChanges(bool revertStaging = true); void undoFileChanges(bool revertStaging = true);
void undoUnstagedFileChanges(); void undoUnstagedFileChanges();
void resetRepository(); void resetRepository();
void startRevertCommit();
void startCherryPickCommit();
void startRevertOrCherryPick(bool isRevert);
void stageFile(); void stageFile();
void unstageFile(); void unstageFile();
void gitkForCurrentFile(); void gitkForCurrentFile();
@@ -124,7 +130,6 @@ private slots:
void gitClientMemberFuncRepositoryAction(); void gitClientMemberFuncRepositoryAction();
void showCommit(); void showCommit();
void startCommit();
void startAmendCommit(); void startAmendCommit();
void stash(); void stash();
void stashSnapshot(); void stashSnapshot();

View File

@@ -72,7 +72,8 @@ private:
MergeTool::MergeTool(QObject *parent) : MergeTool::MergeTool(QObject *parent) :
QObject(parent), QObject(parent),
m_process(0) m_process(0),
m_gitClient(GitPlugin::instance()->gitClient())
{ {
} }
@@ -85,9 +86,8 @@ bool MergeTool::start(const QString &workingDirectory, const QStringList &files)
{ {
QStringList arguments; QStringList arguments;
arguments << QLatin1String("mergetool") << QLatin1String("-y"); arguments << QLatin1String("mergetool") << QLatin1String("-y");
GitClient *client = GitPlugin::instance()->gitClient();
if (!files.isEmpty()) { if (!files.isEmpty()) {
if (client->gitVersion() < 0x010708) { if (m_gitClient->gitVersion() < 0x010708) {
QMessageBox::warning(0, tr("Error"), tr("Files input for mergetool requires git >= 1.7.8")); QMessageBox::warning(0, tr("Error"), tr("Files input for mergetool requires git >= 1.7.8"));
return false; return false;
} }
@@ -95,7 +95,7 @@ bool MergeTool::start(const QString &workingDirectory, const QStringList &files)
} }
m_process = new MergeToolProcess(this); m_process = new MergeToolProcess(this);
m_process->setWorkingDirectory(workingDirectory); m_process->setWorkingDirectory(workingDirectory);
const QString binary = client->gitBinaryPath(); const QString binary = m_gitClient->gitBinaryPath();
VcsBase::VcsBaseOutputWindow::instance()->appendCommand(workingDirectory, binary, arguments); VcsBase::VcsBaseOutputWindow::instance()->appendCommand(workingDirectory, binary, arguments);
m_process->start(binary, arguments); m_process->start(binary, arguments);
if (m_process->waitForStarted()) { if (m_process->waitForStarted()) {
@@ -255,21 +255,48 @@ void MergeTool::readData()
} }
} }
void MergeTool::continuePreviousGitCommand(const QString &msgBoxTitle, const QString &msgBoxText,
const QString &buttonName, const QString &gitCommand)
{
QString workingDirectory = m_process->workingDirectory();
QMessageBox msgBox;
QPushButton *commandButton = msgBox.addButton(buttonName, QMessageBox::AcceptRole);
QPushButton *abortButton = msgBox.addButton(QMessageBox::Abort);
msgBox.addButton(QMessageBox::Ignore);
msgBox.setIcon(QMessageBox::Question);
msgBox.setWindowTitle(msgBoxTitle);
msgBox.setText(msgBoxText);
msgBox.exec();
if (msgBox.clickedButton() == commandButton) { // Continue
if (gitCommand == QLatin1String("rebase"))
m_gitClient->synchronousCommandContinue(workingDirectory, gitCommand);
else
GitPlugin::instance()->startCommit();
} else if (msgBox.clickedButton() == abortButton) { // Abort
m_gitClient->synchronousAbortCommand(workingDirectory, gitCommand);
}
}
void MergeTool::done() void MergeTool::done()
{ {
VcsBase::VcsBaseOutputWindow *outputWindow = VcsBase::VcsBaseOutputWindow::instance(); VcsBase::VcsBaseOutputWindow *outputWindow = VcsBase::VcsBaseOutputWindow::instance();
int exitCode = m_process->exitCode(); int exitCode = m_process->exitCode();
if (!exitCode) { if (!exitCode) {
outputWindow->append(tr("Merge tool process finished successully")); outputWindow->append(tr("Merge tool process finished successully"));
QString workingDirectory = m_process->workingDirectory(); QString gitDir = m_gitClient->findGitDirForRepository(m_process->workingDirectory());
GitClient *client = GitPlugin::instance()->gitClient();
QString gitDir = client->findGitDirForRepository(workingDirectory);
if (QFile::exists(gitDir + QLatin1String("/rebase-apply/rebasing"))) { if (QFile::exists(gitDir + QLatin1String("/rebase-apply/rebasing"))) {
if (QMessageBox::question(0, tr("Continue Rebase"), continuePreviousGitCommand(tr("Continue Rebase"), tr("Continue rebase?"),
tr("Continue rebase?"), tr("Continue"), QLatin1String("rebase"));
QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) { } else if (QFile::exists(gitDir + QLatin1String("/REVERT_HEAD"))) {
client->synchronousCommandContinue(workingDirectory, QLatin1String("rebase")); continuePreviousGitCommand(tr("Continue Revert"),
} tr("You need to commit changes to finish revert.\nCommit now?"),
tr("Commit"), QLatin1String("revert"));
} else if (QFile::exists(gitDir + QLatin1String("/CHERRY_PICK_HEAD"))) {
continuePreviousGitCommand(tr("Continue Cherry-Pick"),
tr("You need to commit changes to finish cherry-pick.\nCommit now?"),
tr("Commit"), QLatin1String("cherry-pick"));
} }
} else { } else {
outputWindow->append(tr("Merge tool process terminated with exit code %1").arg(exitCode)); outputWindow->append(tr("Merge tool process terminated with exit code %1").arg(exitCode));

View File

@@ -41,6 +41,7 @@ namespace Git {
namespace Internal { namespace Internal {
class MergeToolProcess; class MergeToolProcess;
class GitClient;
class MergeTool : public QObject class MergeTool : public QObject
{ {
@@ -77,6 +78,8 @@ private:
QString stateName(FileState state, const QString &extraInfo); QString stateName(FileState state, const QString &extraInfo);
void chooseAction(); void chooseAction();
void addButton(QMessageBox *msgBox, const QString &text, char key); void addButton(QMessageBox *msgBox, const QString &text, char key);
void continuePreviousGitCommand(const QString &msgBoxTitle, const QString &msgBoxText,
const QString &buttonName, const QString &gitCommand);
MergeToolProcess *m_process; MergeToolProcess *m_process;
MergeType m_mergeType; MergeType m_mergeType;
@@ -85,6 +88,7 @@ private:
QString m_localInfo; QString m_localInfo;
FileState m_remoteState; FileState m_remoteState;
QString m_remoteInfo; QString m_remoteInfo;
GitClient *m_gitClient;
bool m_merging; bool m_merging;
}; };