forked from qt-creator/qt-creator
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:
committed by
Tobias Hunger
parent
8f4da818c8
commit
65aef73ec4
@@ -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.");
|
||||||
|
@@ -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,
|
||||||
|
@@ -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();
|
||||||
|
@@ -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();
|
||||||
|
@@ -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));
|
||||||
|
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user